import traceback from flask import Blueprint, request, jsonify, current_app from flask_jwt_extended import jwt_required, get_jwt_identity from app.services.purchase_service import PurchaseService from app.utils.decorators import permission_required purchase_bp = Blueprint('purchase', __name__, url_prefix='/api/v1/purchase') def get_current_user_id(): """获取当前登录用户ID""" identity = get_jwt_identity() return identity def get_current_user_role(): """获取当前用户角色""" from flask_jwt_extended import get_jwt claims = get_jwt() return claims.get('role') # -------------------------------------------------------- # 1. 采购申请列表 # GET /api/v1/purchase # -------------------------------------------------------- @purchase_bp.route('', methods=['GET']) @jwt_required() def get_purchase_list(): """获取采购申请列表""" try: page = int(request.args.get('page', 1)) per_page = int(request.args.get('limit', 20)) status = request.args.get('status') status = int(status) if status is not None else None user_id = get_current_user_id() role = get_current_user_role() # 普通用户(SUPERVISOR 和 SUPER_ADMIN 除外)只看自己提交的 is_admin = role in ('SUPERVISOR', 'SUPER_ADMIN') result = PurchaseService.get_purchase_list( page=page, per_page=per_page, requester_id=None if is_admin else user_id, status=status ) return jsonify({'code': 200, 'msg': '获取成功', 'data': result}) except Exception as e: traceback.print_exc() return jsonify({'code': 500, 'msg': f'获取失败: {str(e)}'}), 500 # -------------------------------------------------------- # 2. 创建采购申请 # POST /api/v1/purchase # -------------------------------------------------------- @purchase_bp.route('', methods=['POST']) @jwt_required() def create_purchase_request(): """创建采购申请""" try: data = request.get_json() if not data: return jsonify({'code': 400, 'msg': '无有效数据'}), 400 user_id = get_current_user_id() # 必填校验 required = ['name', 'quantity', 'purchase_date', 'approver_id'] for field in required: if field not in data or str(data.get(field, '')).strip() == '': return jsonify({'code': 400, 'msg': f'缺少必填字段: {field}'}), 400 purchase = PurchaseService.create_purchase_request(data, requester_id=user_id) return jsonify({ 'code': 200, 'msg': '创建成功', 'data': purchase.to_dict() }), 200 except ValueError as e: return jsonify({'code': 400, 'msg': str(e)}), 400 except Exception as e: traceback.print_exc() return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500 # -------------------------------------------------------- # 3. 获取采购申请详情 # GET /api/v1/purchase/ # -------------------------------------------------------- @purchase_bp.route('/', methods=['GET']) @jwt_required() def get_purchase_detail(purchase_id): """获取采购申请详情""" try: purchase = PurchaseService.get_purchase_by_id(purchase_id) if not purchase: return jsonify({'code': 404, 'msg': '采购申请不存在'}), 404 # 普通用户只能看自己的 user_id = get_current_user_id() role = get_current_user_role() is_admin = role in ('SUPERVISOR', 'SUPER_ADMIN') if not is_admin and purchase['requester_id'] != user_id: return jsonify({'code': 403, 'msg': '无权查看此申请'}), 403 return jsonify({'code': 200, 'msg': '获取成功', 'data': purchase}), 200 except Exception as e: return jsonify({'code': 500, 'msg': str(e)}), 500 # -------------------------------------------------------- # 4. 审批采购申请 # PATCH /api/v1/purchase//approve # -------------------------------------------------------- @purchase_bp.route('//approve', methods=['PATCH']) @jwt_required() def approve_purchase_request(purchase_id): """审批采购申请""" try: user_id = get_current_user_id() role = get_current_user_role() if role not in ('SUPERVISOR', 'SUPER_ADMIN'): return jsonify({'code': 403, 'msg': '只有主管或超级管理员可以审批'}), 403 data = request.get_json() or {} action = data.get('action', 'approve') reject_reason = data.get('reject_reason') if action not in ('approve', 'reject'): return jsonify({'code': 400, 'msg': '无效的审批操作'}), 400 if action == 'reject' and not reject_reason: return jsonify({'code': 400, 'msg': '驳回时必须提供原因'}), 400 purchase = PurchaseService.approve_purchase_request( purchase_id=purchase_id, user_id=user_id, action=action, reject_reason=reject_reason ) msg = '审批通过' if action == 'approve' else '已驳回' return jsonify({'code': 200, 'msg': msg, 'data': purchase.to_dict()}), 200 except ValueError as e: return jsonify({'code': 400, 'msg': str(e)}), 400 except Exception as e: traceback.print_exc() return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500 # -------------------------------------------------------- # 5. 获取可选审批人列表 # GET /api/v1/purchase/approvers # -------------------------------------------------------- @purchase_bp.route('/approvers', methods=['GET']) @jwt_required() def get_purchase_approvers(): """获取可选审批人列表(主管+超管)""" try: from app.models.system import SysUser users = SysUser.query.filter( SysUser.role.in_(['SUPER_ADMIN', 'SUPERVISOR']), SysUser.status == 'active' ).all() return jsonify({ 'code': 200, 'msg': '获取成功', 'data': [ {'id': u.id, 'username': u.username, 'email': u.email or '', 'role': u.role} for u in users ] }), 200 except Exception as e: return jsonify({'code': 500, 'msg': str(e)}), 500 # -------------------------------------------------------- # 6. 根据名称/规格自动补全 # GET /api/v1/purchase/auto-fill?keyword=xxx # -------------------------------------------------------- @purchase_bp.route('/auto-fill', methods=['GET']) @jwt_required() def auto_fill_purchase(): """根据名称或规格自动补全另一个字段""" try: keyword = request.args.get('keyword', '').strip() if not keyword: return jsonify({'code': 200, 'msg': 'ok', 'data': None}), 200 result = PurchaseService.auto_fill_from_material(keyword) return jsonify({'code': 200, 'msg': 'ok', 'data': result}), 200 except Exception as e: return jsonify({'code': 500, 'msg': str(e)}), 500