from app.extensions import db from app.models.bom import BomTable from app.models.base import MaterialBase from app.models.inbound.buy import StockBuy from sqlalchemy import func class BomService: @staticmethod def create_or_update_bom(parent_id, child_list): """ 保存/更新父件的BOM子件关系 child_list: [{"child_id": int, "dosage": float, "remark": str}, ...] """ # 校验父件不能与子件相同 for item in child_list: if item['child_id'] == parent_id: raise ValueError('父件与子件不能是同一物料') # 删除该父件原有的BOM记录 BomTable.query.filter_by(parent_id=parent_id).delete() # 插入新的 for item in child_list: bom = BomTable( parent_id=parent_id, child_id=item['child_id'], dosage=item.get('dosage', 0), remark=item.get('remark', '') ) db.session.add(bom) db.session.commit() return True @staticmethod def get_bom_with_stock(parent_id): """ 查询父件的BOM结构及库存信息 """ bom_items = db.session.query( BomTable, MaterialBase.name.label('child_name') ).join( MaterialBase, BomTable.child_id == MaterialBase.id ).filter( BomTable.parent_id == parent_id ).all() result = [] for bom, child_name in bom_items: # 查询该子件在 StockBuy 中的可用库存总量 stock_qty = db.session.query( func.coalesce(func.sum(StockBuy.available_quantity), 0) ).filter( StockBuy.base_id == bom.child_id ).scalar() or 0 # 计算最大可生产数量 dosage = float(bom.dosage) if bom.dosage else 0 max_producible = int(stock_qty // dosage) if dosage > 0 else 0 result.append({ 'child_id': bom.child_id, 'child_name': child_name, 'dosage': dosage, 'current_stock': float(stock_qty), 'max_producible': max_producible, 'remark': bom.remark or '' }) return result