288766443a
从最新 origin/main 重拉的干净分支,只含本人记账改动,不含 marco 的归因订单(order_record)——后者是另一条未合并分支 feat/user-order-records 的功能,此前被误用 git add -A 和记账混进了 feat/savings-accounting-m1。本分支不带它:savings_record 升级为唯一真相表(新增原价/比价价/支付渠道/源平台/幂等键等列,迁移 savings_report_fields 直接挂 f01db5d77dac、不经 order_record_table);/order/report 改写 savings_record(source='compare'),省额=源平台原价−实付;展示 /api/v1/savings/* 真实优先 demo 兜底。无 order_record 的 model/repo/迁移/路由。alembic 单一 head + pytest 54 passed。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: xianze <ze@192.168.0.138> Reviewed-on: #10 Co-authored-by: zhangxianze <zhangxianze@wonderable.ai> Co-committed-by: zhangxianze <zhangxianze@wonderable.ai>
106 lines
4.1 KiB
Python
106 lines
4.1 KiB
Python
"""记账测试:比价后下单上报 → 写 savings_record(source='compare')。
|
||
|
||
覆盖:上报落库 + 门店/菜品/原价随之入库、(user,client_event_id) 幂等、
|
||
真实(compare)记录优先于 demo seeder、省额 = 源平台原价 − 实付。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
|
||
def _login(client, phone: str) -> str:
|
||
client.post("/api/v1/auth/sms/send", json={"phone": phone})
|
||
r = client.post("/api/v1/auth/sms/login", json={"phone": phone, "code": "123456"})
|
||
assert r.status_code == 200, r.text
|
||
return r.json()["access_token"]
|
||
|
||
|
||
def _auth(token: str) -> dict[str, str]:
|
||
return {"Authorization": f"Bearer {token}"}
|
||
|
||
|
||
def _report_body(**over) -> dict:
|
||
body = {
|
||
"client_event_id": "evt-1",
|
||
"platform": "淘宝闪购",
|
||
"platform_package": "com.taobao.taobao",
|
||
"pay_channel": "alipay",
|
||
"compared_price_cents": 3300,
|
||
"paid_amount_cents": 3300,
|
||
"device_id": "device_test",
|
||
"shop_name": "肯德基宅急送(天北路店)",
|
||
"dishes": ["史迪奇玩具套餐 x1"],
|
||
"original_price_cents": 3680,
|
||
"source_platform_name": "美团",
|
||
"source_deeplink": "https://example.com/reorder",
|
||
}
|
||
body.update(over)
|
||
return body
|
||
|
||
|
||
def test_order_report_creates_real_savings(client) -> None:
|
||
"""上报一笔 → savings 统计/明细只反映这笔真实数据,含门店/菜品/原价。"""
|
||
token = _login(client, "13800002001")
|
||
r = client.post("/api/v1/order/report", json=_report_body(), headers=_auth(token))
|
||
assert r.status_code == 200, r.text
|
||
out = r.json()
|
||
assert out["duplicated"] is False
|
||
assert out["paid_amount_cents"] == 3300
|
||
assert out["platform"] == "淘宝闪购"
|
||
|
||
# summary:真实优先,只算这一笔(demo 不再混入)
|
||
s = client.get("/api/v1/savings/summary", headers=_auth(token)).json()
|
||
assert s["order_count"] == 1
|
||
assert s["total_saved_cents"] == 380 # 3680 − 3300
|
||
assert s["avg_saved_cents"] == 380
|
||
|
||
# records:门店/菜品/原价/支付渠道/源平台都在
|
||
page = client.get("/api/v1/savings/records", headers=_auth(token)).json()
|
||
assert len(page["items"]) == 1
|
||
it = page["items"][0]
|
||
assert it["shop_name"] == "肯德基宅急送(天北路店)"
|
||
assert it["dishes"] == ["史迪奇玩具套餐 x1"]
|
||
assert it["order_amount_cents"] == 3300
|
||
assert it["saved_amount_cents"] == 380
|
||
assert it["original_price_cents"] == 3680
|
||
assert it["platform"] == "淘宝闪购"
|
||
assert it["pay_channel"] == "alipay"
|
||
assert it["source_platform_name"] == "美团"
|
||
|
||
|
||
def test_order_report_idempotent(client) -> None:
|
||
"""同 (user, client_event_id) 重复上报:第二次 duplicated=True,不新增。"""
|
||
token = _login(client, "13800002002")
|
||
body = _report_body(client_event_id="evt-dup")
|
||
r1 = client.post("/api/v1/order/report", json=body, headers=_auth(token))
|
||
assert r1.json()["duplicated"] is False
|
||
r2 = client.post("/api/v1/order/report", json=body, headers=_auth(token))
|
||
assert r2.json()["duplicated"] is True
|
||
s = client.get("/api/v1/savings/summary", headers=_auth(token)).json()
|
||
assert s["order_count"] == 1
|
||
|
||
|
||
def test_real_overrides_demo_seed(client) -> None:
|
||
"""先触发 demo seeder(多笔),再上报一笔真实 → 统计切换为只算真实那笔。"""
|
||
token = _login(client, "13800002003")
|
||
demo = client.get("/api/v1/savings/summary", headers=_auth(token)).json()
|
||
assert demo["order_count"] > 1 # demo 是多笔
|
||
|
||
client.post(
|
||
"/api/v1/order/report",
|
||
json=_report_body(
|
||
client_event_id="evt-real", original_price_cents=5000, paid_amount_cents=4200
|
||
),
|
||
headers=_auth(token),
|
||
)
|
||
s = client.get("/api/v1/savings/summary", headers=_auth(token)).json()
|
||
assert s["order_count"] == 1 # demo 被忽略
|
||
assert s["total_saved_cents"] == 800 # 5000 − 4200
|
||
|
||
page = client.get("/api/v1/savings/records", headers=_auth(token)).json()
|
||
assert len(page["items"]) == 1
|
||
assert page["items"][0]["saved_amount_cents"] == 800
|
||
|
||
|
||
def test_order_report_requires_auth(client) -> None:
|
||
r = client.post("/api/v1/order/report", json=_report_body())
|
||
assert r.status_code == 401
|