feat(douyu): 拆分鱼翅积分与兑换记录查询

This commit is contained in:
yml2213
2026-10-23 10:42:42 +08:00
parent 2c87deed78
commit 2de5d374df
5 changed files with 359 additions and 105 deletions
+88 -67
View File
@@ -1042,9 +1042,10 @@ def query_activity(
*,
client: Any | None = None,
source: str = "manual",
include_records: bool = True,
commit: bool = True,
) -> dict[str, Any]:
"""查询鱼翅、积分和当前账号兑换记录,落一条快照。"""
"""查询鱼翅、积分;``include_records`` 时同时查兑换记录并判定。"""
account = account_by_id(db, order.account_id) or account_by_username(
db, order.account_username
)
@@ -1067,24 +1068,25 @@ def query_activity(
gold = active_client.gold_account()
except Exception as exc: # noqa: BLE001
errors.append(f"鱼翅: {exc}")
try:
records = (
active_client.exchange_records(
manual_id=str(config.manual_id or ""), limit=100, offset=0
).get("records")
or []
)
except Exception as exc: # noqa: BLE001
errors.append(f"兑换记录: {exc}")
try:
orders = (
active_client.exchange_orders(
manual_id=str(config.manual_id or ""), page=1, page_size=10
).get("orders")
or []
)
except Exception as exc: # noqa: BLE001
errors.append(f"锁单: {exc}")
if include_records:
try:
records = (
active_client.exchange_records(
manual_id=str(config.manual_id or ""), limit=100, offset=0
).get("records")
or []
)
except Exception as exc: # noqa: BLE001
errors.append(f"兑换记录: {exc}")
try:
orders = (
active_client.exchange_orders(
manual_id=str(config.manual_id or ""), page=1, page_size=10
).get("orders")
or []
)
except Exception as exc: # noqa: BLE001
errors.append(f"锁单: {exc}")
manual_score = _to_int(elite.get("manual_score"))
fish = _to_int(gold.get("gold"))
@@ -1107,7 +1109,11 @@ def query_activity(
threshold = normalize_threshold(order.points_threshold)
order.points_threshold = threshold
if errors:
matched = 0
if not include_records:
verdict = VERDICT_UNKNOWN
message = ";".join(errors) if errors else "仅查询鱼翅与积分,未查询兑换记录"
elif errors:
verdict = VERDICT_UNKNOWN
message = ";".join(errors)
elif not order.gift_name:
@@ -1160,7 +1166,7 @@ def query_activity(
points_required_total=required_total,
points_surplus=surplus,
records_total=len(records),
records_matched=_match_gift(records, order.gift_name),
records_matched=matched,
verdict=verdict,
message=message,
source=_text(source, max_length=16) or "manual",
@@ -1183,6 +1189,7 @@ def query_activity(
action="douyu:collab:activity",
target=_status_audit_target(order),
detail={
"scope": "activity" if include_records else "balances",
"verdict": verdict,
"message": message,
"fish_fin_balance": fish,
@@ -1193,40 +1200,41 @@ def query_activity(
},
)
# 已上脚本的单,兑换记录命中/未命中是业务事实;其它状态只记快照。
if order.status == STATUS_SCRIPTED and verdict == VERDICT_SUCCESS:
set_status(
db,
current,
order,
status=STATUS_DONE,
reason=message,
expected_version=None,
commit=False,
)
elif order.status == STATUS_SCRIPTED and verdict == VERDICT_FAILED:
set_status(
db,
current,
order,
status=STATUS_FAILED,
reason=message,
expected_version=None,
commit=False,
)
elif order.status in (STATUS_RECHARGED, STATUS_SCRIPTED) and reason in (
"shortage",
"excess",
):
set_status(
db,
current,
order,
status=STATUS_POINTS_ERROR,
reason=points_message,
expected_version=None,
commit=False,
)
# 只有查兑换记录时才做业务判定;余额查询保持只读,不动状态。
if include_records:
if order.status == STATUS_SCRIPTED and verdict == VERDICT_SUCCESS:
set_status(
db,
current,
order,
status=STATUS_DONE,
reason=message,
expected_version=None,
commit=False,
)
elif order.status == STATUS_SCRIPTED and verdict == VERDICT_FAILED:
set_status(
db,
current,
order,
status=STATUS_FAILED,
reason=message,
expected_version=None,
commit=False,
)
elif order.status in (STATUS_RECHARGED, STATUS_SCRIPTED) and reason in (
"shortage",
"excess",
):
set_status(
db,
current,
order,
status=STATUS_POINTS_ERROR,
reason=points_message,
expected_version=None,
commit=False,
)
if commit:
db.commit()
@@ -1235,6 +1243,7 @@ def query_activity(
return {
"order": order,
"metric": metric,
"scope": "activity" if include_records else "balances",
"verdict": verdict,
"message": message,
"points_reason": reason,
@@ -1487,9 +1496,14 @@ def serialized_goods(db: Session) -> list[dict[str, Any]]:
def _metric_views(
db: Session, order_ids: list[int]
) -> dict[int, DouyuExternalOrderMetric]:
) -> tuple[dict[int, DouyuExternalOrderMetric], dict[int, DouyuExternalOrderMetric]]:
"""返回最近一条快照,以及最近一条带兑换判定的快照。
余额查询也会落快照,但它的 verdict 是 unknown;列表上的兑换结论应沿用
最近一次「查兑换记录」的结果,不能被余额刷新覆盖。
"""
if not order_ids:
return {}
return {}, {}
rows = (
db.query(DouyuExternalOrderMetric)
.filter(DouyuExternalOrderMetric.order_id.in_(order_ids))
@@ -1499,10 +1513,14 @@ def _metric_views(
)
.all()
)
result: dict[int, DouyuExternalOrderMetric] = {}
latest: dict[int, DouyuExternalOrderMetric] = {}
verdict_latest: dict[int, DouyuExternalOrderMetric] = {}
for row in rows:
result.setdefault(int(row.order_id), row)
return result
order_id = int(row.order_id)
latest.setdefault(order_id, row)
if not str(row.source or "").startswith("balance"):
verdict_latest.setdefault(order_id, row)
return latest, verdict_latest
def account_clusters(
@@ -1556,6 +1574,7 @@ def serialize_order(
accounts: Mapping[int, Account] | None = None,
cluster: Mapping[str, Any] | None = None,
metric: DouyuExternalOrderMetric | None = None,
verdict_metric: DouyuExternalOrderMetric | None = None,
) -> dict[str, Any]:
users = users or {}
accounts = accounts or {}
@@ -1630,16 +1649,16 @@ def serialize_order(
"account_cluster": dict(cluster) if cluster else None,
"last_metric_at": metric.created_at if metric else None,
"last_metric_message": metric.message if metric else "",
"last_verdict": metric.verdict if metric else "",
"last_verdict": verdict_metric.verdict if verdict_metric else "",
"last_verdict_label": {
VERDICT_SUCCESS: "兑换成功",
VERDICT_FAILED: "兑换失败",
VERDICT_UNKNOWN: "无法判定",
}.get(metric.verdict, "")
if metric
}.get(verdict_metric.verdict, "")
if verdict_metric
else "",
"last_records_total": metric.records_total if metric else 0,
"last_records_matched": metric.records_matched if metric else 0,
"last_records_total": verdict_metric.records_total if verdict_metric else 0,
"last_records_matched": verdict_metric.records_matched if verdict_metric else 0,
}
return payload
@@ -1761,7 +1780,7 @@ def list_orders(
db, {int(order.account_id) for order in orders if order.account_id}
)
clusters = account_clusters(db, orders)
metrics = _metric_views(db, [int(order.id) for order in orders])
metrics, verdict_metrics = _metric_views(db, [int(order.id) for order in orders])
items = [
serialize_order(
order,
@@ -1769,6 +1788,7 @@ def list_orders(
accounts=accounts,
cluster=clusters.get(int(order.account_id)) if order.account_id else None,
metric=metrics.get(int(order.id)),
verdict_metric=verdict_metrics.get(int(order.id)),
)
for order in orders
]
@@ -1802,13 +1822,14 @@ def serialize_one(db: Session, order: DouyuExternalOrder) -> dict[str, Any]:
db, {int(order.account_id)} if order.account_id else set()
)
clusters = account_clusters(db, [order])
metrics = _metric_views(db, [int(order.id)])
metrics, verdict_metrics = _metric_views(db, [int(order.id)])
return serialize_order(
order,
users=users,
accounts=accounts,
cluster=clusters.get(int(order.account_id)) if order.account_id else None,
metric=metrics.get(int(order.id)),
verdict_metric=verdict_metrics.get(int(order.id)),
)