fix(weibo): 隔离换绑角色的微豆核账
This commit is contained in:
@@ -82,6 +82,14 @@ BALANCE_GROUP_STATUSES = (
|
||||
STATUS_WEIDOU_ERROR,
|
||||
)
|
||||
|
||||
AUTO_DONE_SOURCE_STATUSES = (
|
||||
STATUS_TO_RECHARGE,
|
||||
STATUS_RECHARGED,
|
||||
STATUS_SCRIPTED,
|
||||
STATUS_WEIDOU_ERROR,
|
||||
STATUS_FAILED,
|
||||
)
|
||||
|
||||
VERDICT_SUCCESS = "success"
|
||||
VERDICT_FAILED = "failed"
|
||||
VERDICT_UNKNOWN = "unknown"
|
||||
@@ -935,7 +943,8 @@ def check_balance_groups(
|
||||
if len(rows) > CHECK_BATCH_MAX:
|
||||
raise CollabError(f"一次最多核账 {CHECK_BATCH_MAX} 条", code="batch_too_large")
|
||||
threshold = max(0, min(int(threshold), 1_000_000))
|
||||
grouped: dict[int, list[WeiboExternalOrder]] = {}
|
||||
selected_keys: list[tuple[int, str]] = []
|
||||
grouped: dict[tuple[int, str], list[WeiboExternalOrder]] = {}
|
||||
failures: list[dict[str, Any]] = []
|
||||
skipped: list[dict[str, Any]] = []
|
||||
for order in rows:
|
||||
@@ -958,28 +967,49 @@ def check_balance_groups(
|
||||
}
|
||||
)
|
||||
continue
|
||||
grouped.setdefault(int(order.account_id), []).append(order)
|
||||
key = (
|
||||
int(order.account_id),
|
||||
_text(order.game_role_name, max_length=128),
|
||||
)
|
||||
if key not in grouped:
|
||||
selected_keys.append(key)
|
||||
grouped.setdefault(key, []).append(order)
|
||||
|
||||
selected_account_ids = list(dict.fromkeys(key[0] for key in selected_keys))
|
||||
keys_by_account: dict[int, list[tuple[int, str]]] = {}
|
||||
for key in selected_keys:
|
||||
keys_by_account.setdefault(key[0], []).append(key)
|
||||
|
||||
selected_account_ids = set(grouped)
|
||||
grouped = {}
|
||||
for account_id in selected_account_ids:
|
||||
grouped[account_id] = (
|
||||
if selected_account_ids:
|
||||
for row in (
|
||||
db.query(WeiboExternalOrder)
|
||||
.filter(
|
||||
WeiboExternalOrder.account_id == account_id,
|
||||
WeiboExternalOrder.account_id.in_(selected_account_ids),
|
||||
WeiboExternalOrder.status.in_(BALANCE_GROUP_STATUSES),
|
||||
WeiboExternalOrder.archived_at.is_(None),
|
||||
)
|
||||
.order_by(WeiboExternalOrder.id.asc())
|
||||
.all()
|
||||
)
|
||||
):
|
||||
if not row.account_id:
|
||||
continue
|
||||
key = (
|
||||
int(row.account_id),
|
||||
_text(row.game_role_name, max_length=128),
|
||||
)
|
||||
grouped.setdefault(key, []).append(row)
|
||||
|
||||
groups: list[dict[str, Any]] = []
|
||||
updated = 0
|
||||
for account_id, group_orders in grouped.items():
|
||||
for account_id in selected_account_ids:
|
||||
account_keys = keys_by_account.get(account_id, [])
|
||||
account_orders = [
|
||||
order for key in account_keys for order in grouped.get(key, [])
|
||||
]
|
||||
account = db.query(WeiboAccount).filter(WeiboAccount.id == account_id).first()
|
||||
if account is None:
|
||||
for order in group_orders:
|
||||
for order in account_orders:
|
||||
failures.append(
|
||||
{
|
||||
"id": order.id,
|
||||
@@ -989,7 +1019,7 @@ def check_balance_groups(
|
||||
)
|
||||
continue
|
||||
if not account.is_enabled:
|
||||
for order in group_orders:
|
||||
for order in account_orders:
|
||||
failures.append(
|
||||
{
|
||||
"id": order.id,
|
||||
@@ -1001,114 +1031,130 @@ def check_balance_groups(
|
||||
try:
|
||||
data = WeiboClient(account.cookie or "").list_mall(activity)
|
||||
except (WeiboError, ValueError) as exc:
|
||||
for order in group_orders:
|
||||
for order in account_orders:
|
||||
failures.append(
|
||||
{"id": order.id, "order_no": order.order_no, "message": str(exc)}
|
||||
)
|
||||
continue
|
||||
|
||||
balance = _to_int(data.get("weidou_balance"))
|
||||
required_total = sum(int(order.required_weidou or 0) for order in group_orders)
|
||||
surplus = balance - required_total if balance is not None else None
|
||||
if surplus is None:
|
||||
reason = "error"
|
||||
message = "未拿到微豆余额"
|
||||
target = None
|
||||
elif surplus < 0:
|
||||
reason = "shortage"
|
||||
message = (
|
||||
f"微豆不足:余额 {balance},订单合计 {required_total},还差 {-surplus}"
|
||||
)
|
||||
target = STATUS_WEIDOU_ERROR
|
||||
elif surplus > threshold:
|
||||
reason = "excess"
|
||||
message = (
|
||||
f"微豆超出阈值:余额 {balance},订单合计 {required_total},"
|
||||
f"多出 {surplus}(阈值 {threshold})"
|
||||
)
|
||||
target = STATUS_WEIDOU_ERROR
|
||||
else:
|
||||
reason = "ok"
|
||||
message = (
|
||||
f"核账通过:余额 {balance},订单合计 {required_total},结余 {surplus}"
|
||||
)
|
||||
target = STATUS_RECHARGED
|
||||
|
||||
if balance is not None:
|
||||
account.weidou_balance = balance
|
||||
now = _now()
|
||||
for order in group_orders:
|
||||
order.weidou_balance = balance
|
||||
order.weidou_required_total = required_total
|
||||
order.weidou_surplus = surplus
|
||||
order.weidou_threshold = threshold
|
||||
order.weidou_checked_at = now
|
||||
order.weidou_check_reason = reason
|
||||
order.weidou_check_message = message[:512]
|
||||
order.weidou_check_detail = {
|
||||
"account_id": account.id,
|
||||
"uid": account.uid,
|
||||
"balance": balance,
|
||||
"required_total": required_total,
|
||||
"surplus": surplus,
|
||||
"threshold": threshold,
|
||||
"order_ids": [item.id for item in group_orders],
|
||||
}
|
||||
if target is not None:
|
||||
set_status(
|
||||
for account_key in account_keys:
|
||||
game_role_name = account_key[1]
|
||||
group_orders = grouped.get(account_key, [])
|
||||
if not group_orders:
|
||||
continue
|
||||
required_total = sum(
|
||||
int(order.required_weidou or 0) for order in group_orders
|
||||
)
|
||||
surplus = balance - required_total if balance is not None else None
|
||||
if surplus is None:
|
||||
reason = "error"
|
||||
message = "未拿到微豆余额"
|
||||
target = None
|
||||
elif surplus < 0:
|
||||
reason = "shortage"
|
||||
message = (
|
||||
f"微豆不足:角色「{game_role_name or '未绑定'}」,余额 {balance},"
|
||||
f"订单合计 {required_total},还差 {-surplus}"
|
||||
)
|
||||
target = STATUS_WEIDOU_ERROR
|
||||
elif surplus > threshold:
|
||||
reason = "excess"
|
||||
message = (
|
||||
f"微豆超出阈值:角色「{game_role_name or '未绑定'}」,余额 {balance},"
|
||||
f"订单合计 {required_total},多出 {surplus}(阈值 {threshold})"
|
||||
)
|
||||
target = STATUS_WEIDOU_ERROR
|
||||
else:
|
||||
reason = "ok"
|
||||
message = (
|
||||
f"核账通过:角色「{game_role_name or '未绑定'}」,余额 {balance},"
|
||||
f"订单合计 {required_total},结余 {surplus}"
|
||||
)
|
||||
target = STATUS_RECHARGED
|
||||
|
||||
now = _now()
|
||||
for order in group_orders:
|
||||
order.weidou_balance = balance
|
||||
order.weidou_required_total = required_total
|
||||
order.weidou_surplus = surplus
|
||||
order.weidou_threshold = threshold
|
||||
order.weidou_checked_at = now
|
||||
order.weidou_check_reason = reason
|
||||
order.weidou_check_message = message[:512]
|
||||
order.weidou_check_detail = {
|
||||
"account_id": account.id,
|
||||
"uid": account.uid,
|
||||
"role": game_role_name,
|
||||
"balance": balance,
|
||||
"required_total": required_total,
|
||||
"surplus": surplus,
|
||||
"threshold": threshold,
|
||||
"order_ids": [item.id for item in group_orders],
|
||||
}
|
||||
if target is not None:
|
||||
set_status(
|
||||
db,
|
||||
current,
|
||||
order,
|
||||
target,
|
||||
reason=message,
|
||||
allow_check=True,
|
||||
commit=False,
|
||||
)
|
||||
order.recharged_at = now
|
||||
updated += 1
|
||||
_metric(
|
||||
db,
|
||||
current,
|
||||
order,
|
||||
target,
|
||||
reason=message,
|
||||
allow_check=True,
|
||||
commit=False,
|
||||
balance=balance,
|
||||
required_total=required_total,
|
||||
surplus=surplus,
|
||||
records_total=0,
|
||||
records_matched=0,
|
||||
verdict=VERDICT_UNKNOWN if target is None else "",
|
||||
message=message,
|
||||
source="balance_check",
|
||||
raw={
|
||||
"reason": reason,
|
||||
"role": game_role_name,
|
||||
"order_ids": [item.id for item in group_orders],
|
||||
},
|
||||
)
|
||||
order.recharged_at = now
|
||||
updated += 1
|
||||
_metric(
|
||||
db,
|
||||
current,
|
||||
order,
|
||||
balance=balance,
|
||||
required_total=required_total,
|
||||
surplus=surplus,
|
||||
records_total=0,
|
||||
records_matched=0,
|
||||
verdict=VERDICT_UNKNOWN if target is None else "",
|
||||
message=message,
|
||||
source="balance_check",
|
||||
raw={"reason": reason, "order_ids": [item.id for item in group_orders]},
|
||||
)
|
||||
_audit(
|
||||
db,
|
||||
current,
|
||||
order,
|
||||
"weibo:collab:balance_check",
|
||||
_audit(
|
||||
db,
|
||||
current,
|
||||
order,
|
||||
"weibo:collab:balance_check",
|
||||
{
|
||||
"account_id": account.id,
|
||||
"role": game_role_name,
|
||||
"balance": balance,
|
||||
"required_total": required_total,
|
||||
"surplus": surplus,
|
||||
"threshold": threshold,
|
||||
"reason": reason,
|
||||
},
|
||||
)
|
||||
groups.append(
|
||||
{
|
||||
"account_id": account.id,
|
||||
"uid": account.uid,
|
||||
"game_role_name": game_role_name,
|
||||
"status": target or "",
|
||||
"status_label": ORDER_STATUS_LABELS.get(target or "", ""),
|
||||
"balance": balance,
|
||||
"required_total": required_total,
|
||||
"surplus": surplus,
|
||||
"threshold": threshold,
|
||||
"reason": reason,
|
||||
},
|
||||
"message": message,
|
||||
"order_ids": [item.id for item in group_orders],
|
||||
}
|
||||
)
|
||||
groups.append(
|
||||
{
|
||||
"account_id": account.id,
|
||||
"uid": account.uid,
|
||||
"status": target or "",
|
||||
"status_label": ORDER_STATUS_LABELS.get(target or "", ""),
|
||||
"balance": balance,
|
||||
"required_total": required_total,
|
||||
"surplus": surplus,
|
||||
"threshold": threshold,
|
||||
"reason": reason,
|
||||
"message": message,
|
||||
"order_ids": [item.id for item in group_orders],
|
||||
}
|
||||
)
|
||||
db.commit()
|
||||
return {
|
||||
"total": len(rows),
|
||||
@@ -1231,7 +1277,7 @@ def check_exchange_records(
|
||||
order.exchange_record_snapshot = _json_safe(record)
|
||||
order.exchange_verdict = VERDICT_SUCCESS
|
||||
order.exchange_message = "兑换记录唯一命中"
|
||||
if order.status in (STATUS_RECHARGED, STATUS_SCRIPTED):
|
||||
if order.status in AUTO_DONE_SOURCE_STATUSES:
|
||||
set_status(
|
||||
db,
|
||||
current,
|
||||
|
||||
Reference in New Issue
Block a user