tweaks
This commit is contained in:
@@ -8,7 +8,7 @@ from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app.models.assumption import FreightCostRule, PackagingCostRule, ProcessCostRule
|
||||
from app.models.mix import Mix, MixIngredient
|
||||
from app.models.product import Product
|
||||
from app.models.product import Product, ProductIngredient
|
||||
from app.models.raw_material import RawMaterial, RawMaterialPriceVersion
|
||||
|
||||
|
||||
@@ -119,6 +119,78 @@ def calculate_mix_cost(db: Session, mix_id: int, overrides: dict | None = None)
|
||||
}
|
||||
|
||||
|
||||
def _calculate_formula_cost_from_product_ingredients(
|
||||
product_ingredients: list[ProductIngredient],
|
||||
overrides: dict | None = None,
|
||||
) -> dict:
|
||||
overrides = overrides or {}
|
||||
total_mix_kg = 0.0
|
||||
total_mix_cost = 0.0
|
||||
warnings: list[str] = []
|
||||
lines: list[dict] = []
|
||||
|
||||
for ingredient in product_ingredients:
|
||||
raw_material = ingredient.raw_material
|
||||
active_price = get_active_price(raw_material)
|
||||
if active_price is None:
|
||||
warnings.append(f"{raw_material.name} has no active price")
|
||||
lines.append(
|
||||
{
|
||||
"id": ingredient.id,
|
||||
"raw_material_id": raw_material.id,
|
||||
"raw_material_name": raw_material.name,
|
||||
"quantity_kg": ingredient.quantity_kg,
|
||||
"cost_per_kg": None,
|
||||
"line_cost": None,
|
||||
"notes": ingredient.notes,
|
||||
}
|
||||
)
|
||||
total_mix_kg += ingredient.quantity_kg
|
||||
continue
|
||||
|
||||
market_value = overrides.get("raw_material_market_values", {}).get(str(raw_material.id), active_price.market_value)
|
||||
waste_percentage = overrides.get("raw_material_waste_percentages", {}).get(str(raw_material.id), active_price.waste_percentage)
|
||||
price_stub = RawMaterialPriceVersion(
|
||||
raw_material_id=raw_material.id,
|
||||
market_value=market_value,
|
||||
waste_percentage=waste_percentage,
|
||||
effective_date=active_price.effective_date,
|
||||
status=active_price.status,
|
||||
)
|
||||
price_comp = calculate_raw_material_cost(raw_material, price_stub)
|
||||
line_cost = round(ingredient.quantity_kg * price_comp.cost_per_kg, 4)
|
||||
total_mix_kg += ingredient.quantity_kg
|
||||
total_mix_cost += line_cost
|
||||
lines.append(
|
||||
{
|
||||
"id": ingredient.id,
|
||||
"raw_material_id": raw_material.id,
|
||||
"raw_material_name": raw_material.name,
|
||||
"quantity_kg": ingredient.quantity_kg,
|
||||
"cost_per_kg": price_comp.cost_per_kg,
|
||||
"line_cost": line_cost,
|
||||
"notes": ingredient.notes,
|
||||
}
|
||||
)
|
||||
|
||||
if total_mix_kg == 0:
|
||||
warnings.append("Mix total kg is zero")
|
||||
mix_cost_per_kg = None
|
||||
else:
|
||||
mix_cost_per_kg = round(total_mix_cost / total_mix_kg, 4)
|
||||
|
||||
if not product_ingredients:
|
||||
warnings.append("Mix has no ingredients")
|
||||
|
||||
return {
|
||||
"ingredients": lines,
|
||||
"total_mix_kg": round(total_mix_kg, 4),
|
||||
"total_mix_cost": round(total_mix_cost, 4),
|
||||
"mix_cost_per_kg": mix_cost_per_kg,
|
||||
"warnings": warnings,
|
||||
}
|
||||
|
||||
|
||||
def _get_process_costs(db: Session, process_name: str | None, overrides: dict) -> tuple[float, float, float, list[str]]:
|
||||
if not process_name:
|
||||
return 0.0, 0.0, 0.0, ["Missing bagging process"]
|
||||
@@ -192,12 +264,22 @@ def extract_unit_quantity_kg(unit_of_measure: str) -> float:
|
||||
def calculate_product_cost(db: Session, product_id: int, overrides: dict | None = None) -> dict:
|
||||
overrides = overrides or {}
|
||||
overrides = {**overrides, "tenant_id": overrides.get("tenant_id")}
|
||||
product = db.scalar(select(Product).where(Product.id == product_id).options(selectinload(Product.mix)))
|
||||
product = db.scalar(
|
||||
select(Product)
|
||||
.where(Product.id == product_id)
|
||||
.options(
|
||||
selectinload(Product.mix),
|
||||
selectinload(Product.ingredients).selectinload(ProductIngredient.raw_material).selectinload(RawMaterial.price_versions),
|
||||
)
|
||||
)
|
||||
if product is None:
|
||||
raise ValueError(f"Product {product_id} not found")
|
||||
overrides["tenant_id"] = product.tenant_id
|
||||
|
||||
mix_result = calculate_mix_cost(db, product.mix_id, overrides=overrides)
|
||||
if product.ingredients:
|
||||
mix_result = _calculate_formula_cost_from_product_ingredients(product.ingredients, overrides=overrides)
|
||||
else:
|
||||
mix_result = calculate_mix_cost(db, product.mix_id, overrides=overrides)
|
||||
warnings = list(mix_result["warnings"])
|
||||
sale_unit_kg = extract_unit_quantity_kg(product.unit_of_measure)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user