66527f6cdc
## 修改内容 - 新增按 `trace_id + coupon_id` 幂等的逐次单券事件表。 - 保留每日资产记录,同时独立保存每次领券事件,避免同设备同日重跑串场。 - 后台逐场成功率和单券明细改为读取逐次事件。 - 增加历史数据回填迁移、本地 mock 脚本和回归测试。 ## 验证结果 - 领券相关测试:22 项通过。 - 全新 SQLite 数据库执行 `alembic upgrade head`:通过。 - 全量测试:508 项通过;另外 8 项为现有无关失败。 --------- Co-authored-by: unknown <798648091@qq.com> Reviewed-on: #166 Co-authored-by: linkeyu <linkeyu@wonderable.ai> Co-committed-by: linkeyu <linkeyu@wonderable.ai>
55 lines
2.2 KiB
Python
55 lines
2.2 KiB
Python
"""逐次单券事件不能被同设备同日的每日去重记录串场。"""
|
|
|
|
from sqlalchemy import delete, select
|
|
|
|
from app.admin.repositories.coupon_data import _point_scores_by_trace, coupon_point_details
|
|
from app.db.session import SessionLocal
|
|
from app.models.coupon_state import CouponClaimEvent, CouponClaimRecord
|
|
from app.repositories.coupon_state import record_claims
|
|
|
|
|
|
def test_same_device_same_day_keeps_scores_for_each_trace() -> None:
|
|
db = SessionLocal()
|
|
device = "event-repeat-device"
|
|
first_trace = "event-repeat-first"
|
|
second_trace = "event-repeat-second"
|
|
first_results = [
|
|
{"coupon_id": "mt-repeat", "name": "美团测试券", "status": "success"},
|
|
{"coupon_id": "tb-repeat", "name": "淘宝测试券", "status": "failed"},
|
|
]
|
|
second_results = [
|
|
{"coupon_id": "mt-repeat", "name": "美团测试券", "status": "already_claimed"},
|
|
{"coupon_id": "tb-repeat", "name": "淘宝测试券", "status": "success"},
|
|
]
|
|
try:
|
|
record_claims(
|
|
db, device, None, first_trace, first_results, app_env="dev"
|
|
)
|
|
record_claims(
|
|
db, device, None, second_trace, second_results, app_env="prod"
|
|
)
|
|
|
|
assets = db.execute(
|
|
select(CouponClaimRecord).where(CouponClaimRecord.device_id == device)
|
|
).scalars().all()
|
|
assert len(assets) == 2
|
|
assert {row.trace_id for row in assets} == {first_trace}
|
|
|
|
events = db.execute(
|
|
select(CouponClaimEvent).where(CouponClaimEvent.device_id == device)
|
|
).scalars().all()
|
|
assert len(events) == 4
|
|
assert {row.trace_id for row in events} == {first_trace, second_trace}
|
|
|
|
scores = _point_scores_by_trace(db, [first_trace, second_trace])
|
|
assert scores[first_trace] == {"succeeded": 1, "tried": 2}
|
|
assert scores[second_trace] == {"succeeded": 2, "tried": 2}
|
|
assert [row["status"] for row in coupon_point_details(
|
|
db, trace_id=second_trace
|
|
)] == ["already_claimed", "success"]
|
|
finally:
|
|
db.execute(delete(CouponClaimEvent).where(CouponClaimEvent.device_id == device))
|
|
db.execute(delete(CouponClaimRecord).where(CouponClaimRecord.device_id == device))
|
|
db.commit()
|
|
db.close()
|