Files
data-entry-app/backend/tests/test_costing_engine.py
T
2026-04-25 20:43:37 +12:00

96 lines
3.7 KiB
Python

from datetime import date
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from app.core.config import settings
from app.db.session import Base
from app.main import app
from app.models.assumption import FreightCostRule, PackagingCostRule, ProcessCostRule
from app.models.mix import Mix, MixIngredient
from app.models.product import Product
from app.models.raw_material import RawMaterial, RawMaterialPriceVersion
from app.services.costing_engine import calculate_mix_cost, calculate_product_cost, calculate_raw_material_cost
def build_session() -> Session:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine, expire_on_commit=False)()
return session
def test_calculate_raw_material_cost():
raw_material = RawMaterial(name="Maize", unit_of_measure="tonne", kg_per_unit=1000, status="active")
price = RawMaterialPriceVersion(market_value=500, waste_percentage=0.02, effective_date=date(2026, 4, 1))
result = calculate_raw_material_cost(raw_material, price)
assert result.loss_cost == 10.0
assert result.cost_per_unit == 510.0
assert result.cost_per_kg == 0.51
def test_mix_and_product_cost_breakdown():
db = build_session()
maize = RawMaterial(name="Maize", unit_of_measure="tonne", kg_per_unit=1000, status="active")
maize.price_versions.append(RawMaterialPriceVersion(market_value=520, waste_percentage=0.02, effective_date=date(2026, 4, 1)))
barley = RawMaterial(name="Barley", unit_of_measure="tonne", kg_per_unit=1000, status="active")
barley.price_versions.append(RawMaterialPriceVersion(market_value=470, waste_percentage=0.015, effective_date=date(2026, 4, 1)))
db.add_all([maize, barley])
db.flush()
mix = Mix(client_name="Specialty Feeds", name="Pigeon Mix", status="active", version=1)
db.add(mix)
db.flush()
db.add_all(
[
MixIngredient(mix_id=mix.id, raw_material_id=maize.id, quantity_kg=180),
MixIngredient(mix_id=mix.id, raw_material_id=barley.id, quantity_kg=100),
]
)
db.add(ProcessCostRule(process_name="standard_bagging", grading_cost=0.055, bagging_cost=0.04, cracking_cost=0.0))
db.add(PackagingCostRule(sale_type="standard", unit_of_measure="20kg bag", own_bag=False, bag_cost=0.63))
db.add(FreightCostRule(sale_type="standard", unit_of_measure="20kg bag", cost_per_unit=1.45))
db.flush()
product = Product(
client_name="Specialty Feeds",
name="Specialty Pigeon Breeder 20kg",
mix_id=mix.id,
sale_type="standard",
own_bag=False,
unit_of_measure="20kg bag",
items_per_pallet=50,
bagging_process="standard_bagging",
distributor_margin=0.225,
wholesale_margin=0.18,
)
db.add(product)
db.commit()
mix_result = calculate_mix_cost(db, mix.id)
product_result = calculate_product_cost(db, product.id)
assert mix_result["total_mix_kg"] == 280
assert mix_result["mix_cost_per_kg"] == 0.5114
assert product_result["finished_product_delivered"] == 14.208
assert product_result["distributor_price"] == 18.3329
assert product_result["wholesale_price"] == 17.3268
def test_root_and_login_endpoints():
client = TestClient(app)
root_response = client.get("/")
assert root_response.status_code == 200
assert root_response.json()["endpoints"]["login"] == "/api/auth/login"
login_response = client.post(
"/api/auth/login",
json={"email": settings.operator_email, "password": settings.operator_password},
)
assert login_response.status_code == 200
assert login_response.json()["email"] == settings.operator_email