update
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 10m49s

This commit is contained in:
2026-09-03 09:28:28 +08:00
parent dbfeeee253
commit 370fd3e67f
150 changed files with 64402 additions and 247 deletions

View File

@@ -25,7 +25,7 @@
from __future__ import annotations
import csv
from dataclasses import dataclass
from dataclasses import dataclass, replace
from datetime import datetime
from decimal import Decimal
from pathlib import Path
@@ -1158,6 +1158,44 @@ def write_step2(
return [w[2] for w in warnings]
def _apply_package_lifecycle_override(
iccid: str,
lifecycles: list[LegacyPackageLifecycle],
mapping: Mapping,
) -> tuple[list[LegacyPackageLifecycle], str]:
"""应用经确认的逐卡裁决;未覆盖资产保持原始分类。"""
override = mapping.lookup_package_lifecycle_override(iccid)
if override is None:
return lifecycles, ""
records = {item.life_id: item for item in lifecycles if item.source_table == "tbl_card_life"}
selected = {override.active_life_id, *override.pending_life_ids, *override.skipped_life_ids}
unknown = selected - set(records)
if unknown:
return lifecycles, f"套餐生命周期覆盖引用不属于该卡的 tbl_card_life 记录: {sorted(unknown)}"
migratable = {
item.life_id for item in records.values()
if item.migration_status in mapping.package_rules.migrate_statuses
}
if selected != migratable:
missing = sorted(migratable - selected)
extra = sorted(selected - migratable)
return lifecycles, f"套餐生命周期覆盖必须完整裁决原本可迁移记录: 未覆盖={missing}, 非可迁移={extra}"
status_by_id = {override.active_life_id: "active"}
status_by_id.update({life_id: "pending" for life_id in override.pending_life_ids})
status_by_id.update({life_id: "skipped" for life_id in override.skipped_life_ids})
return [
replace(
item,
migration_status=status_by_id[item.life_id],
skip_reason="套餐生命周期覆盖指定跳过" if status_by_id.get(item.life_id) == "skipped" else item.skip_reason,
) if item.life_id in status_by_id else item
for item in lifecycles
], ""
def _resolve_runtime_packages(
*,
cards: list[CardRow],
@@ -1184,6 +1222,14 @@ def _resolve_runtime_packages(
for card, asset_type, asset_identifier in source_cards:
lifecycles = package_lifecycles.get(card.iccid_full, [])
lifecycles, override_error = _apply_package_lifecycle_override(card.iccid_full, lifecycles, mapping)
if override_error:
errors.append(ErrorRow("mapping.yaml", 0, "iccid", card.iccid_full, "package_lifecycle_override_invalid", override_error))
for item in lifecycles:
resolution_rows.append(_package_resolution_row(
asset_type, asset_identifier, card.iccid_full, item, "", "", "blocked", override_error
))
continue
migratable = [
item for item in lifecycles
if item.migration_status in mapping.package_rules.migrate_statuses
@@ -1430,6 +1476,7 @@ def _write_package_usages(
" package_name,\n"
" package_price_config_status, package_is_gift,\n"
" data_reset_cycle,\n"
" expiry_base_snapshot, calendar_type_snapshot, duration_months_snapshot, duration_days_snapshot,\n"
" creator, updater, created_at, updated_at\n"
")\n"
f"SELECT o.id, o.order_no, p.id, {_sql_str(usage_type)},\n"
@@ -1443,6 +1490,9 @@ def _write_package_usages(
" p.package_name,\n"
" p.price_config_status, p.is_gift,\n"
" p.data_reset_cycle,\n"
" p.expiry_base, p.calendar_type,\n"
" CASE WHEN p.calendar_type = 'natural_month' THEN p.duration_months ELSE 0 END,\n"
" CASE WHEN p.calendar_type = 'by_day' THEN p.duration_days ELSE 0 END,\n"
f" {user_id}, {user_id}, NOW(), NOW()\n"
"FROM tb_order o\n"
f"JOIN tb_package p ON p.id = {pkg.target_package_id} AND p.package_type = 'formal' AND p.deleted_at IS NULL\n"