diff --git a/inventory-backend/app/services/inbound/base_service.py b/inventory-backend/app/services/inbound/base_service.py index 3e8c5d8..eda5da9 100644 --- a/inventory-backend/app/services/inbound/base_service.py +++ b/inventory-backend/app/services/inbound/base_service.py @@ -14,6 +14,7 @@ import datetime # 需要 pip install openpyxl from openpyxl import Workbook from openpyxl.styles import Font, Alignment, Border, Side, PatternFill +from collections import defaultdict class MaterialBaseService: @@ -411,15 +412,59 @@ class MaterialBaseService: query_product = query_product.filter(cond) list_product = query_product.all() + # 2.4 计算每个物料基础的最高单价/成本 + buy_max = defaultdict(float) + for stock, base in list_buy: + p = float(stock.pre_tax_unit_price or 0) + if p > buy_max[base.id]: + buy_max[base.id] = p + + semi_max = defaultdict(float) + for stock, base in list_semi: + p = float(stock.raw_material_cost or 0) + float(stock.manual_cost or 0) + if p > semi_max[base.id]: + semi_max[base.id] = p + + product_max = defaultdict(float) + for stock, base in list_product: + p = float(stock.raw_material_cost or 0) + float(stock.manual_cost or 0) + if p > product_max[base.id]: + product_max[base.id] = p + + highest_price = {} + all_base_ids = set() + for stock, base in list_buy: + all_base_ids.add(base.id) + for stock, base in list_semi: + all_base_ids.add(base.id) + for stock, base in list_product: + all_base_ids.add(base.id) + + for base_id in all_base_ids: + price = None + buy_val = buy_max.get(base_id) + if buy_val is not None and buy_val > 0: + price = buy_val + else: + semi_val = semi_max.get(base_id) + if semi_val is not None and semi_val > 0: + price = semi_val + else: + prod_val = product_max.get(base_id) + if prod_val is not None and prod_val > 0: + price = prod_val + highest_price[base_id] = price or 0.0 + # 3. 数据整合 all_rows = [] # 处理采购件 for stock, base in list_buy: - # 价格计算 - unit_price = float(stock.pre_tax_unit_price or 0) + # 价格计算:使用当前物料基础的最高单价 + unit_price = highest_price.get(base.id, 0.0) tax_rate = float(stock.tax_rate or 0) - price_incl = float(stock.post_tax_unit_price or (unit_price * (1 + tax_rate / 100.0))) + # 根据新单价重新计算含税单价 + price_incl = unit_price * (1 + tax_rate / 100.0) qty = float(stock.stock_quantity or 0) # 计算不含税总价 = 数量 * 不含税单价 @@ -447,13 +492,14 @@ class MaterialBaseService: # 处理半成品 for stock, base in list_semi: - cost = float(stock.raw_material_cost or 0) + float(stock.manual_cost or 0) + # 使用当前物料基础的最高单价 + unit_price = highest_price.get(base.id, 0.0) qty = float(stock.stock_quantity or 0) - # 半成品不含税总价 = 数量 * 成本 - total_val_excl = qty * cost + # 半成品不含税总价 = 数量 * 单价 + total_val_excl = qty * unit_price # 含税总价同上 (税率0) - total_val_incl = qty * cost + total_val_incl = qty * unit_price ident = stock.batch_number or stock.serial_number or stock.barcode or stock.sku @@ -466,20 +512,21 @@ class MaterialBaseService: "date": stock.production_date, "qty": qty, "avail": float(stock.available_quantity or 0), - "price_excl": cost, + "price_excl": unit_price, "total_val_excl": total_val_excl, "tax": 0.0, - "price_incl": cost, + "price_incl": unit_price, "total_val": total_val_incl }) # 处理成品 for stock, base in list_product: - cost = float(stock.raw_material_cost or 0) + float(stock.manual_cost or 0) + # 使用当前物料基础的最高单价 + unit_price = highest_price.get(base.id, 0.0) qty = float(stock.stock_quantity or 0) - total_val_excl = qty * cost - total_val_incl = qty * cost + total_val_excl = qty * unit_price + total_val_incl = qty * unit_price ident = stock.serial_number or stock.barcode or stock.sku @@ -492,10 +539,10 @@ class MaterialBaseService: "date": stock.production_date, "qty": qty, "avail": float(stock.available_quantity or 0), - "price_excl": cost, + "price_excl": unit_price, "total_val_excl": total_val_excl, "tax": 0.0, - "price_incl": cost, + "price_incl": unit_price, "total_val": total_val_incl })