dingdanquanliucheng/backend/app/services/reminder_service.py

203 lines
8.4 KiB
Python

from datetime import datetime, timedelta
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.config_repository import ConfigRepository
from backend.app.repositories.reminder_repository import ReminderRepository
class ReminderService:
def __init__(self) -> None:
self.repository = ReminderRepository()
self.config_repository = ConfigRepository()
def list_reminders(self, session: Session | None = None, filters: dict | None = None) -> dict:
filters = filters or {}
if session is not None:
try:
reminders = self.repository.list_reminders(session, filters)
page_no = filters.get("page_no", 1)
page_size = filters.get("page_size", 20)
start = max(page_no - 1, 0) * page_size
page_list = reminders[start : start + page_size]
return {
"total": len(reminders),
"page_no": page_no,
"page_size": page_size,
"list": [self._map_reminder(item) for item in page_list],
}
except SQLAlchemyError:
pass
return {
"total": 1,
"page_no": 1,
"page_size": 20,
"list": [
{
"reminder_id": 6001,
"title": "订单待审批",
"type": "order_approve",
"biz_type": "sales_order",
"biz_id": 9001,
"receiver_user_id": 1,
"status": "pending",
"sent_at": "2026-05-14 11:00:00",
"created_at": "2026-05-14 11:00:00",
}
],
}
def read_reminder(self, reminder_id: int, session: Session | None = None) -> dict:
if session is not None:
try:
reminder = self.repository.get_reminder(session, reminder_id)
if reminder is None:
raise AppException(code=ErrorCode.NOT_FOUND, message="提醒不存在", status_code=404)
reminder.status = "read"
session.add(reminder)
session.commit()
return {"reminder_id": reminder.id, "status": reminder.status}
except AppException:
session.rollback()
raise
except SQLAlchemyError:
session.rollback()
return {"reminder_id": reminder_id, "status": "read"}
def check_arrears(self, session: Session | None = None) -> dict:
if session is not None:
try:
rows = self.repository.list_overdue_arrears(session)
created_count = 0
for arrears, customer, order in rows:
if arrears.due_date is None or arrears.due_date >= datetime.now().date():
continue
receiver_user_id = (customer.salesman_id if customer and customer.salesman_id else 0) or 0
if receiver_user_id <= 0:
continue
existed = self.repository.find_active_reminder(
session,
"arrears",
"customer_arrears",
arrears.id,
receiver_user_id,
)
if existed is not None:
continue
title = f"客户欠款逾期提醒 - {customer.customer_name if customer else '未知客户'}"
content = (
f"客户存在逾期欠款,欠款金额 {float(arrears.arrears_amount or 0):.2f} 元,"
f"订单编号 {order.order_no if order else '-'},请及时跟进。"
)
self.repository.create_reminder(
session,
{
"reminder_type": "arrears",
"biz_type": "customer_arrears",
"biz_id": arrears.id,
"receiver_user_id": receiver_user_id,
"reminder_title": title,
"reminder_content": content,
"status": "pending",
"sent_at": datetime.now(),
},
)
arrears.reminded_at = datetime.now()
arrears.status = "overdue"
session.add(arrears)
created_count += 1
session.commit()
return {"checked": True, "created_count": created_count}
except AppException:
session.rollback()
raise
except SQLAlchemyError:
session.rollback()
return {"checked": True, "created_count": 0}
def check_inactive_customers(self, session: Session | None = None) -> dict:
if session is not None:
try:
inactive_days = int(self._get_config_value(session, "inactive_customer_days", "90"))
amount_threshold = float(self._get_config_value(session, "inactive_customer_amount_threshold", "1000"))
inactive_before = datetime.now() - timedelta(days=inactive_days)
rows = self.repository.list_inactive_customers(session, inactive_before)
created_count = 0
for customer, latest_order in rows:
if float(customer.credit_limit or 0) < amount_threshold:
continue
receiver_user_id = (customer.salesman_id or 0)
if receiver_user_id <= 0:
continue
existed = self.repository.find_active_reminder(
session,
"inactive_customer",
"customer",
customer.id,
receiver_user_id,
)
if existed is not None:
continue
last_order_time = (
latest_order.created_at.strftime("%Y-%m-%d %H:%M:%S")
if latest_order and latest_order.created_at
else "暂无订单"
)
self.repository.create_reminder(
session,
{
"reminder_type": "inactive_customer",
"biz_type": "customer",
"biz_id": customer.id,
"receiver_user_id": receiver_user_id,
"reminder_title": f"沉默客户提醒 - {customer.customer_name}",
"reminder_content": f"客户超过 {inactive_days} 天未下单,最近订单时间:{last_order_time}",
"status": "pending",
"sent_at": datetime.now(),
},
)
created_count += 1
session.commit()
return {"checked": True, "created_count": created_count}
except AppException:
session.rollback()
raise
except SQLAlchemyError:
session.rollback()
return {"checked": True, "created_count": 0}
def _get_config_value(self, session: Session, config_key: str, default: str) -> str:
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 _map_reminder(self, reminder) -> dict:
return {
"reminder_id": reminder.id,
"title": reminder.reminder_title,
"type": reminder.reminder_type,
"biz_type": reminder.biz_type,
"biz_id": reminder.biz_id,
"receiver_user_id": reminder.receiver_user_id,
"status": reminder.status,
"sent_at": reminder.sent_at.strftime("%Y-%m-%d %H:%M:%S") if reminder.sent_at else "",
"created_at": reminder.created_at.strftime("%Y-%m-%d %H:%M:%S") if reminder.created_at else "",
}
reminder_service = ReminderService()