feat(bom): 自制件子件选版本落库/强校验 + 独立启停 + 状态筛选

- save_bom 落库 child_bom_no/child_bom_version;自制件必选且须属于启用未归档配方集,外购件置空;跨版本查重纳入引用版本
- get_bom_detail 改为读存储列,空则回退最新启用配方;候选/校验/回退读取均排除 is_archived
- 新增 GET /bom/self-bom-versions(子件候选版本);新增 POST /bom/status 独立启停(update_enabled 清缓存)
- 草稿链路 save_draft/get_draft_detail/publish 持久化引用版本
- get_bom_list/get_bom_summary 支持 status(enabled/disabled) 过滤
This commit is contained in:
yueli
2026-09-08 10:14:44 +08:00
parent 6250fa94cb
commit 91fb6c1a03
5 changed files with 206 additions and 26 deletions

View File

@ -66,13 +66,14 @@ def get_bom_list():
try:
keyword = request.args.get('keyword', '').strip()
active_only = request.args.get('active_only', 'false').lower() == 'true'
status = request.args.get('status', '').strip() or None
category = request.args.get('category', '').strip() or None
page = request.args.get('page', 1, type=int)
limit = request.args.get('pageSize', 15, type=int)
data = BomService.get_bom_list(
keyword=keyword, active_only=active_only,
category=category, page=page, limit=limit
category=category, page=page, limit=limit, status=status
)
# 字段级脱敏data 现在是 {items, total, pages, current_page} 字典)
user_permissions = get_current_user_permissions()
@ -98,13 +99,43 @@ def get_bom_list():
def get_bom_summary():
try:
keyword = request.args.get('keyword', '').strip() or None
data = BomService.get_bom_summary(keyword=keyword)
status = request.args.get('status', '').strip() or None
data = BomService.get_bom_summary(keyword=keyword, status=status)
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 独立启停(仅更新状态,不触发整表保存) ====================
@bom_bp.route('/status', methods=['POST'])
@jwt_required()
@permission_required('bom_manage:operation')
@audit_log(
module='BOM管理',
action='更新状态',
get_target_name_fn=lambda: (request.get_json() or {}).get('bom_no')
)
def update_bom_status():
"""仅切换某 BOM 版本(整组)的启用/停用状态。"""
try:
data = request.get_json() or {}
bom_no = data.get('bom_no')
version = data.get('version')
is_enabled = data.get('is_enabled')
if not bom_no or not version:
return jsonify({'code': 400, 'msg': 'bom_no 与 version 不能为空'}), 400
if not isinstance(is_enabled, bool):
return jsonify({'code': 400, 'msg': 'is_enabled 必须为布尔值'}), 400
BomService.update_enabled(bom_no, version, is_enabled)
return jsonify({'code': 200, 'msg': '更新成功'})
except ValueError as e:
return jsonify({'code': 400, 'msg': str(e)}), 400
except Exception as e:
current_app.logger.error(f'更新BOM状态失败: {str(e)}')
return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500
@bom_bp.route('/detail/<path:bom_no>', methods=['GET'])
@jwt_required()
@permission_required('bom_manage')
@ -398,6 +429,27 @@ def get_material_base_list():
return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500
@bom_bp.route('/self-bom-versions', methods=['GET'])
@jwt_required()
@permission_required('bom_manage')
def get_child_bom_versions():
"""
获取某物料作为父件时的"启用配方版本清单"(bom_no, version)。
前端在编辑/新建 BOM、选中自制件子件后调用用于生成必选版本下拉。
Query参数: child_id (必填, 物料ID)
返回 data: [{bom_no, version}, ...];空数组 = 该物料非自制件(无现行 BOM),无需选版本。
"""
try:
child_id = request.args.get('child_id', type=int)
if not child_id:
return jsonify({'code': 400, 'msg': 'child_id 不能为空'}), 400
data = BomService.get_child_bom_versions(child_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('/parents', methods=['GET'])
@jwt_required()
@permission_required('bom_manage')