2026-02-04 17:22:20 +08:00
|
|
|
|
from flask import Blueprint, request, jsonify
|
|
|
|
|
|
from app.services.outbound_service import OutboundService
|
2026-02-27 13:54:06 +08:00
|
|
|
|
from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
|
2026-03-10 17:16:57 +08:00
|
|
|
|
from app.utils.decorators import permission_required, audit_log
|
2026-02-27 13:54:06 +08:00
|
|
|
|
from app.services.auth_service import AuthService
|
2026-02-05 10:20:52 +08:00
|
|
|
|
import traceback
|
2026-02-04 17:22:20 +08:00
|
|
|
|
|
|
|
|
|
|
outbound_bp = Blueprint('outbound', __name__, url_prefix='/outbound')
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-02-27 13:57:59 +08:00
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
# 辅助函数:获取当前用户的完整权限列表(基于角色查询)
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
def get_current_user_permissions():
|
|
|
|
|
|
"""
|
|
|
|
|
|
返回当前用户拥有的所有权限码列表(包括菜单和元素)
|
|
|
|
|
|
此函数根据角色查询数据库得到权限。
|
|
|
|
|
|
"""
|
|
|
|
|
|
from flask_jwt_extended import get_jwt
|
|
|
|
|
|
from app.services.auth_service import AuthService
|
|
|
|
|
|
claims = get_jwt()
|
|
|
|
|
|
user_role = claims.get('role')
|
|
|
|
|
|
if not user_role:
|
|
|
|
|
|
return []
|
2026-02-27 17:04:22 +08:00
|
|
|
|
# 超级管理员返回所有字段权限 (忽略大小写)
|
|
|
|
|
|
if user_role.upper() == 'SUPER_ADMIN':
|
2026-02-27 13:57:59 +08:00
|
|
|
|
return ['outbound_list:*']
|
|
|
|
|
|
perm_dict = AuthService.get_user_permissions(user_role)
|
|
|
|
|
|
# 合并菜单和元素权限
|
|
|
|
|
|
perms = perm_dict.get('menus', []) + perm_dict.get('elements', [])
|
|
|
|
|
|
return perms
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def filter_item_by_permissions(item_dict, user_permissions):
|
|
|
|
|
|
"""
|
|
|
|
|
|
根据用户权限过滤 item 字典,无权限的字段值置为 None
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 字段名到权限码的映射(与前端 permissionMap 保持一致)
|
|
|
|
|
|
field_to_perm = {
|
|
|
|
|
|
'outbound_no': 'outbound_list:outbound_no',
|
|
|
|
|
|
'outbound_time': 'outbound_list:outbound_time',
|
|
|
|
|
|
'outbound_type': 'outbound_list:outbound_type',
|
|
|
|
|
|
'total_amount': 'outbound_list:total_amount',
|
|
|
|
|
|
'consumer_name': 'outbound_list:consumer_name',
|
|
|
|
|
|
'operator_name': 'outbound_list:operator_name',
|
|
|
|
|
|
'remark': 'outbound_list:remark',
|
|
|
|
|
|
'signature_path': 'outbound_list:signature_path',
|
|
|
|
|
|
# 明细字段
|
|
|
|
|
|
'sku': 'outbound_list:sku',
|
|
|
|
|
|
'name': 'outbound_list:name',
|
|
|
|
|
|
'material_type': 'outbound_list:material_type',
|
|
|
|
|
|
'category': 'outbound_list:category',
|
|
|
|
|
|
'spec_model': 'outbound_list:spec_model',
|
|
|
|
|
|
'quantity': 'outbound_list:quantity',
|
|
|
|
|
|
'unit_price': 'outbound_list:unit_price',
|
|
|
|
|
|
'subtotal': 'outbound_list:subtotal',
|
|
|
|
|
|
}
|
|
|
|
|
|
# 如果用户是超级管理员且有 'outbound_list:*',则不过滤
|
|
|
|
|
|
if 'outbound_list:*' in user_permissions:
|
|
|
|
|
|
return item_dict
|
|
|
|
|
|
for field, perm_code in field_to_perm.items():
|
|
|
|
|
|
if field in item_dict and perm_code not in user_permissions:
|
|
|
|
|
|
item_dict[field] = None
|
|
|
|
|
|
# 如果 item_dict 中包含 items 列表,递归处理每个子项
|
|
|
|
|
|
if 'items' in item_dict and isinstance(item_dict['items'], list):
|
|
|
|
|
|
for sub_item in item_dict['items']:
|
|
|
|
|
|
filter_item_by_permissions(sub_item, user_permissions)
|
|
|
|
|
|
return item_dict
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-02-04 17:22:20 +08:00
|
|
|
|
# --------------------------------------------------------
|
2026-02-05 10:20:52 +08:00
|
|
|
|
# 1. 扫码查询库存接口 (关联三个库存表)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
# GET /api/v1/outbound/scan?barcode=...
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('/scan', methods=['GET'])
|
|
|
|
|
|
@jwt_required()
|
2026-02-27 13:45:49 +08:00
|
|
|
|
@permission_required('outbound_selection')
|
2026-02-04 17:22:20 +08:00
|
|
|
|
def scan_barcode():
|
|
|
|
|
|
barcode = request.args.get('barcode')
|
|
|
|
|
|
if not barcode:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '请提供条码'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# 调用 Service 层去三个表中查找 (Service已更新,会返回价格)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
result = OutboundService.get_stock_by_barcode(barcode)
|
2026-02-05 10:20:52 +08:00
|
|
|
|
|
2026-02-04 17:22:20 +08:00
|
|
|
|
if result:
|
2026-02-05 10:20:52 +08:00
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': '扫描成功',
|
|
|
|
|
|
'data': result
|
|
|
|
|
|
})
|
2026-02-04 17:22:20 +08:00
|
|
|
|
else:
|
2026-02-05 10:20:52 +08:00
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 404,
|
|
|
|
|
|
'msg': '未找到对应的库存记录,请确认条码是否正确'
|
|
|
|
|
|
}), 404
|
|
|
|
|
|
|
2026-02-04 17:22:20 +08:00
|
|
|
|
except Exception as e:
|
2026-02-05 10:20:52 +08:00
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
return jsonify({'code': 500, 'msg': f'扫描查询出错: {str(e)}'}), 500
|
2026-02-04 17:22:20 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --------------------------------------------------------
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# 2. 提交出库单接口 (批量)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
# POST /api/v1/outbound
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('', methods=['POST'])
|
|
|
|
|
|
@jwt_required()
|
2026-03-10 17:16:57 +08:00
|
|
|
|
@audit_log(
|
|
|
|
|
|
module='出库管理',
|
|
|
|
|
|
action='新增',
|
|
|
|
|
|
get_target_name_fn=lambda: request.get_json().get('order_no') if request.get_json() else None
|
|
|
|
|
|
)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
def create_outbound():
|
2026-02-27 13:54:06 +08:00
|
|
|
|
# 权限检查:需要 outbound_create:operation 或 outbound_selection:operation 之一
|
|
|
|
|
|
claims = get_jwt()
|
|
|
|
|
|
user_role = claims.get('role')
|
|
|
|
|
|
if not user_role:
|
|
|
|
|
|
return jsonify({'code': 403, 'msg': '未授权'}), 403
|
|
|
|
|
|
|
|
|
|
|
|
# 超级管理员直接放行
|
2026-02-27 17:07:45 +08:00
|
|
|
|
if user_role.upper() != 'SUPER_ADMIN':
|
2026-02-27 13:54:06 +08:00
|
|
|
|
perm_dict = AuthService.get_user_permissions(user_role)
|
|
|
|
|
|
perms = perm_dict.get('menus', []) + perm_dict.get('elements', [])
|
|
|
|
|
|
if ('outbound_create:operation' not in perms) and ('outbound_selection:operation' not in perms):
|
|
|
|
|
|
return jsonify({'code': 403, 'msg': '权限不足'}), 403
|
|
|
|
|
|
|
2026-02-04 17:22:20 +08:00
|
|
|
|
data = request.get_json()
|
|
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '无有效数据'}), 400
|
|
|
|
|
|
|
2026-02-05 10:20:52 +08:00
|
|
|
|
# 获取当前登录用户名 (JWT identity)
|
|
|
|
|
|
current_user_name = get_jwt_identity()
|
|
|
|
|
|
if not current_user_name:
|
|
|
|
|
|
current_user_name = 'Unknown'
|
|
|
|
|
|
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# 获取最终的操作员名称
|
2026-02-05 10:20:52 +08:00
|
|
|
|
final_operator = data.get('operator_name')
|
|
|
|
|
|
if not final_operator:
|
|
|
|
|
|
final_operator = current_user_name
|
2026-02-04 17:22:20 +08:00
|
|
|
|
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# 必填校验 (针对整个单据)
|
|
|
|
|
|
# items 必须是列表且不为空,consumer_name 和 signature_path 必填
|
|
|
|
|
|
if 'items' not in data or not data['items']:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '出库商品列表不能为空'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
if not data.get('consumer_name') or not data.get('signature_path'):
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '领用人及签名信息缺失'}), 400
|
2026-02-04 17:22:20 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# ★ [修改] 调用批量创建服务
|
|
|
|
|
|
outbound_no = OutboundService.create_outbound_batch(data, operator_name=final_operator)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': '出库成功',
|
2026-02-05 16:54:11 +08:00
|
|
|
|
'data': {'outbound_no': outbound_no}
|
2026-02-04 17:22:20 +08:00
|
|
|
|
})
|
|
|
|
|
|
except ValueError as e:
|
2026-02-05 10:20:52 +08:00
|
|
|
|
# 业务逻辑错误 (如库存不足)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
return jsonify({'code': 400, 'msg': str(e)}), 400
|
|
|
|
|
|
except Exception as e:
|
2026-02-05 10:20:52 +08:00
|
|
|
|
traceback.print_exc()
|
2026-02-04 17:22:20 +08:00
|
|
|
|
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --------------------------------------------------------
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# 3. 获取出库记录列表 (分组展示)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
# GET /api/v1/outbound
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('', methods=['GET'])
|
|
|
|
|
|
@jwt_required()
|
2026-02-27 13:57:59 +08:00
|
|
|
|
@permission_required('outbound_list')
|
2026-02-04 17:22:20 +08:00
|
|
|
|
def get_outbound_list():
|
|
|
|
|
|
try:
|
|
|
|
|
|
page = int(request.args.get('page', 1))
|
2026-02-05 10:20:52 +08:00
|
|
|
|
limit = int(request.args.get('limit', 10))
|
2026-02-04 17:22:20 +08:00
|
|
|
|
keyword = request.args.get('keyword', '')
|
2026-03-20 10:26:45 +08:00
|
|
|
|
search_type = request.args.get('search_type', 'all')
|
2026-02-05 16:54:11 +08:00
|
|
|
|
# 如果前端传了日期范围,可以解析处理,这里暂略
|
2026-02-04 17:22:20 +08:00
|
|
|
|
|
2026-03-20 10:26:45 +08:00
|
|
|
|
# ★ [修改] 调用分组查询服务,支持搜索类型
|
|
|
|
|
|
result = OutboundService.get_grouped_list(page, limit, keyword, search_type=search_type)
|
2026-02-04 17:22:20 +08:00
|
|
|
|
|
2026-02-27 13:57:59 +08:00
|
|
|
|
# 字段级脱敏
|
|
|
|
|
|
user_permissions = get_current_user_permissions()
|
|
|
|
|
|
if result.get('items'):
|
|
|
|
|
|
result['items'] = [filter_item_by_permissions(item, user_permissions) for item in result['items']]
|
|
|
|
|
|
|
2026-02-04 17:22:20 +08:00
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': '获取成功',
|
|
|
|
|
|
'data': result
|
|
|
|
|
|
})
|
|
|
|
|
|
except Exception as e:
|
2026-02-05 10:20:52 +08:00
|
|
|
|
traceback.print_exc()
|
2026-02-27 13:45:49 +08:00
|
|
|
|
return jsonify({'code': 500, 'msg': str(e)}), 500
|
2026-04-28 16:02:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
# 出库审批相关接口
|
|
|
|
|
|
# ==============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
from app.services.outbound_service import OutboundApprovalService
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_user_id():
|
|
|
|
|
|
"""获取当前用户ID"""
|
|
|
|
|
|
from app.models.system import SysUser
|
|
|
|
|
|
identity = get_jwt_identity()
|
|
|
|
|
|
if not identity:
|
|
|
|
|
|
return None
|
|
|
|
|
|
# JWT identity 是数据库主键整数,直接用 .get() 查询
|
|
|
|
|
|
user = SysUser.query.get(identity)
|
|
|
|
|
|
return user.id if user else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_user_info():
|
|
|
|
|
|
"""获取当前用户信息和角色"""
|
|
|
|
|
|
from app.models.system import SysUser
|
|
|
|
|
|
identity = get_jwt_identity()
|
|
|
|
|
|
if not identity:
|
|
|
|
|
|
return None, None
|
|
|
|
|
|
# JWT identity 是数据库主键整数,直接用 .get() 查询
|
|
|
|
|
|
user = SysUser.query.get(identity)
|
|
|
|
|
|
return user.id if user else None, user.role if user else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
# 4. 创建出库审批单
|
|
|
|
|
|
# POST /api/v1/outbound/request
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('/request', methods=['POST'])
|
|
|
|
|
|
@jwt_required()
|
|
|
|
|
|
def create_outbound_request():
|
|
|
|
|
|
"""
|
|
|
|
|
|
创建出库审批单(申请阶段,用户只需提交宏观物料信息,无需关联具体库存记录)
|
|
|
|
|
|
|
|
|
|
|
|
请求体示例:
|
|
|
|
|
|
{
|
|
|
|
|
|
"items": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"name": "物料A", // 物料名称 (必填)
|
|
|
|
|
|
"spec_model": "规格1", // 规格型号 (必填)
|
|
|
|
|
|
"quantity": 10, // 计划出库数量 (必填)
|
|
|
|
|
|
"warehouse_location": "A区-01-01", // 库位 (可选)
|
|
|
|
|
|
"remark": "备注信息" // 物品备注 (可选)
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"allowed_approvers": [
|
|
|
|
|
|
{"type": "role", "value": "SUPERVISOR"},
|
|
|
|
|
|
{"type": "role", "value": "SUPER_ADMIN"}
|
|
|
|
|
|
],
|
|
|
|
|
|
"remark": "紧急出库申请"
|
|
|
|
|
|
}
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
user_id, user_role = get_current_user_info()
|
|
|
|
|
|
if not user_id:
|
|
|
|
|
|
return jsonify({'code': 401, 'msg': '用户未登录'}), 401
|
|
|
|
|
|
|
|
|
|
|
|
data = request.get_json()
|
|
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '无有效数据'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
items = data.get('items', [])
|
|
|
|
|
|
if not items:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '出库物品列表不能为空'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# ★ 申请阶段仅校验宏观字段:名称、规格、数量
|
|
|
|
|
|
required_fields = ['name', 'spec_model', 'quantity']
|
|
|
|
|
|
for idx, item in enumerate(items):
|
|
|
|
|
|
missing = [f for f in required_fields if f not in item or item.get(f) is None or str(item.get(f)).strip() == '']
|
|
|
|
|
|
if missing:
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 400,
|
|
|
|
|
|
'msg': f'第{idx + 1}条物品缺少必填字段: {", ".join(missing)}。'
|
|
|
|
|
|
f'必须包含: name(名称), spec_model(规格), quantity(数量)'
|
|
|
|
|
|
}), 400
|
|
|
|
|
|
try:
|
|
|
|
|
|
qty = float(item.get('quantity', 0))
|
|
|
|
|
|
if qty <= 0:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': f'第{idx + 1}条物品的出库数量必须大于0'}), 400
|
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': f'第{idx + 1}条物品的 quantity 格式无效'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
# ★ 指定审批人:前端传 approver_id 则精准通知,否则用默认角色规则
|
|
|
|
|
|
approver_id = data.get('approver_id')
|
|
|
|
|
|
_default_approvers = [
|
|
|
|
|
|
{"type": "role", "value": "SUPERVISOR"},
|
|
|
|
|
|
{"type": "role", "value": "SUPER_ADMIN"}
|
|
|
|
|
|
]
|
|
|
|
|
|
allowed_approvers = data.get('allowed_approvers') or _default_approvers
|
|
|
|
|
|
|
|
|
|
|
|
# 创建审批单(直接存储前端传来的宏观信息快照,不查询库存)
|
|
|
|
|
|
approval = OutboundApprovalService.create_request(
|
|
|
|
|
|
applicant_id=user_id,
|
|
|
|
|
|
items=items,
|
|
|
|
|
|
allowed_approvers=allowed_approvers,
|
|
|
|
|
|
remark=data.get('remark'),
|
|
|
|
|
|
approver_id=approver_id
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': '审批单创建成功',
|
|
|
|
|
|
'data': approval.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. 审批出库申请
|
|
|
|
|
|
# PATCH /api/v1/outbound/request/<id>/approve
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('/request/<int:request_id>/approve', methods=['PATCH'])
|
|
|
|
|
|
@jwt_required()
|
|
|
|
|
|
def approve_outbound_request(request_id):
|
|
|
|
|
|
"""
|
|
|
|
|
|
审批出库申请
|
|
|
|
|
|
|
|
|
|
|
|
请求体示例:
|
|
|
|
|
|
{
|
|
|
|
|
|
"action": "approve", // "approve" 通过, "reject" 驳回
|
|
|
|
|
|
"reject_reason": "库存不足" // 仅在驳回时需要
|
|
|
|
|
|
}
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
user_id, user_role = get_current_user_info()
|
|
|
|
|
|
if not user_id:
|
|
|
|
|
|
return jsonify({'code': 401, 'msg': '用户未登录'}), 401
|
|
|
|
|
|
|
|
|
|
|
|
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': '无效的审批操作,仅支持 approve 或 reject'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
if action == 'reject' and not reject_reason:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': '驳回时必须提供原因'}), 400
|
|
|
|
|
|
|
|
|
|
|
|
success, message, approval = OutboundApprovalService.approve(
|
|
|
|
|
|
request_id=request_id,
|
|
|
|
|
|
user_id=user_id,
|
|
|
|
|
|
user_role=user_role,
|
|
|
|
|
|
action=action,
|
|
|
|
|
|
reject_reason=reject_reason
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if not success:
|
|
|
|
|
|
return jsonify({'code': 400, 'msg': message}), 400
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': message,
|
|
|
|
|
|
'data': approval.to_dict() if approval else None
|
|
|
|
|
|
}), 200
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
return jsonify({'code': 500, 'msg': f'服务器内部错误: {str(e)}'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
# 6. 获取审批单列表
|
|
|
|
|
|
# GET /api/v1/outbound/request
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('/request', methods=['GET'])
|
|
|
|
|
|
@jwt_required()
|
|
|
|
|
|
def get_outbound_request_list():
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取出库审批单列表
|
|
|
|
|
|
|
|
|
|
|
|
Query参数:
|
|
|
|
|
|
- page: 页码 (默认1)
|
|
|
|
|
|
- limit: 每页数量 (默认10)
|
|
|
|
|
|
- applicant_id: 按申请人筛选 (可选)
|
|
|
|
|
|
- status: 按状态筛选 (0待审/1通过/2驳回/3完成, 可选)
|
|
|
|
|
|
"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
page = int(request.args.get('page', 1))
|
|
|
|
|
|
limit = int(request.args.get('limit', 10))
|
|
|
|
|
|
|
|
|
|
|
|
applicant_id = request.args.get('applicant_id')
|
|
|
|
|
|
if applicant_id:
|
|
|
|
|
|
applicant_id = int(applicant_id)
|
|
|
|
|
|
|
|
|
|
|
|
status = request.args.get('status')
|
|
|
|
|
|
if status is not None:
|
|
|
|
|
|
status = int(status)
|
|
|
|
|
|
|
|
|
|
|
|
result = OutboundApprovalService.get_request_list(
|
|
|
|
|
|
page=page,
|
|
|
|
|
|
per_page=limit,
|
|
|
|
|
|
applicant_id=applicant_id,
|
|
|
|
|
|
status=status
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': '获取成功',
|
|
|
|
|
|
'data': result
|
|
|
|
|
|
}), 200
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
return jsonify({'code': 500, 'msg': str(e)}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
# 7. 获取单个审批单详情
|
|
|
|
|
|
# GET /api/v1/outbound/request/<id>
|
|
|
|
|
|
# --------------------------------------------------------
|
|
|
|
|
|
@outbound_bp.route('/request/<int:request_id>', methods=['GET'])
|
|
|
|
|
|
@jwt_required()
|
|
|
|
|
|
def get_outbound_request_detail(request_id):
|
|
|
|
|
|
"""获取出库审批单详情"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
approval = OutboundApprovalService.get_request_by_id(request_id)
|
|
|
|
|
|
|
|
|
|
|
|
if not approval:
|
|
|
|
|
|
return jsonify({'code': 404, 'msg': '审批单不存在'}), 404
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({
|
|
|
|
|
|
'code': 200,
|
|
|
|
|
|
'msg': '获取成功',
|
|
|
|
|
|
'data': approval.to_dict()
|
|
|
|
|
|
}), 200
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
return jsonify({'code': 500, 'msg': str(e)}), 500
|