修复一些问题
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
step2_03_card_data_usage_update.sql - 卡累计流量 UPDATE
|
||||
step2_04_agent_wallet_init.sql - 代理钱包初始化(main + commission)
|
||||
step2_05_agent_wallet_transactions.sql - 代理钱包初始化流水
|
||||
step2_06_asset_series_update.sql - 资产套餐系列回填
|
||||
|
||||
设计原则:
|
||||
- 所有 INSERT 通过 SELECT 子查询动态取 id,不硬编码新库 id
|
||||
@@ -143,6 +144,29 @@ def _device_package_source_iccid(device: DeviceRow) -> str:
|
||||
)
|
||||
|
||||
|
||||
def _target_series_id_expr_for_iccid_19(
|
||||
iccid_19: str,
|
||||
card_metas: dict[str, LegacyCardMeta],
|
||||
mapping: Mapping,
|
||||
) -> str:
|
||||
"""按卡当前套餐映射生成新库套餐系列 SQL 表达式。
|
||||
|
||||
系列归属以新系统目标套餐为准,避免奇成套餐系列与新库系列二次映射不一致。
|
||||
"""
|
||||
if not iccid_19:
|
||||
return "NULL"
|
||||
meta = card_metas.get(iccid_19)
|
||||
if meta is None or not meta.current_meal_id:
|
||||
return "NULL"
|
||||
pkg_map = mapping.lookup_package(meta.current_meal_id)
|
||||
if pkg_map is None or not pkg_map.target_package_id:
|
||||
return "NULL"
|
||||
return (
|
||||
"(SELECT series_id FROM tb_package "
|
||||
f"WHERE id = {pkg_map.target_package_id} AND deleted_at IS NULL LIMIT 1)"
|
||||
)
|
||||
|
||||
|
||||
def _device_by_virtual_no(devices: list[DeviceRow]) -> dict[str, DeviceRow]:
|
||||
return {d.virtual_no: d for d in devices}
|
||||
|
||||
@@ -285,8 +309,7 @@ def _write_iot_cards(
|
||||
|
||||
card_category = "industry" if c.is_industry else "normal"
|
||||
shop_code = _resolve_card_shop_code(c, meta, mapping)
|
||||
series = mapping.lookup_series(_meal_to_series_id(meta, mapping))
|
||||
series_id_expr = str(series.target_series_id) if series and series.target_series_id else "NULL"
|
||||
series_id_expr = _target_series_id_expr_for_iccid_19(c.iccid_19, card_metas, mapping)
|
||||
|
||||
f.write(
|
||||
"INSERT INTO tb_iot_card (\n"
|
||||
@@ -316,19 +339,6 @@ def _write_iot_cards(
|
||||
)
|
||||
|
||||
|
||||
def _meal_to_series_id(meta: LegacyCardMeta, mapping: Mapping) -> str:
|
||||
"""由 meta 的 meal_id 经 mapping.packages 间接拿不到 series,所以这里直接靠
|
||||
mapping.series 用 legacy_series_id 反查就行。简化:返回空字符串(让上层走 series 映射)。
|
||||
|
||||
实际上 series_id 仅在套餐有 meal_series_id 时才有意义。考虑到 LegacyCardMeta 没存
|
||||
series_id,这里返回 '' — 让 series_id_expr 走 NULL 分支。后续若需要,scan_legacy
|
||||
可把 series_id 也下沉到 card_meta。
|
||||
"""
|
||||
_ = meta
|
||||
_ = mapping
|
||||
return ""
|
||||
|
||||
|
||||
def _write_devices(
|
||||
path: Path,
|
||||
devices: list[DeviceRow],
|
||||
@@ -349,13 +359,15 @@ def _write_devices(
|
||||
f.write(_file_header("step1_02 设备资产导入 (tb_device)"))
|
||||
for d in devices:
|
||||
shop_code = _resolve_device_shop_code(d, card_metas, mapping)
|
||||
source_iccid = _device_package_source_iccid(d)
|
||||
series_id_expr = _target_series_id_expr_for_iccid_19(source_iccid, card_metas, mapping)
|
||||
f.write(
|
||||
"INSERT INTO tb_device (\n"
|
||||
" virtual_no, max_sim_slots, imei,\n"
|
||||
" status, asset_status, generation, online_status,\n"
|
||||
" enable_polling, realname_policy,\n"
|
||||
" software_version, switch_mode,\n"
|
||||
" batch_no, shop_id,\n"
|
||||
" batch_no, shop_id, series_id,\n"
|
||||
" creator, updater, created_at, updated_at\n"
|
||||
") VALUES (\n"
|
||||
f" {_sql_str(d.virtual_no)}, {d.max_sim_slots}, "
|
||||
@@ -363,7 +375,7 @@ def _write_devices(
|
||||
" 1, 1, 1, 0,\n"
|
||||
" TRUE, 'after_order',\n"
|
||||
" '', '0',\n"
|
||||
f" {_sql_str(mapping.migration_batch_no)}, {_shop_id_sub(shop_code)},\n"
|
||||
f" {_sql_str(mapping.migration_batch_no)}, {_shop_id_sub(shop_code)}, {series_id_expr},\n"
|
||||
f" {user_id}, {user_id}, NOW(), NOW()\n"
|
||||
")\n"
|
||||
"ON CONFLICT (virtual_no) WHERE deleted_at IS NULL DO NOTHING;\n\n"
|
||||
@@ -607,6 +619,7 @@ def write_step2(
|
||||
output_dir / "step2_02_package_usages.sql", cards, resolved_packages, devices_by_virtual_no, usage_snapshots, user_id,
|
||||
)
|
||||
_write_card_data_usage(output_dir / "step2_03_card_data_usage_update.sql", cards, usage_snapshots)
|
||||
_write_asset_series_update(output_dir / "step2_06_asset_series_update.sql", cards, resolved_packages, devices_by_virtual_no)
|
||||
|
||||
# 代理钱包:只为 mapping.agents 中 target_shop_code 已填的项写入
|
||||
eligible_agents = [a for a in mapping.agents.values() if (a.target_shop_code or "").strip()]
|
||||
@@ -802,6 +815,50 @@ def _write_card_data_usage(path: Path, cards: list[CardRow], usage_snapshots: di
|
||||
)
|
||||
|
||||
|
||||
def _write_asset_series_update(
|
||||
path: Path,
|
||||
cards: list[CardRow],
|
||||
resolved_packages: dict[str, tuple[int, str]],
|
||||
devices_by_virtual_no: dict[str, DeviceRow],
|
||||
) -> None:
|
||||
"""按迁移套餐回填资产套餐系列。
|
||||
|
||||
step1 的 INSERT 遇到已存在资产会 DO NOTHING,所以这里用幂等 UPDATE 覆盖已导入资产的漏写场景。
|
||||
"""
|
||||
with path.open("w", encoding="utf-8") as f:
|
||||
f.write(_file_header("step2_06 资产套餐系列回填 (tb_iot_card / tb_device)"))
|
||||
for c in cards:
|
||||
if c.iccid_19 not in resolved_packages:
|
||||
continue
|
||||
target_pkg_id, _expire = resolved_packages[c.iccid_19]
|
||||
f.write(
|
||||
"UPDATE tb_iot_card c\n"
|
||||
"SET series_id = p.series_id,\n"
|
||||
" updated_at = NOW()\n"
|
||||
"FROM tb_package p\n"
|
||||
f"WHERE c.iccid = {_sql_str(c.iccid_full)} AND c.deleted_at IS NULL\n"
|
||||
f" AND p.id = {target_pkg_id} AND p.deleted_at IS NULL\n"
|
||||
" AND p.series_id IS NOT NULL\n"
|
||||
" AND c.series_id IS DISTINCT FROM p.series_id;\n\n"
|
||||
)
|
||||
|
||||
asset = _runtime_asset_for_card(c, devices_by_virtual_no)
|
||||
if asset is None:
|
||||
continue
|
||||
asset_type, asset_identifier = asset
|
||||
if asset_type == "device":
|
||||
f.write(
|
||||
"UPDATE tb_device d\n"
|
||||
"SET series_id = p.series_id,\n"
|
||||
" updated_at = NOW()\n"
|
||||
"FROM tb_package p\n"
|
||||
f"WHERE d.virtual_no = {_sql_str(asset_identifier)} AND d.deleted_at IS NULL\n"
|
||||
f" AND p.id = {target_pkg_id} AND p.deleted_at IS NULL\n"
|
||||
" AND p.series_id IS NOT NULL\n"
|
||||
" AND d.series_id IS DISTINCT FROM p.series_id;\n\n"
|
||||
)
|
||||
|
||||
|
||||
def _write_agent_wallet_init(
|
||||
path: Path,
|
||||
eligible_agents,
|
||||
|
||||
Reference in New Issue
Block a user