# 业务方资料投放目录 业务方按以下规则把数据放到本目录,**重命名去掉 `.example` 后缀**,即可被脚本读取。 > 设计原则:**业务方只填"是哪张卡"、"在哪台设备上"和少量行级槽位覆盖**。 > 归属、批量默认槽位、套餐迁移范围由 `config/mapping.yaml` 决定;运营商、套餐、号码等历史事实从奇成只读查询。 `cards.csv` 必填。`devices.csv` 可选: - 只有卡迁移:只放 `cards.csv`,不要放 `devices.csv`。 - 卡 + 设备迁移:同时放 `cards.csv` 和 `devices.csv`,设备槽位引用的卡必须出现在 `cards.csv`。 ## cards.csv 卡资产清单 每张要迁移的卡一行。`iccid_19` / `iccid_20` 至少填一个。只有 20 位完整 ICCID 时可只填 `iccid_20`,脚本会自动派生前 19 位写入 `iccid_19` 字段。 只填 `iccid_20` 的卡,脚本查询奇成主表时只按 20 位精确匹配;只有同时显式填写 `iccid_19` 和 `iccid_20` 时,才允许 20 位未命中后退回 19 位查询。 | 列名 | 必填 | 说明 | |------|------|------| | `iccid_19` | 条件必填 | ICCID 前 19 位(必须 19 位;允许奇成历史字母位)。`iccid_20` 已填时可留空 | | `iccid_20` | 视运营商 | 完整 20 位 ICCID;CMCC/CUCC/CBN(20 位运营商) **必填**,CTCC(19 位)**必须留空**;非空时前 19 位必须等于 `iccid_19` | | `is_industry` | 否 | 是否行业卡,留空 = `false`(普通卡) | 具体运营商从奇成 `tbl_card.account_id/account_name` 扫描后写入 `mapping.yaml.carriers`; `tbl_card.category` 只是奇成大类,仅辅助人工填写 `target_carrier_type`。填完映射后会做一致性校验: - CTCC 卡填了 `iccid_20` → `errors.csv: carrier_length_conflict` 阻断 - 非 CTCC 卡 `iccid_20` 留空 → 同上阻断 - 同一完整 ICCID 在奇成 `tbl_card` 命中多条记录 → `errors.csv: legacy_duplicate` 阻断,请业务方人工确认 **店铺归属不在 CSV 里填**。独立卡由 `mapping.yaml.ownership_rules.standalone_card` 和 `overrides.cards` 决定。多店铺批次使用 `standalone_card.mode: legacy_agent`, 再按奇成 `agent_id` 填 `mapping.yaml.agents[].target_shop_code`。设备上的卡跟随设备归属, 不单独生成分配记录。 ## devices.csv 设备资产清单(可选) 每台要迁移的设备一行。没有设备时不要创建这个文件,脚本会把所有卡按独立卡处理。 | 列名 | 必填 | 说明 | |------|------|------| | `imei` | 否 | 设备 IMEI(非蜂窝设备可留空) | | `virtual_no` | 否 | 设备虚拟号/设备号。留空时用 `imei` 兜底;两者都为空则该行报错 | | `device_name` | 否 | 设备名称,写入 `tb_device.device_name` | | `device_model` | 否 | 设备型号,写入 `tb_device.device_model` | | `device_type` | 否 | 设备类型,写入 `tb_device.device_type` | | `max_sim_slots` | 否 | 最大卡槽数,范围 1-4。不填时按非空 `sim_iccid_*` 的最大槽位推导 | | `sim_iccid_1` ~ `sim_iccid_4` | 否 | 各插槽 ICCID,引用 `cards.csv` 的卡。可填 19 或 20 位;20 位精确匹配完整 ICCID,19 位仅在该前缀唯一对应一张卡时允许(至少要有 1 个) | | `current_slot` | 否 | 当前槽位,范围 1-4。写入 `tb_device_sim_binding.is_current`;空值用批量规则或覆盖项 | | `package_source_slot` | 否 | 设备旧套餐读取槽位,范围 1-4。新系统套餐仍归属设备;该字段只决定从奇成哪张绑定卡读取正式套餐生命周期 | **槽位优先级**: 1. `devices.csv` 行级 `current_slot` / `package_source_slot` 2. `mapping.yaml.overrides.devices` 中同设备号覆盖项 3. `mapping.yaml.ownership_rules.device` 批量默认槽位 若 `current_slot` 或 `package_source_slot` 对应的 `sim_iccid_N` 为空,脚本会写入 `errors.csv` 并阻断该设备相关 SQL。非 `package_source_slot` 的设备绑定卡只生成 基础卡和绑定 SQL,不会再读取它的奇成套餐,避免同一设备重复迁入多份主套餐。 **其他字段自动取默认值**:`manufacturer` 留空,`max_sim_slots` 按已填写卡槽推导, 设备归属由 `mapping.yaml.ownership_rules.device` 和 `overrides.devices` 决定。设备使用 `device.mode: legacy_agent` 时,脚本会按 `package_source_slot` 对应绑定卡的奇成 `agent_id` 查 `mapping.yaml.agents[].target_shop_code`。 ## 一致性约束 - `devices.csv` 任何 `sim_iccid_*` 引用的 ICCID **必须**在 `cards.csv` 中存在 - 同一 ICCID 不允许在 `cards.csv` 中重复出现 - 19 位前缀对应多张 20 位卡时,`devices.csv` 必须填写完整 20 位 ICCID - `imei` 和 `virtual_no` 至少要有一个(用作设备唯一标识) - 同一 ICCID 不能同时被多个设备/插槽引用