- Added `ThresholdRepository` for managing customer loss threshold configurations and notifications. - Introduced `threshold_service` to handle loss threshold alerts based on customer portfolio performance. - Enhanced `customer_prompts` to include new intent for querying product net values. - Updated `customer_service` to integrate new threshold alert functionality into existing workflows. - Implemented `sanitize_postprocess` for improved compliance handling in customer interactions. - Enhanced course documentation to reflect updates in advisor training modules and interactive elements. This update significantly improves the customer experience by providing proactive loss threshold notifications and enhancing the overall service framework.
60 lines
1.8 KiB
Python
60 lines
1.8 KiB
Python
"""C-04 亏损阈值提醒服务单测。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from decimal import Decimal
|
|
|
|
import pytest
|
|
|
|
from app.service import threshold_service as ts
|
|
|
|
|
|
def test_parse_loss_threshold_pct():
|
|
assert ts.parse_loss_threshold_pct("亏10%就提醒我") == Decimal("10")
|
|
assert ts.parse_loss_threshold_pct("亏损 12.5% 通知我") == Decimal("12.5")
|
|
assert ts.parse_loss_threshold_pct("没有数字") is None
|
|
|
|
|
|
def test_portfolio_pnl_pct_weighted():
|
|
rows = [
|
|
{"market_value": 60000, "pnl_pct": -12.0},
|
|
{"market_value": 40000, "pnl_pct": -8.0},
|
|
]
|
|
pnl = ts.portfolio_pnl_pct(rows)
|
|
assert pnl is not None
|
|
assert round(pnl, 2) == -10.4
|
|
|
|
|
|
def test_build_threshold_alert_when_breached(monkeypatch):
|
|
logs: list[dict] = []
|
|
|
|
class FakeRepo:
|
|
def list_enabled(self, cid):
|
|
return [{
|
|
"id": 7,
|
|
"scope_type": "portfolio",
|
|
"loss_threshold_pct": Decimal("10"),
|
|
}]
|
|
|
|
def insert_notify_log(self, **kwargs):
|
|
logs.append(kwargs)
|
|
|
|
monkeypatch.setattr(ts, "ThresholdRepository", FakeRepo)
|
|
holdings = [{"market_value": 100000, "pnl_pct": -15.0}]
|
|
alert = ts.build_threshold_alert("CUST-1", holdings, trace_id="t1")
|
|
assert alert and "阈值提醒" in alert
|
|
assert logs and logs[0]["customer_id"] == "CUST-1"
|
|
|
|
|
|
def test_build_threshold_alert_skips_when_within_threshold(monkeypatch):
|
|
class FakeRepo:
|
|
def list_enabled(self, cid):
|
|
return [{"id": 1, "scope_type": "portfolio", "loss_threshold_pct": Decimal("20")}]
|
|
|
|
def insert_notify_log(self, **kwargs):
|
|
raise AssertionError("should not notify")
|
|
|
|
monkeypatch.setattr(ts, "ThresholdRepository", FakeRepo)
|
|
holdings = [{"market_value": 100000, "pnl_pct": -5.0}]
|
|
assert ts.build_threshold_alert("CUST-1", holdings) is None
|