dingdanquanliucheng/backend/app/services/arrears_service.py

130 lines
5.1 KiB
Python
Raw Normal View History

"""欠款管理服务模块
负责订单欠款记录的自动生成
当订单状态流转到已发货/已送达等阶段时根据客户的结算天数和结算起始方式
自动创建欠款记录并计算到期日
被调用方 order_service订单状态变更时 logistics_service物流状态变更时调用
"""
from datetime import date, timedelta
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.repositories.config_repository import ConfigRepository
from backend.app.repositories.reminder_repository import ReminderRepository
class ArrearsService:
"""欠款业务服务。
依赖
- ConfigRepository读取欠款生成模式配置
- ReminderRepository欠款记录的查询和创建客户信息查询
"""
def __init__(self) -> None:
self.config_repository = ConfigRepository()
self.reminder_repository = ReminderRepository()
def sync_order_arrears(self, session: Session, order) -> None:
"""根据订单状态同步生成欠款记录。
根据系统配置的触发模式已发货或已送达判断是否需要生成欠款
若订单已有欠款记录则跳过若金额为 0 也跳过
根据客户的结算天数和结算起始方式计算到期日
参数
session: 数据库会话调用方负责 commit/rollback
order: 订单模型对象需包含 idorder_statuscustomer_idsale_price_totalcreated_at 等字段
被调用方order_service订单状态变更时logistics_service物流状态变更时
"""
trigger_mode = self._get_config_value(session, "arrears_generate_mode", "delivered")
if not self._should_generate(trigger_mode, order.order_status):
return
existed = self.reminder_repository.get_arrears_by_order_id(session, order.id)
if existed is not None:
return
settlement_days = 0
customer = None
2026-05-26 11:36:57 +08:00
settlement_start_type = "order_date"
if order.customer_id:
customer = self.reminder_repository.get_customer(session, order.customer_id)
settlement_days = int(customer.settlement_days or 0) if customer else 0
2026-06-14 16:20:04 +08:00
# 从系统配置获取欠款起算节点,而非客户字段
settlement_start_type = "order_date"
2026-05-26 11:36:57 +08:00
settlement_start_date = self._resolve_settlement_start_date(order, settlement_start_type)
due_date = settlement_start_date + timedelta(days=max(settlement_days, 0))
arrears_amount = float(order.sale_price_total or 0)
if arrears_amount <= 0:
return
self.reminder_repository.create_arrears(
session,
{
"customer_id": order.customer_id or 0,
"order_id": order.id,
"arrears_amount": arrears_amount,
"settlement_start_date": settlement_start_date,
"due_date": due_date,
"status": "pending",
},
)
2026-05-26 11:36:57 +08:00
def _resolve_settlement_start_date(self, order, settlement_start_type: str) -> date:
"""根据结算起始方式确定欠款计算的起始日期。
参数
order: 订单模型对象
settlement_start_type: 结算起始方式'order_date' 取订单创建日期
'delivery_date' 取供应商确认日期
返回
结算起始日期无法确定时默认使用今天
"""
2026-05-26 11:36:57 +08:00
if settlement_start_type == "order_date":
if order.created_at:
return order.created_at.date()
return date.today()
if settlement_start_type == "delivery_date":
if order.supplier_text_confirmed_at:
return order.supplier_text_confirmed_at.date()
return date.today()
return date.today()
def _get_config_value(self, session: Session, config_key: str, default: str) -> str:
"""从系统配置表读取配置值,不存在时返回默认值。
参数
session: 数据库会话
config_key: 配置键名
default: 当配置不存在或为空时的默认值
返回
配置值字符串
"""
config = self.config_repository.get_by_key(session, config_key)
return config.config_value if config is not None and config.config_value else default
def _should_generate(self, trigger_mode: str, order_status: str) -> bool:
"""判断当前订单状态是否满足欠款生成条件。
参数
trigger_mode: 触发模式'shipped'已发货 'delivered'已送达
order_status: 订单当前状态
返回
满足条件返回 True否则返回 False
"""
if trigger_mode == "shipped":
return order_status in {"shipped", "delivered", "completed", "settled"}
return order_status in {"delivered", "completed", "settled"}
arrears_service = ArrearsService()