From 5c0c1632c357fd41e393384e4e61f47a77bf8eb1 Mon Sep 17 00:00:00 2001 From: DXC Date: Fri, 12 Jun 2026 15:04:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E5=AE=A1=E6=89=B9=E9=82=AE=E4=BB=B6):=20it?= =?UTF-8?q?ems=5Fjson=E5=BA=8F=E5=88=97=E5=8C=96Bug=E4=BF=AE=E5=A4=8D=20+?= =?UTF-8?q?=20=E9=82=AE=E4=BB=B6=E6=96=B9=E6=B3=95=E5=87=BA=E5=BA=93/?= =?UTF-8?q?=E5=80=9F=E5=BA=93=E7=89=A9=E7=90=86=E9=9A=94=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/services/borrow_service.py | 45 ++--- .../app/services/outbound_service.py | 16 +- inventory-backend/app/utils/email_service.py | 170 ++++++++++++++---- 3 files changed, 170 insertions(+), 61 deletions(-) diff --git a/inventory-backend/app/services/borrow_service.py b/inventory-backend/app/services/borrow_service.py index 61dfcac..22c1df0 100644 --- a/inventory-backend/app/services/borrow_service.py +++ b/inventory-backend/app/services/borrow_service.py @@ -136,7 +136,7 @@ class BorrowApprovalService: """发送新借库申请通知邮件给审批人和申请人(静默处理,不阻断主流程)""" try: from flask import current_app - from app.utils.email_service import send_new_request_notify + from app.utils.email_service import send_borrow_new_request_notify from app.models.system import SysUser applicant_name = '' @@ -176,7 +176,7 @@ class BorrowApprovalService: # 4. 分别发送邮件 if applicant_emails: try: - send_new_request_notify( + send_borrow_new_request_notify( to_emails=applicant_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -189,7 +189,7 @@ class BorrowApprovalService: if approver_emails: try: - send_new_request_notify( + send_borrow_new_request_notify( to_emails=approver_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -215,7 +215,7 @@ class BorrowApprovalService: logger = logging.getLogger(__name__) try: - from app.utils.email_service import send_approval_result_notify, send_warehouse_dispatch_notify + from app.utils.email_service import send_borrow_approval_result_notify, send_borrow_dispatch_notify from app.models.system import SysUser as SU # 1. 提取申请人信息 @@ -229,17 +229,32 @@ class BorrowApprovalService: applicant_emails.append(user.email) # 2. 提取物料明细 - items = approval.items_json if approval.items_json else [] + items = approval.get_items() if approval else [] # 3. 分支逻辑 if action == 'approve': - # 3.1 通知库管(带明细) + # 3.1 通知申请人(审批已通过,明确告知结果) + if applicant_emails: + try: + send_borrow_approval_result_notify( + to_emails=applicant_emails, + request_no=approval.request_no, + is_passed=True, + reject_reason='', + applicant_name=applicant_name + ) + except Exception as e: + logger.error(f"[Email] 通知申请人(通过)失败: {e}") + else: + logger.warning("[Email] 申请人无邮箱,无法发送审批通过通知") + + # 3.2 通知库管(请备货) warehouse_role_codes = ['WAREHOUSE_MGR', 'OUTBOUND'] warehouse_emails = BorrowApprovalService._get_emails_by_identifiers(role_codes=warehouse_role_codes) if warehouse_emails: try: - send_warehouse_dispatch_notify( + send_borrow_dispatch_notify( to_emails=warehouse_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -247,24 +262,14 @@ class BorrowApprovalService: ) except Exception as e: logger.error(f"[Email] 通知库管失败: {e}") - - # 3.2 通知申请人(审批通过,带完整物料清单) - if applicant_emails: - try: - send_warehouse_dispatch_notify( - to_emails=applicant_emails, - request_no=approval.request_no, - applicant_name=applicant_name, - items=items - ) - except Exception as e: - logger.error(f"[Email] 通知申请人(通过)失败: {e}") + else: + logger.warning("[Email] 无库管角色邮箱,无法发送备货通知") elif action == 'reject': # 3.3 通知申请人(已驳回) if applicant_emails: try: - send_approval_result_notify( + send_borrow_approval_result_notify( to_emails=applicant_emails, request_no=approval.request_no, is_passed=False, diff --git a/inventory-backend/app/services/outbound_service.py b/inventory-backend/app/services/outbound_service.py index faef504..e8885e3 100644 --- a/inventory-backend/app/services/outbound_service.py +++ b/inventory-backend/app/services/outbound_service.py @@ -709,7 +709,7 @@ class OutboundApprovalService: """发送新申请通知邮件给审批人和申请人(静默处理,不阻断主流程)""" try: from flask import current_app - from app.utils.email_service import send_new_request_notify + from app.utils.email_service import send_outbound_new_request_notify from app.models.system import SysUser applicant_name = '' @@ -749,7 +749,7 @@ class OutboundApprovalService: # 4. 分别发送邮件 if applicant_emails: try: - send_new_request_notify( + send_outbound_new_request_notify( to_emails=applicant_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -762,7 +762,7 @@ class OutboundApprovalService: if approver_emails: try: - send_new_request_notify( + send_outbound_new_request_notify( to_emails=approver_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -871,7 +871,7 @@ class OutboundApprovalService: logger = logging.getLogger(__name__) try: - from app.utils.email_service import send_approval_result_notify, send_warehouse_dispatch_notify + from app.utils.email_service import send_outbound_approval_result_notify, send_outbound_dispatch_notify from app.models.system import SysUser as SU # 1. 提取申请人信息(供两个分支使用) @@ -885,7 +885,7 @@ class OutboundApprovalService: applicant_emails.append(user.email) # 2. 提取物料明细(供通过分支使用) - items = approval.items_json if approval.items_json else [] + items = approval.get_items() if approval else [] # 3. 分支逻辑 if action == 'approve': @@ -895,7 +895,7 @@ class OutboundApprovalService: if warehouse_emails: try: - send_warehouse_dispatch_notify( + send_outbound_dispatch_notify( to_emails=warehouse_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -907,7 +907,7 @@ class OutboundApprovalService: # 3.2 通知申请人(审批通过,带完整物料清单) if applicant_emails: try: - send_warehouse_dispatch_notify( + send_outbound_dispatch_notify( to_emails=applicant_emails, request_no=approval.request_no, applicant_name=applicant_name, @@ -920,7 +920,7 @@ class OutboundApprovalService: # 3.3 通知申请人(已驳回) if applicant_emails: try: - send_approval_result_notify( + send_outbound_approval_result_notify( to_emails=applicant_emails, request_no=approval.request_no, is_passed=False, diff --git a/inventory-backend/app/utils/email_service.py b/inventory-backend/app/utils/email_service.py index 18bc9cc..1b6b58e 100644 --- a/inventory-backend/app/utils/email_service.py +++ b/inventory-backend/app/utils/email_service.py @@ -118,24 +118,13 @@ def send_email(to_email: Union[str, List[str]], subject: str, content: str): logger.error(f"[Email] 发送邮件时发生未知异常: {e}") -def send_new_request_notify(to_emails: List[str], request_no: str, +def send_outbound_new_request_notify(to_emails: List[str], request_no: str, applicant_name: str = '', remark: str = '', items: list = None, is_applicant_notify: bool = False): """ 通知审批人有新的出库申请单待审批(可附带物料清单) 或通知申请人其申请已提交(is_applicant_notify=True 时) - - Args: - to_emails: 审批人邮箱列表 - request_no: 审批单号 - applicant_name: 申请人姓名 - remark: 申请备注 - items: 物料明细列表(可选) - is_applicant_notify: True=通知申请人(标题:您的出库申请已提交),False=通知审批人(标题:您有一笔新的出库审批待处理) """ - print(f"[DEBUG send_new_request_notify] 入参 items={items}, is_applicant_notify={is_applicant_notify}") - - # 拼装物料表格 rows = [] rows.append("名称 | 规格 | 计划数量") rows.append("-" * 40) @@ -194,21 +183,78 @@ https://172.16.0.198/outbound/approval send_email(to_emails, subject, content) -def send_approval_result_notify(to_emails: List[str], request_no: str, +def send_borrow_new_request_notify(to_emails: List[str], request_no: str, + applicant_name: str = '', remark: str = '', + items: list = None, is_applicant_notify: bool = False): + """ + 通知审批人有新的借库申请单待审批(可附带物料清单) + 或通知申请人其申请已提交(is_applicant_notify=True 时) + """ + rows = [] + rows.append("名称 | 规格 | 计划数量") + rows.append("-" * 40) + if items: + for item in items: + name = item.get('name', '-') or '-' + spec = item.get('spec_model', '-') or '-' + qty = item.get('quantity', '-') or '-' + rows.append(f"{name} | {spec} | {qty}") + else: + rows.append("(无物料明细)") + + if is_applicant_notify: + subject = f"【已提交】您的借库申请单 {request_no} 已提交" + content = f"""您好, + +您的借库申请单 {request_no} 已成功提交,等待审批。 + + 申请单号:{request_no} + 申请人:{applicant_name or '未知'} + 备注说明:{remark or '无'} + +物料清单如下: +{chr(10).join(rows)} + +--- +您可以点击下方链接查看申请状态: +https://172.16.0.198/operation/borrow_apply +--- + +此邮件由系统自动发送,请勿回复。 +""" + else: + subject = f"【待审批】借库申请单 {request_no}" + content = f"""您好, + +您有一笔新的借库审批申请待处理: + + 申请单号:{request_no} + 申请人:{applicant_name or '未知'} + 备注说明:{remark or '无'} + +物料清单如下: +{chr(10).join(rows)} + +--- +⚡ 快速通道: +请点击下方链接直接进入系统审批: +https://172.16.0.198/operation/borrow_approval +--- + +请登录仓库管理系统进行审批。 + +此邮件由系统自动发送,请勿回复。 +""" + send_email(to_emails, subject, content) + + +def send_outbound_approval_result_notify(to_emails: List[str], request_no: str, is_passed: bool, reject_reason: str = '', applicant_name: str = ''): """ - 通知审批结果 - - Args: - to_emails: 收件人邮箱列表 - request_no: 审批单号 - is_passed: 是否通过(通过时发给库管,驳回时发给申请人) - reject_reason: 驳回原因(仅 is_passed=False 时使用) - applicant_name: 申请人姓名(仅驳回通知时使用) + 通知出库审批结果 """ if is_passed: - # ★ 发给申请人:告知已通过,去领料 subject = f"【已通过】出库申请单 {request_no}" content = f"""{"尊敬的 " + applicant_name + ",您好" if applicant_name else "您好"}, @@ -219,7 +265,6 @@ def send_approval_result_notify(to_emails: List[str], request_no: str, 此邮件由系统自动发送,请勿回复。 """ else: - # ★ 发给申请人:告知被驳回 subject = f"【已驳回】出库申请单 {request_no}" content = f"""{"尊敬的 " + applicant_name + ",您好" if applicant_name else "您好"}, @@ -234,19 +279,43 @@ def send_approval_result_notify(to_emails: List[str], request_no: str, send_email(to_emails, subject, content) -def send_warehouse_dispatch_notify(to_emails: List[str], request_no: str, +def send_borrow_approval_result_notify(to_emails: List[str], request_no: str, + is_passed: bool, reject_reason: str = '', + applicant_name: str = ''): + """ + 通知借库审批结果 + """ + if is_passed: + subject = f"【已通过】借库申请单 {request_no}" + content = f"""{"尊敬的 " + applicant_name + ",您好" if applicant_name else "您好"}, + +您的借库申请单 {request_no} 已审批通过,请前往仓库扫码借出。 + +请登录仓库管理系统查看详情。 + +此邮件由系统自动发送,请勿回复。 +""" + else: + subject = f"【已驳回】借库申请单 {request_no}" + content = f"""{"尊敬的 " + applicant_name + ",您好" if applicant_name else "您好"}, + +借库申请单 {request_no} 已被审批驳回。 + +驳回原因:{reject_reason or '未填写'} + +请登录仓库管理系统查看详情,并根据驳回原因调整后重新提交申请。 + +此邮件由系统自动发送,请勿回复。 +""" + send_email(to_emails, subject, content) + + +def send_outbound_dispatch_notify(to_emails: List[str], request_no: str, applicant_name: str = '', items: list = None): """ 通知库管备货出库(包含完整物料清单) - - Args: - to_emails: 库管邮箱列表 - request_no: 审批单号 - applicant_name: 申请人姓名 - items: 物料明细列表,每个元素包含 name/spec_model/warehouse_location/quantity """ - print(f"[DEBUG send_warehouse_dispatch_notify] 入参 items={items}") - print(f"[DEBUG send_warehouse_dispatch_notify] items 类型={type(items)}, 长度={len(items) if items else 0}") + print(f"[DEBUG send_outbound_dispatch_notify] 入参 items={items}") rows = [] rows.append("名称 | 规格 | 库位 | 计划数量") @@ -275,4 +344,39 @@ def send_warehouse_dispatch_notify(to_emails: List[str], request_no: str, 此邮件由系统自动发送,请勿回复。 """ send_email(to_emails, subject, content) - print(f"DEBUG: 准备向服务器提交发信请求,收件人: {to_emails}") + + +def send_borrow_dispatch_notify(to_emails: List[str], request_no: str, + applicant_name: str = '', items: list = None): + """ + 通知库管备货借库(包含完整物料清单) + """ + print(f"[DEBUG send_borrow_dispatch_notify] 入参 items={items}") + + rows = [] + rows.append("名称 | 规格 | 库位 | 计划数量") + rows.append("-" * 50) + if items: + for item in items: + name = item.get('name', '-') or '-' + spec = item.get('spec_model', '-') or '-' + loc = item.get('warehouse_location', '-') or '-' + qty = item.get('quantity', '-') or '-' + rows.append(f"{name} | {spec} | {loc} | {qty}") + else: + rows.append("(无物料明细)") + + subject = f"【待借库】借库申请单 {request_no} 已审批通过" + content = f"""您好, + +借库申请单 {request_no} 已审批通过,请按以下清单准备备货: + +{chr(10).join(rows)} + +申请人:{applicant_name or '未知'} + +请登录仓库管理系统执行"扫码借库"操作。 + +此邮件由系统自动发送,请勿回复。 +""" + send_email(to_emails, subject, content)