This commit is contained in:
2026-06-09 21:28:53 +12:00
parent daa6e60a69
commit 349e4a4b5b
61 changed files with 6404 additions and 1382 deletions
+169
View File
@@ -0,0 +1,169 @@
from app.services.product_costing_service import (
ProductCostAssumptions,
ProductCostInputItem,
calculate_product_cost_item,
)
def assumptions() -> ProductCostAssumptions:
return ProductCostAssumptions(
grading_per_kg=0.05,
cracking_per_kg=0.03,
process_costs={
"Bagging + Grading": 0.04,
"Standard Bagging": 0.02,
"PHF Horse Mixes": 0.01,
"Peckish": 0.08,
"Hay & Straw": 0.09,
},
client_margins={
"Specialty": {"distributor_margin": 0.2, "wholesale_margin": 0.1},
"Peckish": {"distributor_margin": 0.25, "wholesale_margin": 0.15},
"Hay & Straw": {"distributor_margin": 0.3, "wholesale_margin": 0.2},
"Straight Grain": {"distributor_margin": 0.1, "wholesale_margin": 0.08},
"PHF Horse Mixes": {"distributor_margin": 0.18, "wholesale_margin": 0.12},
},
bag_costs={
"20kg_bag": 0.6,
"bulka_bag": 22.0,
"own_bag_credit": 0.2,
"1_5kg_bagging": 0.35,
"peckish_bag": 0.4,
},
freight_costs={
"freight_per_pallet": 80.0,
"peckish_freight_per_pallet": 96.0,
"hay_straw_freight_per_pallet": 120.0,
},
)
def item(**overrides) -> ProductCostInputItem:
values = {
"client_category": "Specialty",
"product_name": "Pigeon Mix 20kg",
"mix_product_name": "Pigeon Mix",
"unit_type": "Standard",
"own_bag": None,
"unit_kg": 20.0,
"items_per_pallet": 40,
"bagging_process": "Bagging + Grading",
"manual_distributor_margin": None,
"manual_wholesale_margin": None,
}
values.update(overrides)
return ProductCostInputItem(**values)
def test_standard_product_uses_per_kg_components_unit_bag_freight_and_default_margins():
result = calculate_product_cost_item(item(), assumptions(), 0.5)
assert result.grading_cost_per_kg == 0.05
assert result.bagging_cost_per_kg == 0.04
assert result.bag_cost_per_unit == 0.6
assert result.freight_cost_per_unit == 2.0
assert result.finished_product_delivered_cost == 14.4
assert result.distributor_price == 18.0
assert result.wholesale_price == 16.0
assert result.warnings == []
def test_bulka_uses_per_kg_delivered_formula_and_bulka_bag_and_freight_divided_by_unit_kg():
result = calculate_product_cost_item(item(unit_type="Bulka", unit_kg=1000, items_per_pallet=1), assumptions(), 0.5)
assert result.bag_cost_per_unit == 0.022
assert result.freight_cost_per_unit == 0.08
assert result.finished_product_delivered_cost == 0.692
def test_per_unit_uses_per_kg_delivered_formula_but_standard_pallet_freight():
result = calculate_product_cost_item(item(unit_type="Per Unit", unit_kg=1, items_per_pallet=10), assumptions(), 0.5)
assert result.freight_cost_per_unit == 8.0
assert result.finished_product_delivered_cost == 8.59
def test_peckish_uses_peckish_bag_freight_and_zero_grading():
result = calculate_product_cost_item(
item(client_category="Peckish", bagging_process="Peckish", items_per_pallet=24),
assumptions(),
0.5,
)
assert result.grading_cost_per_kg == 0
assert result.bagging_cost_per_kg == 0.08
assert result.bag_cost_per_unit == 0.4
assert result.freight_cost_per_unit == 4.0
def test_hay_and_straw_uses_hay_freight_and_zero_grading():
result = calculate_product_cost_item(
item(client_category="Hay & Straw", bagging_process="Hay & Straw", items_per_pallet=30),
assumptions(),
0.5,
)
assert result.grading_cost_per_kg == 0
assert result.freight_cost_per_unit == 4.0
def test_phf_horse_mixes_have_zero_grading():
result = calculate_product_cost_item(
item(client_category="PHF Horse Mixes", bagging_process="PHF Horse Mixes"),
assumptions(),
0.5,
)
assert result.grading_cost_per_kg == 0
def test_own_bag_subtracts_credit_and_no_bag_sets_bag_cost_to_zero():
own_bag = calculate_product_cost_item(item(own_bag="Yes"), assumptions(), 0.5)
no_bag = calculate_product_cost_item(item(own_bag="No Bag"), assumptions(), 0.5)
assert own_bag.bag_cost_per_unit == 0.4
assert no_bag.bag_cost_per_unit == 0
def test_one_point_five_kg_branch_multiplies_pack_formula_by_eight():
result = calculate_product_cost_item(item(unit_type="1.5 kg", unit_kg=1.5), assumptions(), 0.5)
assert result.bag_cost_per_unit == 0.35
assert result.finished_product_delivered_cost == 10.84
def test_cracked_product_adds_cracking_cost_and_manual_margins_override_defaults():
result = calculate_product_cost_item(
item(product_name="Cracked Maize 20kg", manual_distributor_margin=0.1, manual_wholesale_margin=0.05),
assumptions(),
0.5,
)
assert result.cracking_cost_per_kg == 0.03
assert result.distributor_price == 16.6667
assert result.wholesale_price == 15.8
def test_straight_grain_bulka_wholesale_rounds_up_to_two_decimals():
result = calculate_product_cost_item(
item(client_category="Straight Grain", unit_type="Bulka", unit_kg=1000, items_per_pallet=1),
assumptions(),
0.5,
)
assert result.wholesale_price == 0.76
def test_missing_lookup_and_invalid_inputs_generate_warnings_without_prices():
result = calculate_product_cost_item(
item(unit_kg=None, items_per_pallet=0, manual_distributor_margin=1.2),
assumptions(),
None,
)
assert "Missing mix/product cost lookup" in result.warnings
assert "Missing unit kg" in result.warnings
assert "Missing pallet quantity" in result.warnings
assert "Invalid distributor margin" in result.warnings
assert result.finished_product_delivered_cost is None
assert result.distributor_price is None