a3a14b484a
改了什么:新增京东联盟订单查询客户端、cps_order 京东字段迁移、CPS 对账接口 platform=all/jd、数据大盘京东订单与佣金聚合。 为什么改:数据大盘需要展示京东 CPS 真实订单佣金,不再保持占位。 验证方式:python -m pytest tests\\test_admin_read.py::test_dashboard_overview tests\\test_cps_admin.py::test_jd_reconcile_updates_dashboard -q;本地真实拉取 2026-06-27 京东订单 3 行,页面显示京东有效 1 单/佣金 ¥0.13。 --------- Co-authored-by: lowmaster-chen <1119780489@qq.com> Reviewed-on: #90 Co-authored-by: chenshuobo <chenshuobo@wonderable.ai> Co-committed-by: chenshuobo <chenshuobo@wonderable.ai>
82 lines
4.5 KiB
Python
82 lines
4.5 KiB
Python
"""CPS 对账订单(cps_order)。
|
|
|
|
从联盟 API 按时间窗拉回、按平台落库的 CPS 订单明细。字段最初对齐美团 query_order,
|
|
后续兼容京东订单报表:
|
|
实测返回:
|
|
- payPrice / profit 是「元」字符串 → 入库统一转「分」(与全站口径一致)
|
|
- payTime / updateTime 是秒级时间戳 → 入库转 tz-aware datetime
|
|
- status: 2付款 3完成 4取消 5风控 6结算(取消/风控不计佣金)
|
|
order_id 全局唯一,reconcile 按它 upsert(订单状态会变,重复拉则更新)。京东订单用
|
|
`jd:<row_id>` 前缀避免与美团订单号碰撞。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import JSON, DateTime, Integer, String, func
|
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.db.base import Base
|
|
|
|
|
|
class CpsOrder(Base):
|
|
__tablename__ = "cps_order"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
|
|
# 平台:meituan / jd。历史数据迁移默认 meituan。
|
|
platform: Mapped[str] = mapped_column(String(20), default="meituan", index=True, nullable=False)
|
|
# 平台订单号/行号包装后的全局唯一键,upsert 幂等。
|
|
order_id: Mapped[str] = mapped_column(String(64), unique=True, index=True, nullable=False)
|
|
# 平台原始订单号/行号。京东一笔订单多 SKU 时可按行号区分。
|
|
external_order_id: Mapped[str | None] = mapped_column(String(128), index=True, nullable=True)
|
|
external_row_id: Mapped[str | None] = mapped_column(String(128), index=True, nullable=True)
|
|
# 渠道追踪位 = 群 sid(历史无 sid 订单为空)。按它归群聚合。
|
|
sid: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
|
|
act_id: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True)
|
|
biz_line: Mapped[int | None] = mapped_column(Integer, nullable=True) # 1=外卖
|
|
trade_type: Mapped[int | None] = mapped_column(Integer, nullable=True) # 1=cps 2=cpa
|
|
|
|
pay_price_cents: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
commission_cents: Mapped[int | None] = mapped_column(Integer, nullable=True) # 预估佣金(profit)
|
|
commission_rate: Mapped[str | None] = mapped_column(String(16), nullable=True) # "300"=3% "10"=0.1%
|
|
refund_price_cents: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
refund_profit_cents: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
# 通用佣金拆分。美团只有预估 profit;京东有预估/实际佣金。
|
|
estimated_commission_cents: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
actual_commission_cents: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
|
|
# 美团订单状态: 2付款 3完成 4取消 5风控 6结算
|
|
mt_status: Mapped[str | None] = mapped_column(String(8), index=True, nullable=True)
|
|
# 京东订单有效码(validCode),用于判断是否有效/已完成。
|
|
jd_valid_code: Mapped[str | None] = mapped_column(String(16), index=True, nullable=True)
|
|
invalid_reason: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
product_name: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
|
settle_month: Mapped[str | None] = mapped_column(String(16), nullable=True)
|
|
site_id: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
position_id: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
pid: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
sub_union_id: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
|
|
pay_time: Mapped[datetime | None] = mapped_column(
|
|
DateTime(timezone=True), index=True, nullable=True
|
|
)
|
|
mt_update_time: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
raw: Mapped[dict] = mapped_column(
|
|
JSON().with_variant(JSONB(), "postgresql"), nullable=False, default=dict
|
|
)
|
|
first_seen: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), nullable=False
|
|
)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False
|
|
)
|
|
|
|
def __repr__(self) -> str: # pragma: no cover
|
|
return (
|
|
f"<CpsOrder id={self.id} order_id={self.order_id!r} "
|
|
f"platform={self.platform!r} sid={self.sid!r} "
|
|
f"status={self.mt_status or self.jd_valid_code} profit_cents={self.commission_cents}>"
|
|
)
|