fix(借库审批): borrow_service pytz时区修复 + transactions except块traceback增强
This commit is contained in:
@ -3,6 +3,7 @@ from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
|
||||
from app.utils.decorators import permission_required, audit_log
|
||||
from app.services.auth_service import AuthService
|
||||
from app.services.trans_service import TransService
|
||||
from app.services.borrow_service import BorrowApprovalService
|
||||
import traceback
|
||||
|
||||
trans_bp = Blueprint('transactions', __name__, url_prefix='/transactions')
|
||||
@ -29,6 +30,16 @@ def get_current_user_permissions():
|
||||
return perms
|
||||
|
||||
|
||||
def get_current_user_info():
|
||||
"""获取当前用户信息和角色"""
|
||||
from app.models.system import SysUser
|
||||
identity = get_jwt_identity()
|
||||
if not identity:
|
||||
return None, None
|
||||
user = SysUser.query.get(identity)
|
||||
return user.id if user else None, user.role if user else None
|
||||
|
||||
|
||||
def filter_item_by_permissions(item_dict, user_permissions, prefix='op_records'):
|
||||
"""
|
||||
根据用户权限过滤 item 字典,无权限的字段值置为 None
|
||||
@ -125,3 +136,178 @@ def get_records():
|
||||
if res.get('items'):
|
||||
res['items'] = [filter_item_by_permissions(item, user_permissions, 'op_records') for item in res['items']]
|
||||
return jsonify({'code': 200, 'data': res})
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# 借库审批流 API(与出库审批流平行)
|
||||
# ==============================================================================
|
||||
|
||||
# --- 提交借库申请 ---
|
||||
@trans_bp.route('/borrow/request', methods=['POST'])
|
||||
@jwt_required()
|
||||
def submit_borrow_request():
|
||||
"""
|
||||
提交借库申请(仅存储意向,不扣库存)
|
||||
请求体: { items: [...], allowed_approvers: [...], remark: '', approver_id: int }
|
||||
"""
|
||||
try:
|
||||
user_id, user_role = get_current_user_info()
|
||||
if not user_id:
|
||||
return jsonify({'code': 401, 'msg': '用户未登录'}), 401
|
||||
|
||||
from app.models.system import SysUser
|
||||
current_user = SysUser.query.get(user_id)
|
||||
current_username = current_user.username if current_user else None
|
||||
|
||||
data = request.get_json() or {}
|
||||
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 str(item.get(f) or '').strip() == '']
|
||||
if missing:
|
||||
return jsonify({
|
||||
'code': 400,
|
||||
'msg': f'第{idx + 1}条物品缺少必填字段: {", ".join(missing)}'
|
||||
}), 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 = 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 = BorrowApprovalService.submit_approval(
|
||||
applicant_id=user_id,
|
||||
items=items,
|
||||
allowed_approvers=allowed_approvers,
|
||||
remark=data.get('remark'),
|
||||
approver_id=approver_id,
|
||||
borrower_name=current_username
|
||||
)
|
||||
|
||||
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:
|
||||
return jsonify({'code': 500, 'msg': f"接口内部报错: {str(e)}", 'trace': traceback.format_exc()}), 500
|
||||
|
||||
|
||||
# --- 审批借库申请 ---
|
||||
@trans_bp.route('/borrow/request/<int:request_id>/approve', methods=['PATCH'])
|
||||
@jwt_required()
|
||||
def approve_borrow_request(request_id):
|
||||
"""
|
||||
审批借库申请
|
||||
请求体: {"action": "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 = BorrowApprovalService.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
|
||||
|
||||
|
||||
# --- 获取借库审批单列表 ---
|
||||
@trans_bp.route('/borrow/request', methods=['GET'])
|
||||
@jwt_required()
|
||||
def get_borrow_request_list():
|
||||
"""
|
||||
获取借库审批单列表
|
||||
Query参数: page, limit, applicant_id, status
|
||||
"""
|
||||
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 = BorrowApprovalService.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:
|
||||
return jsonify({'code': 500, 'msg': str(e)}), 500
|
||||
|
||||
|
||||
# --- 执行借库扣减(审批通过后调用)---
|
||||
@trans_bp.route('/borrow/dispatch', methods=['POST'])
|
||||
@jwt_required()
|
||||
@permission_required('op_borrow:operation')
|
||||
def dispatch_borrow():
|
||||
"""
|
||||
执行借库扣减
|
||||
请求体: {
|
||||
approval_id: int, // 关联的审批单ID
|
||||
items: [...], // 扫码选中的库存物品(含 id, source_table, out_quantity)
|
||||
borrower_name: str,
|
||||
signature_path: str,
|
||||
remark: str,
|
||||
expected_return_time: str
|
||||
}
|
||||
"""
|
||||
try:
|
||||
data = request.get_json() or {}
|
||||
approval_id = data.get('approval_id')
|
||||
if not approval_id:
|
||||
return jsonify({'code': 400, 'msg': '缺少 approval_id'}), 400
|
||||
|
||||
borrow_no = TransService.execute_dispatch(
|
||||
approval_id=approval_id,
|
||||
items=data.get('items', []),
|
||||
operator_name=get_jwt_identity(),
|
||||
borrower_name=data.get('borrower_name'),
|
||||
signature=data.get('signature_path'),
|
||||
remark=data.get('remark'),
|
||||
expected_return_time=data.get('expected_return_time')
|
||||
)
|
||||
|
||||
return jsonify({'code': 200, 'msg': '借库成功', 'data': {'borrow_no': borrow_no}}), 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
|
||||
|
||||
Reference in New Issue
Block a user