(no commit message provided)
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
@ -0,0 +1,7 @@
|
|||||||
|
from flask import Blueprint
|
||||||
|
from .inbound import inbound_bp
|
||||||
|
from .bom import bom_bp
|
||||||
|
|
||||||
|
v1_bp = Blueprint('v1', __name__)
|
||||||
|
v1_bp.register_blueprint(inbound_bp, url_prefix='/inbound')
|
||||||
|
v1_bp.register_blueprint(bom_bp, url_prefix='/bom')
|
||||||
|
|||||||
37
inventory-backend/app/api/v1/bom.py
Normal file
37
inventory-backend/app/api/v1/bom.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from flask import Blueprint, request, jsonify, current_app
|
||||||
|
from app.services.bom_service import BomService
|
||||||
|
from flask_jwt_extended import jwt_required
|
||||||
|
|
||||||
|
bom_bp = Blueprint('bom', __name__)
|
||||||
|
|
||||||
|
@bom_bp.route('/<int:parent_id>', methods=['GET'])
|
||||||
|
@jwt_required()
|
||||||
|
def get_bom(parent_id):
|
||||||
|
try:
|
||||||
|
data = BomService.get_bom_with_stock(parent_id)
|
||||||
|
return jsonify({
|
||||||
|
'code': 200,
|
||||||
|
'msg': 'success',
|
||||||
|
'data': data
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error(f'获取BOM失败: {str(e)}')
|
||||||
|
return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500
|
||||||
|
|
||||||
|
@bom_bp.route('', methods=['POST'])
|
||||||
|
@jwt_required()
|
||||||
|
def save_bom():
|
||||||
|
try:
|
||||||
|
req_data = request.get_json()
|
||||||
|
parent_id = req_data.get('parent_id')
|
||||||
|
child_list = req_data.get('children', [])
|
||||||
|
if not parent_id or not isinstance(child_list, list):
|
||||||
|
return jsonify({'code': 400, 'msg': '参数错误'}), 400
|
||||||
|
BomService.create_or_update_bom(parent_id, child_list)
|
||||||
|
return jsonify({
|
||||||
|
'code': 200,
|
||||||
|
'msg': '保存成功'
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.error(f'保存BOM失败: {str(e)}')
|
||||||
|
return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500
|
||||||
17
inventory-backend/app/models/bom.py
Normal file
17
inventory-backend/app/models/bom.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from app.extensions import db
|
||||||
|
|
||||||
|
class BomTable(db.Model):
|
||||||
|
__tablename__ = 'bom_table'
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
parent_id = db.Column(db.Integer, db.ForeignKey('material_base.id'), nullable=False)
|
||||||
|
child_id = db.Column(db.Integer, db.ForeignKey('material_base.id'), nullable=False)
|
||||||
|
bom_no = db.Column(db.String(100), comment='BOM编号')
|
||||||
|
version = db.Column(db.String(50), comment='版本')
|
||||||
|
dosage = db.Column(db.Numeric(19, 4), comment='用量')
|
||||||
|
loss_rate = db.Column(db.Numeric(5, 2), comment='损耗率%')
|
||||||
|
remark = db.Column(db.Text, comment='备注')
|
||||||
|
|
||||||
|
# relationships
|
||||||
|
parent = db.relationship('MaterialBase', foreign_keys=[parent_id], backref='bom_parents')
|
||||||
|
child = db.relationship('MaterialBase', foreign_keys=[child_id], backref='bom_children')
|
||||||
63
inventory-backend/app/services/bom_service.py
Normal file
63
inventory-backend/app/services/bom_service.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
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}, ...]
|
||||||
|
"""
|
||||||
|
# 删除该父件原有的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
|
||||||
Reference in New Issue
Block a user