from flask import Blueprint, request, jsonify, current_app from app.services.bom_service import BomService from app.models.base import MaterialBase from app.models.bom import BomTable from app.extensions import db from flask_jwt_extended import jwt_required from sqlalchemy import distinct bom_bp = Blueprint('bom', __name__) # ==================== 新版 BOM 接口(基于 bom_no) ==================== @bom_bp.route('/list', methods=['GET']) @jwt_required() def get_bom_list(): """获取所有 BOM 配方列表(按 bom_no 分组)""" try: data = BomService.get_bom_list() 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('/detail/', methods=['GET']) @jwt_required() def get_bom_detail(bom_no): """根据 BOM 编号获取配方详情""" try: data = BomService.get_bom_detail(bom_no) if not data: return jsonify({'code': 404, 'msg': 'BOM 不存在'}), 404 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('/save', methods=['POST']) @jwt_required() def save_bom(): """保存或更新 BOM 配方(支持新建和另存为新版本)""" try: req_data = request.get_json() # 必需字段校验 if 'parent_id' not in req_data or 'children' not in req_data: return jsonify({'code': 400, 'msg': '缺少 parent_id 或 children 字段'}), 400 bom_no = BomService.save_bom(req_data) return jsonify({ 'code': 200, 'msg': '保存成功', 'data': {'bom_no': bom_no} }) 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('/stock/', methods=['GET']) @jwt_required() def get_bom_with_stock_by_no(bom_no): """根据 BOM 编号获取配方详情及库存信息""" try: data = BomService.get_bom_with_stock_by_bom_no(bom_no) if not data: return jsonify({'code': 404, 'msg': 'BOM 不存在'}), 404 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_no删除整个配方) ==================== @bom_bp.route('/', methods=['DELETE']) @jwt_required() def delete_bom(bom_no): """根据 BOM 编号删除整个配方(包括所有子件记录)""" try: # 先检查是否存在 exist = BomTable.query.filter_by(bom_no=bom_no).first() if not exist: return jsonify({'code': 404, 'msg': 'BOM 不存在'}), 404 # 删除该 bom_no 下所有记录 BomTable.query.filter_by(bom_no=bom_no).delete() db.session.commit() return jsonify({ 'code': 200, 'msg': '删除成功' }) except Exception as e: current_app.logger.error(f'删除BOM失败: {str(e)}') return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 # ==================== 兼容旧接口(保留不改动现有前端) ==================== @bom_bp.route('/', 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_legacy(): 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 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('/base/list', methods=['GET']) @jwt_required() def get_material_base_list(): """获取所有基础物料列表,用于前端下拉框""" try: materials = MaterialBase.query.filter_by(is_enabled=True).order_by(MaterialBase.id.desc()).all() data = [item.to_dict() for item in materials] return jsonify({ 'code': 200, 'msg': 'success', 'data': data }) except Exception as e: current_app.logger.error(f'获取基础物料列表失败: {str(e)}') return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @bom_bp.route('/parents', methods=['GET']) @jwt_required() def get_bom_parents(): """获取所有已定义BOM的父件物料列表(兼容旧版)""" try: subq = db.session.query(BomTable.parent_id).distinct().subquery() parents = MaterialBase.query.join(subq, MaterialBase.id == subq.c.parent_id).all() data = [item.to_dict() for item in parents] 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