修复:领券单券成功率按任务独立统计
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
"""生成 admin「领券记录」本地联调数据。
|
||||
|
||||
用法:
|
||||
python scripts/seed_coupon_session_mock.py
|
||||
|
||||
脚本只清理 ``mock-coupon-repeat-*`` 前缀的数据并重新生成。打开后台「领券记录」,
|
||||
日期选今天;分别切换 prod/dev,可验证同一设备同一天多次领券仍各自显示正确分数。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from sqlalchemy import delete, select
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from app.db.session import SessionLocal, engine # noqa: E402
|
||||
from app.models.coupon_state import ( # noqa: E402
|
||||
CouponClaimEvent,
|
||||
CouponClaimRecord,
|
||||
CouponSession,
|
||||
)
|
||||
from app.models.user import User # noqa: E402
|
||||
from app.repositories.coupon_state import record_claims, today_cn # noqa: E402
|
||||
|
||||
PREFIX = "mock-coupon-repeat-"
|
||||
CN_TZ = ZoneInfo("Asia/Shanghai")
|
||||
DEVICE_REPEAT = f"{PREFIX}device"
|
||||
DEVICE_CONTROL = f"{PREFIX}control-device"
|
||||
PHONE = "19900009001"
|
||||
USERNAME = "80000009001"
|
||||
PLATFORM_ELAPSED = {
|
||||
"meituan-waimai": 46_800,
|
||||
"taobao-shanguang": 19_500,
|
||||
"jd-waimai": 24_000,
|
||||
}
|
||||
|
||||
FIRST_RESULTS = [
|
||||
{"coupon_id": "mt_mock_1", "name": "美团模拟券1", "vendor": "meituan", "status": "success"},
|
||||
{"coupon_id": "mt_mock_2", "name": "美团模拟券2", "vendor": "meituan", "status": "success"},
|
||||
{"coupon_id": "mt_mock_3", "name": "美团模拟券3", "vendor": "meituan", "status": "success"},
|
||||
{"coupon_id": "mt_mock_4", "name": "美团模拟券4", "vendor": "meituan", "status": "failed", "reason": "模拟失败"},
|
||||
{"coupon_id": "tb_mock_1", "name": "淘宝模拟券1", "vendor": "taobao", "status": "success"},
|
||||
{"coupon_id": "tb_mock_2", "name": "淘宝模拟券2", "vendor": "taobao", "status": "success"},
|
||||
{"coupon_id": "tb_mock_3", "name": "淘宝模拟券3", "vendor": "taobao", "status": "success"},
|
||||
{"coupon_id": "jd_mock_1", "name": "京东模拟券", "vendor": "jingdong", "status": "success"},
|
||||
]
|
||||
|
||||
SECOND_RESULTS = [
|
||||
{"coupon_id": "mt_mock_1", "name": "美团模拟券1", "vendor": "meituan", "status": "skipped", "reason": "模拟跳过,不计分母"},
|
||||
{"coupon_id": "mt_mock_2", "name": "美团模拟券2", "vendor": "meituan", "status": "already_claimed"},
|
||||
{"coupon_id": "mt_mock_3", "name": "美团模拟券3", "vendor": "meituan", "status": "success"},
|
||||
{"coupon_id": "mt_mock_4", "name": "美团模拟券4", "vendor": "meituan", "status": "success"},
|
||||
{"coupon_id": "tb_mock_1", "name": "淘宝模拟券1", "vendor": "taobao", "status": "success"},
|
||||
{"coupon_id": "tb_mock_2", "name": "淘宝模拟券2", "vendor": "taobao", "status": "success"},
|
||||
{"coupon_id": "tb_mock_3", "name": "淘宝模拟券3", "vendor": "taobao", "status": "already_claimed"},
|
||||
{"coupon_id": "jd_mock_1", "name": "京东模拟券", "vendor": "jingdong", "status": "success"},
|
||||
]
|
||||
|
||||
|
||||
def _started_at(hour: int, minute: int) -> datetime:
|
||||
local = datetime.combine(today_cn(), datetime.min.time()).replace(
|
||||
hour=hour, minute=minute, tzinfo=CN_TZ
|
||||
)
|
||||
return local.astimezone(UTC)
|
||||
|
||||
|
||||
def _session(
|
||||
*,
|
||||
trace_id: str,
|
||||
device_id: str,
|
||||
user_id: int,
|
||||
app_env: str,
|
||||
hour: int,
|
||||
minute: int,
|
||||
status: str = "completed",
|
||||
elapsed_ms: int | None = 91_900,
|
||||
platform_elapsed: dict[str, int] | None = None,
|
||||
) -> CouponSession:
|
||||
started_at = _started_at(hour, minute)
|
||||
return CouponSession(
|
||||
trace_id=trace_id,
|
||||
device_id=device_id,
|
||||
user_id=user_id,
|
||||
status=status,
|
||||
app_env=app_env,
|
||||
platforms=[],
|
||||
origin_package=None,
|
||||
device_model="Mock Phone",
|
||||
rom="MockOS 1",
|
||||
started_at=started_at,
|
||||
started_date=today_cn(),
|
||||
finished_at=started_at if status != "started" else None,
|
||||
elapsed_ms=elapsed_ms,
|
||||
platform_elapsed=platform_elapsed,
|
||||
platform_success=(
|
||||
["meituan-waimai", "taobao-shanguang", "jd-waimai"]
|
||||
if status == "completed" else None
|
||||
),
|
||||
claimed_count=7 if status == "completed" else 0,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# 本地旧库 Alembic 版本链可能未同步;仅为联调补建新事件表,正式环境仍走 migration。
|
||||
CouponClaimEvent.__table__.create(bind=engine, checkfirst=True)
|
||||
with SessionLocal() as db:
|
||||
db.execute(delete(CouponClaimEvent).where(
|
||||
CouponClaimEvent.trace_id.startswith(PREFIX)
|
||||
))
|
||||
db.execute(delete(CouponClaimRecord).where(
|
||||
CouponClaimRecord.device_id.startswith(PREFIX)
|
||||
))
|
||||
db.execute(delete(CouponSession).where(
|
||||
CouponSession.trace_id.startswith(PREFIX)
|
||||
))
|
||||
user = db.execute(select(User).where(User.phone == PHONE)).scalar_one_or_none()
|
||||
if user is None:
|
||||
user = User(
|
||||
phone=PHONE,
|
||||
username=USERNAME,
|
||||
register_channel="sms",
|
||||
nickname="领券重复测试",
|
||||
)
|
||||
db.add(user)
|
||||
db.flush()
|
||||
|
||||
first_trace = f"{PREFIX}dev-first"
|
||||
second_trace = f"{PREFIX}prod-second"
|
||||
abandoned_trace = f"{PREFIX}prod-abandoned"
|
||||
control_trace = f"{PREFIX}prod-control"
|
||||
db.add_all([
|
||||
_session(
|
||||
trace_id=first_trace,
|
||||
device_id=DEVICE_REPEAT,
|
||||
user_id=user.id,
|
||||
app_env="dev",
|
||||
hour=10,
|
||||
minute=0,
|
||||
platform_elapsed=PLATFORM_ELAPSED,
|
||||
),
|
||||
_session(
|
||||
trace_id=second_trace,
|
||||
device_id=DEVICE_REPEAT,
|
||||
user_id=user.id,
|
||||
app_env="prod",
|
||||
hour=15,
|
||||
minute=0,
|
||||
platform_elapsed=PLATFORM_ELAPSED,
|
||||
),
|
||||
_session(
|
||||
trace_id=abandoned_trace,
|
||||
device_id=DEVICE_REPEAT,
|
||||
user_id=user.id,
|
||||
app_env="prod",
|
||||
hour=16,
|
||||
minute=0,
|
||||
status="abandoned",
|
||||
elapsed_ms=21_500,
|
||||
platform_elapsed={"meituan-waimai": 20_500},
|
||||
),
|
||||
_session(
|
||||
trace_id=control_trace,
|
||||
device_id=DEVICE_CONTROL,
|
||||
user_id=user.id,
|
||||
app_env="prod",
|
||||
hour=17,
|
||||
minute=0,
|
||||
platform_elapsed=PLATFORM_ELAPSED,
|
||||
),
|
||||
])
|
||||
db.commit()
|
||||
|
||||
record_claims(
|
||||
db, DEVICE_REPEAT, user.id, first_trace, FIRST_RESULTS, app_env="dev"
|
||||
)
|
||||
record_claims(
|
||||
db, DEVICE_REPEAT, user.id, second_trace, SECOND_RESULTS, app_env="prod"
|
||||
)
|
||||
record_claims(
|
||||
db, DEVICE_CONTROL, user.id, control_trace, FIRST_RESULTS, app_env="prod"
|
||||
)
|
||||
|
||||
print(f"已生成 {today_cn()} 的领券 mock 数据。")
|
||||
print("筛选用户 19900009001。")
|
||||
print("prod 应有:7/7(100.0%)、-、7/8(87.5%)三条。")
|
||||
print("dev 应有:7/8(87.5%)一条。")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user