dingdanquanliucheng/backend/app/services/config_service.py

147 lines
6.3 KiB
Python
Raw Normal View History

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.services.audit_service import audit_service
from backend.app.services.bootstrap import DEFAULT_CONFIGS
2026-05-14 13:51:06 +08:00
class ConfigService:
def __init__(self) -> None:
self.repository = ConfigRepository()
self.default_configs = {item["config_key"]: item for item in DEFAULT_CONFIGS}
def get_config(self, config_key: str, session: Session | None = None) -> dict:
self._ensure_config_key(config_key)
if session is not None:
try:
config = self.repository.get_by_key(session, config_key)
if config is not None:
return self._map_config(config)
except SQLAlchemyError:
pass
default_item = self.default_configs.get(config_key)
if default_item is None:
raise AppException(code=ErrorCode.NOT_FOUND, message="配置不存在", status_code=404)
return {
"config_key": default_item["config_key"],
"config_value": default_item["config_value"],
"config_name": default_item["config_name"],
"remark": None,
"status": 1,
}
def update_config(self, config_key: str, payload: dict, session: Session | None = None) -> dict:
self._ensure_config_key(config_key)
self._ensure_config_value(config_key, payload["config_value"])
config_name = (payload.get("config_name") or self.default_configs.get(config_key, {}).get("config_name") or config_key).strip()
if session is not None:
try:
config = self.repository.get_by_key(session, config_key)
if config is None:
config = self.repository.create_config(
session,
{
"config_key": config_key,
"config_value": payload["config_value"].strip(),
"config_name": config_name,
"remark": payload.get("remark"),
"status": payload.get("status", 1),
},
)
audit_service.write_log(
session,
{
"operate_type": "config_create",
"biz_type": "system_config",
"biz_id": config.id,
"before_value": None,
"after_value": self._map_config(config),
"remark": f"新增配置 {config_key}",
},
)
else:
before_snapshot = self._map_config(config)
self.repository.update_config(
config,
{
"config_value": payload["config_value"].strip(),
"config_name": config_name,
"remark": payload.get("remark"),
"status": payload.get("status", 1),
},
)
audit_service.write_log(
session,
{
"operate_type": "config_update",
"biz_type": "system_config",
"biz_id": config.id,
"before_value": before_snapshot,
"after_value": self._map_config(config),
"remark": f"更新配置 {config_key}",
},
)
session.commit()
return {
"config_key": config.config_key,
"config_value": config.config_value,
"config_name": config.config_name,
"remark": config.remark,
"status": config.status,
"updated": True,
}
except AppException:
session.rollback()
raise
except SQLAlchemyError:
session.rollback()
return {
"config_key": config_key,
"config_value": payload["config_value"].strip(),
"config_name": config_name,
"remark": payload.get("remark"),
"status": payload.get("status", 1),
"updated": True,
}
def _ensure_config_key(self, config_key: str) -> None:
if not config_key.strip():
raise AppException(code=ErrorCode.PARAM_ERROR, message="配置键不能为空", status_code=400)
def _ensure_config_value(self, config_key: str, config_value: str) -> None:
value = config_value.strip()
if not value:
raise AppException(code=ErrorCode.PARAM_ERROR, message="配置值不能为空", status_code=400)
if config_key == "arrears_generate_mode" and value not in {"shipped", "delivered"}:
raise AppException(code=ErrorCode.PARAM_ERROR, message="欠款生成模式仅支持 shipped 或 delivered", status_code=400)
if config_key in {"logistics_timeout_hours", "inactive_customer_days"}:
if not value.isdigit() or int(value) <= 0:
raise AppException(code=ErrorCode.PARAM_ERROR, message="配置值必须为正整数", status_code=400)
if config_key == "inactive_customer_amount_threshold":
try:
amount = float(value)
except ValueError as exc:
raise AppException(code=ErrorCode.PARAM_ERROR, message="金额阈值格式错误", status_code=400) from exc
if amount < 0:
raise AppException(code=ErrorCode.PARAM_ERROR, message="金额阈值不能小于 0", status_code=400)
2026-05-14 13:51:06 +08:00
def _map_config(self, config) -> dict:
return {
"config_key": config.config_key,
"config_value": config.config_value,
"config_name": config.config_name,
"remark": config.remark,
"status": config.status,
}
2026-05-14 13:51:06 +08:00
config_service = ConfigService()