diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py index d2284ff..b814296 100644 --- a/inventory-backend/app/services/inbound/product_service.py +++ b/inventory-backend/app/services/inbound/product_service.py @@ -137,6 +137,11 @@ class ProductInboundService: in_date_val = current_time in_qty = float(data.get('in_quantity') or 0) + raw_cost = float(data.get('raw_material_cost') or 0) + manual_cost = 0.0 # 字段已弃用,保持向后兼容 + unit_total_cost = float(data.get('unit_total_cost') or raw_cost or 0) + total_price = unit_total_cost * in_qty + p_start = data.get('production_start_time', '') p_end = data.get('production_end_time', '') time_range = f"{p_start} ~ {p_end}" if p_start or p_end else None @@ -175,8 +180,10 @@ class ProductInboundService: work_order_code=data.get('work_order_code'), production_manager=data.get('production_manager'), production_time_range=time_range, - raw_material_cost=float(data.get('raw_material_cost') or 0), - manual_cost=float(data.get('manual_cost') or 0), + raw_material_cost=raw_cost, + manual_cost=manual_cost, + unit_total_cost=unit_total_cost, + total_price=total_price, quality_status=data.get('quality_status', '合格'), product_photo=json.dumps(photo_list), quality_report_link=json.dumps(quality_list), @@ -230,7 +237,7 @@ class ProductInboundService: if 'sale_price' in data: stock.sale_price = float(data['sale_price']) if 'raw_material_cost' in data: stock.raw_material_cost = float(data['raw_material_cost']) - if 'manual_cost' in data: stock.manual_cost = float(data['manual_cost']) + if 'unit_total_cost' in data: stock.unit_total_cost = float(data['unit_total_cost']) if 'in_quantity' in data: new_qty = float(data['in_quantity']) @@ -239,6 +246,10 @@ class ProductInboundService: stock.stock_quantity = float(stock.stock_quantity) + diff stock.available_quantity = float(stock.available_quantity) + diff + if 'unit_total_cost' in data or 'in_quantity' in data: + qty = float(data.get('in_quantity', stock.in_quantity or 1)) + stock.total_price = float(stock.unit_total_cost or 0) * qty + if 'production_start_time' in data or 'production_end_time' in data: old_range = stock.production_time_range or " ~ " parts = old_range.split(' ~ ') @@ -415,4 +426,4 @@ class ProductInboundService: return [r[0] for r in records if r[0]] except Exception: traceback.print_exc() - return [] \ No newline at end of file + return [] diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py index 95099fb..ed4c86c 100644 --- a/inventory-backend/app/services/inbound/semi_service.py +++ b/inventory-backend/app/services/inbound/semi_service.py @@ -172,8 +172,8 @@ class SemiInboundService: in_qty = float(data.get('in_quantity') or 0) raw_cost = float(data.get('raw_material_cost') or 0) - manual_cost = float(data.get('manual_cost') or 0) - unit_total_cost = raw_cost + manual_cost + manual_cost = 0.0 # 字段已弃用,保持向后兼容 + unit_total_cost = float(data.get('unit_total_cost') or raw_cost or 0) total_value = unit_total_cost * in_qty next_global_id = 0 @@ -220,7 +220,8 @@ class SemiInboundService: production_end_time=p_end, production_time_range=time_range_str, raw_material_cost=raw_cost, - manual_cost=manual_cost, + manual_cost=manual_cost, # 保持 0.0 + unit_total_cost=unit_total_cost, total_price=total_value, arrival_photo=json.dumps(arrival_list), quality_report_link=json.dumps(quality_report_list), @@ -312,7 +313,6 @@ class SemiInboundService: stock.production_time_range = raw_range qty_changed = False - cost_changed = False if 'in_quantity' in data: new_qty = float(data['in_quantity']) diff = new_qty - float(stock.in_quantity) @@ -321,15 +321,15 @@ class SemiInboundService: stock.stock_quantity = float(stock.stock_quantity) + diff stock.available_quantity = float(stock.available_quantity) + diff qty_changed = True + if 'raw_material_cost' in data: stock.raw_material_cost = float(data['raw_material_cost']) - cost_changed = True - if 'manual_cost' in data: - stock.manual_cost = float(data['manual_cost']) - cost_changed = True - if cost_changed or qty_changed: - unit_total = float(stock.raw_material_cost) + float(stock.manual_cost) - stock.total_price = float(stock.in_quantity) * unit_total + if 'unit_total_cost' in data: + stock.unit_total_cost = float(data['unit_total_cost']) + + if 'unit_total_cost' in data or qty_changed: + qty = float(stock.in_quantity or 1) + stock.total_price = float(stock.unit_total_cost or 0) * qty db.session.commit() return stock @@ -503,4 +503,4 @@ class SemiInboundService: return [r[0] for r in records if r[0]] except Exception: traceback.print_exc() - return [] \ No newline at end of file + return [] diff --git a/inventory-web/src/views/stock/inbound/product.vue b/inventory-web/src/views/stock/inbound/product.vue index 81150f4..bc7afe7 100644 --- a/inventory-web/src/views/stock/inbound/product.vue +++ b/inventory-web/src/views/stock/inbound/product.vue @@ -467,7 +467,8 @@ import { searchMaterialBase, searchBom, getFilterOptions, - getManagerHistory // [新增] + getManagerHistory, // [新增] + calculateBomCost } from '@/api/inbound/product' import { uploadFile, deleteFile } from '@/api/inbound/buy' import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue' @@ -657,7 +658,7 @@ const handleSearchBom = async (query: string) => { bomOptions.value = res.data || [] } finally { bomSearchLoading.value = false } } -const handleBomSelect = (val: string) => { +const handleBomSelect = async (val: string) => { if (!val) { form.bom_code = '' form.bom_version = '' @@ -666,6 +667,17 @@ const handleBomSelect = (val: string) => { const [code, version] = val.split('###') form.bom_code = code form.bom_version = version + // 自动计算 BOM 成本并填入 raw_material_cost 和 unit_total_cost + try { + const res: any = await calculateBomCost({ bom_code: code, bom_version: version }) + if (res.code === 200 && typeof res.data === 'number') { + form.raw_material_cost = res.data + form.unit_total_cost = res.data + } + } catch (e) { + // 计算失败不影响现有输入 + console.warn('BOM 成本计算失败', e) + } } // ------------------------------------ @@ -1087,4 +1099,4 @@ onMounted(() => { .product-dropdown { width: 580px !important; } .product-dropdown .el-select-dropdown__wrap { max-height: 320px !important; } .product-dropdown .el-input__suffix { z-index: 10; } - \ No newline at end of file + diff --git a/inventory-web/src/views/stock/inbound/semi.vue b/inventory-web/src/views/stock/inbound/semi.vue index a8e3e68..7182b08 100644 --- a/inventory-web/src/views/stock/inbound/semi.vue +++ b/inventory-web/src/views/stock/inbound/semi.vue @@ -473,13 +473,13 @@ - - + + - + @@ -539,7 +539,8 @@ import { searchMaterialBase, searchBom, getFilterOptions, - getManagerHistory // [新增] + getManagerHistory, // [新增] + calculateBomCost } from '@/api/inbound/semi' import { uploadFile, deleteFile } from '@/api/inbound/buy' import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue' @@ -731,13 +732,11 @@ const form = reactive({ production_manager: '', production_time_range: [] as string[], arrival_photo: [] as string[], quality_report_link: [] as string[], detail_link: '' }) -// === 新增:监听计算总成本 === -watch([() => form.in_quantity, () => form.manual_cost], ([qty, manual_cost]) => { - if (manual_cost !== undefined && manual_cost !== null) { - form.unit_total_cost = Number((qty * manual_cost).toFixed(2)) - } else { - form.unit_total_cost = undefined - } +// === 监听计算总成本 === +watch([() => form.unit_total_cost, () => form.in_quantity], ([unit, qty]) => { + const unitNum = Number(unit || 0) + const qtyNum = Number(qty || 1) + form.total_price = Number((unitNum * qtyNum).toFixed(2)) }) // ------------------------------------ @@ -750,7 +749,7 @@ const handleSearchBom = async (query: string) => { bomOptions.value = res.data || [] } finally { bomSearchLoading.value = false } } -const handleBomSelect = (val: string) => { +const handleBomSelect = async (val: string) => { // val 格式为 bom_no###version if (!val) { form.bom_code = '' @@ -760,6 +759,17 @@ const handleBomSelect = (val: string) => { const [code, version] = val.split('###') form.bom_code = code form.bom_version = version + // 自动计算 BOM 成本并填入 raw_material_cost 和 unit_total_cost + try { + const res: any = await calculateBomCost({ bom_code: code, bom_version: version }) + if (res.code === 200 && typeof res.data === 'number') { + form.raw_material_cost = res.data + form.unit_total_cost = res.data + } + } catch (e) { + // 计算失败不影响现有输入 + console.warn('BOM 成本计算失败', e) + } } // ------------------------------------ @@ -1221,4 +1231,4 @@ onMounted(() => { .long-dropdown { width: 580px !important; } .long-dropdown .el-select-dropdown__wrap { max-height: 320px !important; } .long-dropdown .el-input__suffix { z-index: 10; } - \ No newline at end of file +