97 lines
4.7 KiB
Python
97 lines
4.7 KiB
Python
"""CRM/运费审批通知快照;只读业务状态,不发送消息、不提交事务。"""
|
|
from urllib.parse import quote
|
|
|
|
from app.models.crm_models import CrmContract, CrmContractApproval, CrmQuote, CrmQuoteApproval
|
|
from app.models.pl_models import PlFreightSettlement, PlFreightSettlementApproval
|
|
from app.services.wechat_notice_types import NoticeSnapshot, PendingApprover
|
|
|
|
|
|
_SOURCES = {
|
|
"crm_quote": (CrmQuote, CrmQuoteApproval, "quote_id", "quote_no", "报价单审批"),
|
|
"crm_contract": (CrmContract, CrmContractApproval, "contract_id", "contract_no", "合同审批"),
|
|
"pl_freight": (PlFreightSettlement, PlFreightSettlementApproval, "settlement_id", "settlement_no", "运费结算审批"),
|
|
}
|
|
|
|
# 保留本轮审批结论,后续签订/执行/转合同/发放不撤销已产生的结果通知。
|
|
# 合同签订直接进入 executing,当前业务没有 signed 状态。
|
|
_APPROVED_LIFECYCLE_STATUSES = {
|
|
"crm_quote": {"accepted", "converted", "viewed", "expired"},
|
|
"crm_contract": {"approved", "executing", "finished"},
|
|
"pl_freight": {"approved", "confirmed"},
|
|
}
|
|
|
|
|
|
def get_snapshot(db, biz_type, biz_id, tenant_no):
|
|
source = _SOURCES.get(biz_type)
|
|
if not source:
|
|
return None
|
|
model, approval_model, foreign_key, number_field, name = source
|
|
document = db.query(model).filter(
|
|
model.id == biz_id, model.tenant_no == tenant_no, model.del_flag == 0
|
|
).first()
|
|
if document is None:
|
|
return None
|
|
approvals = db.query(approval_model).filter(
|
|
getattr(approval_model, foreign_key) == biz_id,
|
|
approval_model.tenant_no == tenant_no,
|
|
approval_model.del_flag == 0,
|
|
).order_by(approval_model.step.asc(), approval_model.create_time.asc(), approval_model.id.asc()).all()
|
|
applicant_id = next((row.create_by for row in approvals if row.create_by), document.create_by or "")
|
|
started_at = min((row.create_time for row in approvals if row.create_time), default=None)
|
|
status = document.settlement_status if biz_type == "pl_freight" else document.status
|
|
active = status == ("submitted" if biz_type == "crm_quote" else "approving")
|
|
pending = []
|
|
if active:
|
|
for row in approvals:
|
|
if row.approval_result != "pending":
|
|
continue
|
|
if biz_type == "crm_quote":
|
|
if any(prior.step < row.step and prior.approval_result != "approved" for prior in approvals):
|
|
continue
|
|
elif row.is_current != 1:
|
|
continue
|
|
pending.append(PendingApprover(task_key=f"{row.id}:{row.approver_id}", user_id=row.approver_id))
|
|
result = None
|
|
if biz_type == "crm_quote":
|
|
if status in _APPROVED_LIFECYCLE_STATUSES[biz_type]:
|
|
result = "approved"
|
|
elif status == "rejected":
|
|
result = "rejected"
|
|
elif biz_type == "crm_contract":
|
|
if status in _APPROVED_LIFECYCLE_STATUSES[biz_type] and document.approval_status == "approved":
|
|
result = "approved"
|
|
elif status == "draft" and document.approval_status == "rejected":
|
|
result = "rejected"
|
|
else:
|
|
if status in _APPROVED_LIFECYCLE_STATUSES[biz_type]:
|
|
result = "approved"
|
|
elif status == "rejected":
|
|
result = "rejected"
|
|
if result == "approved":
|
|
allowed_results = {"approved", "skipped"} if biz_type == "pl_freight" else {"approved"}
|
|
# 手工改为 accepted / approved 或旧状态修复不能代替完整的本轮审批。
|
|
if not approvals or any(row.approval_result not in allowed_results for row in approvals):
|
|
result = None
|
|
completed = [row for row in approvals if row.approval_result == result and row.approval_time]
|
|
terminal = max(completed, key=lambda row: (row.approval_time, row.step, row.id)) if completed else None
|
|
# Old status-only records do not establish a real approval result.
|
|
if terminal is None:
|
|
result = None
|
|
if result:
|
|
name = (document.quote_title if biz_type == "crm_quote" else
|
|
document.contract_name if biz_type == "crm_contract" else "运费结算单") or name
|
|
page = ""
|
|
if biz_type != "pl_freight":
|
|
domain = "quote" if biz_type == "crm_quote" else "contract"
|
|
path = f"/m/crm/{domain}/{quote(str(biz_id), safe='')}"
|
|
if active:
|
|
path += "?from=approve"
|
|
page = "pages/common/mp-webview?path=" + quote(path, safe="")
|
|
return NoticeSnapshot(
|
|
business_name=name, business_no=getattr(document, number_field) or "",
|
|
applicant_id=applicant_id, pending=pending, result=result,
|
|
approver_id=terminal.approver_id if terminal else "",
|
|
occurred_at=terminal.approval_time if terminal else started_at,
|
|
page=page,
|
|
)
|