跳到主要内容

完整产品生命周期指南

本指南提供了在 OmniCRM 中产品生命周期的端到端流程,从创建产品定义到服务配置、添加附加组件和取消配置。我们将涵盖定价策略、Ansible 集成,并在整个过程中提供实际案例。

概述:产品到服务的旅程

OmniCRM 中产品的生命周期遵循以下阶段:

  1. 产品定义 - 管理员创建包含定价和配置规则的产品模板
  2. 服务创建 - 客户订购产品,系统配置服务实例
  3. 服务生命周期 - 客户使用服务,添加附加组件/充值,修改服务
  4. 取消配置 - 服务被终止,资源被释放

理解定价:批发与零售

OmniCRM 中的每个产品和服务都有两个定价维度:批发零售

批发成本

批发成本代表交付服务的实际成本:

  • 基础设施和带宽成本
  • 许可费用
  • 设备成本
  • 运营费用

零售成本

零售成本是向客户收取的金额。

设置成本

批发和零售都有一次性配置费用的变体:

  • wholesale_setup_cost - 您的配置成本
  • retail_setup_cost - 向客户收取的激活费用

示例:

{
"retail_cost": 15.00,
"wholesale_cost": 5.00,
"retail_setup_cost": 0.00,
"wholesale_setup_cost": 1.00
}

阶段 1:创建产品定义

产品是定义要配置的内容及客户如何收费的模板。

创建移动 SIM 产品

让我们创建一个每月 20GB 数据的预付费移动 SIM 产品。

步骤 1:导航到产品管理

从管理员 UI,转到 产品创建产品

步骤 2:定义基本信息

{
"product_name": "Prepaid Mobile 20GB",
"product_slug": "prepaid-mobile-20gb",
"category": "standalone",
"service_type": "mobile",
"enabled": true,
"icon": "fa-solid fa-sim-card",
"comment": "预付费移动 SIM,包含 20GB 数据,无限通话和短信"
}

字段说明:

  • product_name - 客户可见的名称,在目录中显示
  • product_slug - 在 API 调用和链接中使用的 URL 安全标识符
  • category - “standalone” 意味着这创建了一个新服务(与附加组件/捆绑不同)
  • service_type - 将相关产品分组,用于附加组件过滤
  • enabled - 产品必须为 true 才能被订购
  • icon - 在 UI 中显示的 FontAwesome 图标
  • comment - 内部备注供员工参考

步骤 3:设置定价

{
"retail_cost": 15.00,
"wholesale_cost": 5.00,
"retail_setup_cost": 0.00,
"wholesale_setup_cost": 1.00,
"contract_days": 30
}

定价细分:

  • 每位客户的月收入:£15.00
  • 每月交付成本:£5.00
  • 每月利润率:£10.00(200% 加价,67% 利润)
  • 设置利润:-£1.00(补贴以吸引客户)
  • 合同期限:30 天(每月续订)

步骤 4:定义客户资格

{
"residential": true,
"business": false,
"customer_can_purchase": true,
"available_from": "2025-01-01T00:00:00Z",
"available_until": null
}
  • 住宅客户可以订购
  • 商业客户不能(不同的产品线)
  • 自助购买已启用
  • 从 2025 年 1 月 1 日起可用
  • 没有结束日期(持续优惠)

步骤 5:配置自动续订

{
"auto_renew": "prompt",
"allow_auto_renew": true
}
  • "prompt" - 在购买时询问客户是否希望自动续订
  • "true" - 自动续订,无需询问
  • "false" - 永不自动续订(仅手动充值)
  • allow_auto_renew: true - 客户可以稍后启用/禁用自动续订

步骤 6:指定库存要求

库存要求定义在配置此产品时必须���配哪些物理或虚拟资源。这是将您的产品目录与您的 库存管理系统 连接起来的关键步骤。

{
"inventory_items_list": "['SIM Card', 'Mobile Number']"
}

什么是库存项目?

库存项目是存储在 OmniCRM 库存系统中的可追踪资源。每个项目都有:

  • 类型 - 由库存模板定义(例如,“SIM 卡”、“手机号码”、“调制解调器”)
  • 唯一属性 - 序列号、MAC 地址、电话号码等
  • 状态 - 在库、已分配、退役等
  • 位置 - 物理或逻辑位置

库存要求如何工作:

inventory_items_list 是一个包含库存类型名称的 Python 列表(作为字符串)。每个名称必须完全匹配现有的 库存模板 名称。

示例库存要求:

# 移动 SIM 产品
inventory_items_list: "['SIM Card', 'Mobile Number']"

# 固定互联网服务
inventory_items_list: "['Modem Router', 'Static IP Address']"

# 数字服务(没有物理项目)
inventory_items_list: "[]"

# 固定无线与 CPE
inventory_items_list: "['Fixed Wireless CPE', 'IPv4 Address', 'IPv6 Prefix']"

库存选择器流程

当用户配置具有库存要求的产品时,系统强制执行强制选择流程:

1. 点击配置按钮

选择产品后,用户点击“配置”。系统检查 inventory_items_list,而不是立即配置。

2. 库存选择器模态框出现

如果需要库存,将出现一个模态对话框,每种库存类型都有一个单独的下拉菜单:

3. 过滤可用库存

每种库存类型的下拉菜单仅显示以下项目:

  • 正确类型 - 完全匹配库存模板名称
  • 可用状态 - item_state 为“新”或“在库”(而不是“已分配”或“损坏”)
  • 未分配 - service_idcustomer_id 为 NULL
  • 在指定位置有库存 - 可选择按仓库/商店位置过滤

示例下拉选项:

对于“SIM 卡”库存类型,下拉菜单可能显示:

每个选项显示:

  • 库存 ID 或参考编号
  • 主要标识符(itemtext1 - 例如,SIM 的 ICCID,电话的号码)
  • 当前地点(item_location

4. 选择是继续的必要条件

关键规则: 在选择所有必需的库存项目之前,配置无法继续。

  • “继续”按钮在所有下拉菜单都有选择之前被禁用
  • 用户必须为每种库存类型选择一个项目
  • 系统在继续之前验证选择

5. 选定的库存传递给 Ansible

一旦用户点击“继续”,所选库存 ID 作为变量传递给 Ansible 剧本:

# 用户选择:
# - SIM 卡 inventory_id: 5001
# - 手机号码 inventory_id: 5002

# 传递给 Ansible 的变量:
{
"product_id": 42,
"customer_id": 123,
"SIM Card": 5001, # 库存 ID
"Mobile Number": 5002, # 库存 ID
"access_token": "eyJ..."
}

注意: 变量名称与库存类型完全匹配。剧本使用 hostvars[inventory_hostname]['SIM Card'] 来访问库存 ID。

6. 剧本获取完整库存详细信息

Ansible 剧本使用库存 ID 获取完整详细信息:

- name: 从库存获取 SIM 卡详细信息
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ hostvars[inventory_hostname]['SIM Card'] }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: api_response_sim

- name: 提取 ICCID 和 IMSI
set_fact:
iccid: "{{ api_response_sim.json.itemtext1 }}"
imsi: "{{ api_response_sim.json.itemtext2 }}"

现在剧本拥有所有 SIM 详细信息(ICCID、IMSI 等)以在 HSS 中配置用户。

7. 库存状态更改为“已分配”

在创建服务记录后,剧本更新库存以将其链接到服务:

- name: 将 SIM 卡分配给服务
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ hostvars[inventory_hostname]['SIM Card'] }}"
method: PATCH
body:
{
"service_id": "{{ service_creation_response.json.service_id }}",
"customer_id": "{{ customer_id }}",
"item_state": "Assigned"
}

重要: 库存分配发生在 剧本执行期间 作为特定任务,而不是在点击配置按钮时。这意味着:

  • 双重分配风险:在点击“配置”和库存被分配之间,另一个用户理论上可以选择同一库存项目
  • 最佳实践:对于高容量操作,实施库存锁定或使用数据库事务
  • 失败时回滚:如果剧本在库存分配之前失败,库存保持未分配状态并可供重用

为什么不早点分配?

在点击“配置”时不会分配库存,因为:

  1. 需要服务 IDservice_id 在剧本中创建服务之前不存在
  2. 回滚简单性:如果配置早期失败(例如,OCS 账户创建失败),则不需要清理库存
  3. 灵活性:剧本可以根据条件逻辑决定不分配库存

处理失败的配置:

当配置在库存分配后失败时,救援块应释放库存:

rescue:
- name: 失败时释放库存
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ hostvars[inventory_hostname]['SIM Card'] }}"
method: PATCH
body:
{
"service_id": null,
"customer_id": null,
"item_state": "In Stock"
}
when: service_id is defined # 仅在服务已创建时

这确保库存不会留在“已分配”状态下,针对不存在或失败的服务。

当库存列表为空时

如果 inventory_items_list: "[]"(空列表),则完全跳过库存选择器,配置立即进行。这在以下情况下很常见:

  • 数字产品 - 软件许可证、VPN 账户
  • 服务附加组件 - 不需要新硬件的数据充值
  • 虚拟服务 - 不消耗可追踪资源

示例: “5GB 数据提升”附加组件具有 inventory_items_list: "[]",因为它只是向现有服务添加余额,而不需要新硬件。

库存模板设置

inventory_items_list 中使用库存类型之前,您必须创建库存模板:

  1. 导航到 管理库存模板
  2. 创建具有确切名称的模板(例如,“SIM 卡”)
  3. 定义字段:
    • itemtext1_label: "ICCID"
    • itemtext2_label: "IMSI"
    • itemtext3_label: "PUK 代码"
  4. 将此类型的库存项目添加到库存中

有关创建和管理库存模板的完整详细信息,请参见 库存管理

相同类型的多个项目

虽然 inventory_items_list 是一个数组,但拥有重复类型(例如,"['SIM Card', 'SIM Card']"不推荐,因为这可能会导致 UI 和剧本变量命名中的混淆。

对于需要多个相似项目的场景:

选项 1:创建不同的库存模板名称

# 双 SIM 手机服务
inventory_items_list: "['Primary SIM Card', 'Secondary SIM Card', 'Mobile Number']"

创建单独的模板:“Primary SIM Card”和“Secondary SIM Card”,具有相同字段但不同名称。

选项 2:使用单个捆绑库存项目

# 双 SIM 套件
inventory_items_list: "['Dual SIM Kit', 'Mobile Number']"

其中“Dual SIM Kit”库存模板具有两个 SIM 的字段(itemtext1: 主 ICCID,itemtext2: 次 ICCID 等)。

常见库存场景

移动服务:

inventory_items_list: "['SIM Card', 'Mobile Number']"
  • SIM 卡:带有 ICCID/IMSI 的物理或 eSIM
  • 手机号码:电话号码(MSISDN)

固定互联网:

inventory_items_list: "['Modem Router', 'Static IP Address']"
  • 调制解调器路由器:带有 MAC 地址的 CPE 设备
  • 静态 IP 地址:来自地址池的 IPv4

固定无线:

inventory_items_list: "['Fixed Wireless CPE', 'IPv4 Address', 'IPv6 Prefix']"
  • CPE:客户场所设备(天线、调制解调器)
  • IPv4:公共 IP 地址
  • IPv6 前缀:/56 或 /64 前缀

注意: 预约和调度不是库存项目。请使用单独的调度/日历系统进行安装预约。

VoIP 服务:

inventory_items_list: "['DID Number']"
  • DID 号码:直接拨入电话号码

注意: SIP 用户名、密码和账户配置配置剧本程序生成,而不是从库存中选择。

GPON/光纤:

inventory_items_list: "['ONT Device', 'GPON Port', 'IPv4 Address', 'Fiber Drop Cable']"
  • ONT 设备:带有序列号的光网络终端
  • GPON 端口:与光纤连接的 OLT 上的特定端口
  • IPv4 地址:公共或私有 IP
  • 光纤下线电缆:从街道到场所的物理光纤电缆(用于资产管理跟踪)

设备租赁:

inventory_items_list: "['Rental Modem']"
  • 跟踪哪个调制解调器与哪个客户
  • 取消时回收设备非常重要

为什么库存要求很重要

1. 防止双重分配

没有库存跟踪,您可能会意外地:

  • 将同一 SIM 卡分配给两个客户
  • 将同一 IP 地址��配给多个服务
  • 将同一设备序列号发货到不同位置

库存选择器确保每个项目仅分配给一个服务。

2. 审计跟踪

库存分配创建完整的审计跟踪:

  • 哪个 SIM 卡与哪个客户
  • 何时分配
  • 哪个服务使用哪个电话号码
  • 设备历史(谁拥有,何时,服务是什么)

3. 资源规划

跟踪库存水平:

  • 当 SIM 卡即将用完时发出警报
  • 在缺货之前重新订购
  • 根据 CPE 可用性规划技术人员日程
  • 管理 IP 地址空间分配

4. 成本跟踪

将批发成本链接到特定项目:

  • 跟踪每个 SIM 卡的成本
  • 计算设备折旧
  • 确定丢失或被盗的项目
  • 准确的 COGS(销售成本)

5. 取消配置

当服务被取消时,库存可以:

  • 释放回库存(SIM 卡、调制解调器)
  • 退役(损坏的设备)
  • 退还给供应商(租赁设备)
  • 在宽限期内保留(释放前的电话号码)

排查库存选择器问题

问题: “没有可用库存”消息出现

原因:

  • 数据库中不存在所需类型的库存项目
  • 所有项目已“分配”给其他服务
  • 项目被标记为“损坏”或“停用”
  • 库存模板名称不完全匹配(区分大小写)

解决方案:

  1. 验证库存模板是否存在:管理库存模板
  2. 检查模板名称是否完全匹配(包括空格、大小写)
  3. 添加此类型的库存项目:管理库存添加项目
  4. 验证项目是否处于“新”或“在库”状态
  5. 检查项目是否未分配(service_id 应为 NULL)

问题: 库存选择器未出现

原因:

  • inventory_items_list 为空:"[]"
  • inventory_items_list 为 NULL 或未设置
  • 产品类别为“附加组件”,并继承父服务库存

解决方案:

  • 如果需要库存,请设置 inventory_items_list: "['Type1', 'Type2']"
  • 验证产品定义是否正确保存
  • 检查 API 响应以确保产品包含 inventory_items_list

问题: 剧本失败,出现“未找到库存”

原因:

  • 剧本引用了错误的变量名称
  • 库存 ID 未正确传递
  • 在选择和配置之间库存已被删除

解决方案:

  • 验证剧本使用正确的变量: hostvars[inventory_hostname]['SIM Card']
  • 检查变量是否为整数: {{ hostvars[inventory_hostname]['SIM Card'] | int }}
  • 在剧本中添加缺失库存的错误处理

请参见 库存管理 以获取有关创建模板、添加项目��管理库存水平的完整详细信息。

步骤 7:定义功能和条款

功能和条款是面向客户的营销和法律内容,帮助客户理解他们所购买的内容及相关义务。

{
"features_list": "20GB 高速数据。无限通话和短信。包括欧盟漫游。无合同。30天到期",
"terms": "信用在 30 天后到期。数据、通话和短信仅在到期期间有效。适用公平使用政策。请参阅网站以获取完整条款。"
}

目的和商业价值

功能列表 - 营销与销售:

功能列表服务多个关键业务功能:

  1. 产品差异化 - 帮助客户快速比较产品并选择合适的产品
    • “预付费移动 20GB”与“预付费移动 50GB” - 功能清楚地显示差异
    • 如果没有功能,客户只会看到价格,错过价值主张
  2. 营销沟通 - 关键卖点显著展示
    • “包括欧盟漫游”吸引国际旅行者
    • “无合同”吸引不愿意承诺的客户
    • 功能推动购买决策
  3. 客户期望 - 明确设定包含的内容
    • 减少支持电话(“这包括通话吗?”→ 清楚列出)
    • 防止误解和退款请求
    • 通过透明度建立信任
  4. 自助服务 - 使客户能够自选适当的产品
    • 客户阅读功能,理解提供,做出明智选择
    • 减少销售人员的解释需求
    • 加快购买过程
  5. SEO 和可发现性 - 功能可以被索引以供搜索
    • 客户搜索“无限通话移动计划”→ 产品出现
    • 提高产品目录的可搜索性

条款和条件 - 法律与合规:

条款服务法律和运营目的:

  1. 法律保护 - 保护企业免受争议和责任
    • “信用在 30 天后到期” - 客户不能在 31 天时要求退款
    • “适用公平使用政策” - 防止滥用(在移动计划上为整个办公室提供网络)
    • 创建具有约束力的协议
  2. 期望管理 - 防止客户不满
    • “仅在到期期间有效” - 客户知道使用截止日期
    • “不可退款”(对于附加组件) - 防止欺诈性购买
    • 减少退款和投诉
  3. 合规性 - 符合法律要求
    • 消费者保护法要求明确条款
    • 电信法规要求披露
    • GDPR/隐私条款可以被引用
  4. 运营边界 - 定义服务范围和限制
    • “受网络覆盖限制” - 不对死区负责
    • “速度可能会有所不同” - 管理对“最高”速度的期望
    • “设备必须归还” - 确保租赁设备的回收
  5. 审计跟踪 - 证明客户已被告知
    • 客户在购买时接受条款
    • 系统记录接受时间戳
    • 在争议或法律程序中可辩护

实际案例:

客户购买“无限通话和短信”计划,然后用于电话营销(每天 10,000 个电话)。没有条款:

  • 客户:“你说无限!”
  • 提供商:“我们的意思是个人使用...\”
  • 客户:“这不是你宣传的内容!”
  • 结果:争议,潜在的监管投诉,品牌损害

有条款:“适用公平使用政策。服务仅供个人使用。禁止商业使用。”

  • 提供商:指向客户接受的条款
  • 客户无法声称无知
  • 有法律依据暂停服务
  • 争议以提供商的有利结果解决

功能列表格式:

理解正确的格式至关重要,因为不正确的格式会破坏 UI 显示。功能可能会显示为一个长字符串而不是项目符号,或者根本不显示。

features_list 字段可以以两种方式格式化:

选项 1:以句号分隔的字符串(推荐)

功能用句号和空格(“.”)分隔。UI 在此分隔符上拆分并将每个功能呈现为项目符号。

为什么选择这种格式?

  • 易于编辑 - 只需在它们之间输入句号即可
  • 无需转义特殊字符
  • 在所有 UI 组件中可靠工作
  • 易于更新而不破坏 JSON 语法

正确与错误:

选项 2:JSON 数组字符串

"['20GB 高速数据', '无限通话和短信', '包括欧盟漫游']"

UI 也可以解析 JSON 数组。请注意,这是一种包含 JSON 的字符串,而不是数据库中的实际 JSON 数组。

为什么存在这种格式?

  • 允许功能中包含句号(例如,“最高 100Mbps。受可用性限制。”)
  • 从脚本/API 进行程序生成更容易
  • 从使用数组的外部产品目录导入

重要: 这必须是有效的 Python 列表语法作为字符串。每个项目周围使用单引号,整个字符串使用双引号。

使用哪种格式?

  • 以句号分隔 - 用于在 UI 中手动创建产品(更简单,错误更少)
  • JSON 数组 - 用于基于 API/脚本的产品创建(对于复杂功能更强大)

这两种格式在 UI 中产生相同的输出 - 只是影响您输入数据的方式。

功能在 UI 中出现的位置:

1. 产品目录(客户视图)

当客户浏览可用产品时,功能显示为每个产品卡上的项目符号:

2. 产品详细信息页面

点击“查看详细信息”显示完整的产品信息,包括:

  • 产品名称和图标
  • 定价(每月费用、设置费用)
  • 完整功能列表(项目符号)
  • 条款和条件(见下文)
  • 可用性和资格

3. 配置确认

在配置过程中,功能显示给用户以供审阅后确认:

功能:• 20GB 高速数据 • 无限通话和短信 • 包括欧盟漫游 • 无合同 • 30 天到期

成本:£15.00/月 设置:£0.00

[取消] [确认并配置]

4. 服务详细信息(配置后)

服务激活后,功能显示在服务详细信息页面供客户参考。

条款和条件格式:

terms 字段是可以包含换行符的纯文本:

条款在 UI 中出现的位置:

1. 产品详细信息页面

条款显示在点击时展开的折叠部分中:

2. 订单确认

在配置过程中,复选框要求用户接受条款:

[配置] 按钮在选中之前被禁用

3. 发票

服务条款可能作为脚注包含在发票中以便清晰。

最佳实践:

  • 功能: 保持简洁(每个不超过 50 个字符),关注关键利益
  • 条款: 包括关键法律要求、到期政策、公平使用政策
  • 两者: 产品变更时更新,以保持客户知情

步骤 8:链接 Ansible 配置剧本

{
"provisioning_play": "play_local_mobile_sim",
"provisioning_json_vars": "{
\"days\": 30,
\"data_gb\": 20,
\"voice_minutes\": \"unlimited\",
\"sms_count\": \"unlimited\"
}"
}
  • provisioning_play - Ansible 剧本的名称(不带 .yaml 扩展名)
  • provisioning_json_vars - 传递给剧本的默认变量
  • 剧本必须存在于: OmniCRM-API/Provisioners/plays/play_local_mobile_sim.yaml

完整产品定义

{
"product_name": "Prepaid Mobile 20GB",
"product_slug": "prepaid-mobile-20gb",
"category": "standalone",
"service_type": "mobile",
"enabled": true,
"icon": "fa-solid fa-sim-card",
"comment": "预付费移动 SIM,包含 20GB 数据,无限通话和短信",

"retail_cost": 15.00,
"wholesale_cost": 5.00,
"retail_setup_cost": 0.00,
"wholesale_setup_cost": 1.00,
"contract_days": 30,

"residential": true,
"business": false,
"customer_can_purchase": true,
"available_from": "2025-01-01T00:00:00Z",
"available_until": null,

"auto_renew": "prompt",
"allow_auto_renew": true,

"inventory_items_list": "['SIM Card', 'Mobile Number']",

"features_list": "[
'20GB 高速数据',
'无限通话和短信',
'包括欧盟漫游',
'无合同',
'30天到期'
]",
"terms": "信用在 30 天后到期。数据、通话和短信仅在到��期间有效。适用公平使用政策。",

"provisioning_play": "play_local_mobile_sim",
"provisioning_json_vars": "{
\"days\": 30,
\"data_gb\": 20,
\"voice_minutes\": \"unlimited\",
\"sms_count\": \"unlimited\"
}"
}

创建附加组件产品

附加组件增强或修改现有服务。它们分为两种类型:虚拟附加组件(没有物理资源)和 硬件附加组件(需要库存)。

示例 1:虚拟附加组件(5GB 数据提升)

一个数字附加组件,向现有移动服务添加数据:

{
"product_name": "5GB Data Boost",
"product_slug": "5gb-data-boost",
"category": "addon",
"service_type": "mobile",
"enabled": true,
"icon": "fa-solid fa-plus",
"comment": "向现有移动服务添加 5GB 额外数据",

"retail_cost": 5.00,
"wholesale_cost": 1.50,
"retail_setup_cost": 0.00,
"wholesale_setup_cost": 0.00,
"contract_days": 0,

"residential": true,
"business": true,
"customer_can_purchase": true,

"auto_renew": "false",
"allow_auto_renew": false,

"inventory_items_list": "[]",
"relies_on_list": "",

"features_list": "5GB 高速数据。有效期 7 天",
"terms": "数据在 7 天后或用��时到期。不可退款。",

"provisioning_play": "play_topup_charge_then_action",
"provisioning_json_vars": "{
\"data_gb\": 5,
\"days\": 7
}"
}

示例 2:硬件附加组件(调制解调器租赁)

一个附加组件,为现有光纤服务提供物理设备:

{
"product_name": "WiFi 6 Modem Rental",
"product_slug": "wifi6-modem-rental",
"category": "addon",
"service_type": "internet",
"enabled": true,
"icon": "fa-solid fa-router",
"comment": "为光纤服务添加 WiFi 6 调制解调器 - 租赁",

"retail_cost": 10.00,
"wholesale_cost": 3.00,
"retail_setup_cost": 0.00,
"wholesale_setup_cost": 45.00,
"contract_days": 30,

"residential": true,
"business": true,
"customer_can_purchase": true,

"auto_renew": "true",
"allow_auto_renew": true,

"inventory_items_list": "['Rental Modem']",
"relies_on_list": "",

"features_list": "WiFi 6 (802.11ax)。双频 2.4GHz + 5GHz。支持最多 40 个设备。家长控制",
"terms": "设备租赁。必须在服务取消时归还,否则将收取 £150 替换费。设备仍为提供商的财产。",

"provisioning_play": "play_addon_assign_modem",
"provisioning_json_vars": "{
\"device_type\": \"modem_router\",
\"requires_configuration\": true
}"
}

附加组件的关键区别:

  • category: "addon" - 应用于现有服务,而不是独立的
  • contract_days: 0(虚拟)或 30(定期租赁) - 计费频率
  • inventory_items_list: "[]"(虚拟)或 "['Rental Modem']"(硬件) - 物理资源
  • auto_renew: "false"(一次性)或 "true"(租赁) - 定期行为
  • relies_on_list: "" - 为空意味着适用于任何匹配 service_type 的服务

为什么硬件附加组件需要库存:

硬件附加组件需要 inventory_items_list,因为:

  1. 跟踪设备 - 知道哪个调制解调器与哪个客户
  2. 防止缺货 - 如果没有调制解调器,则无法配置附加组件
  3. 回收 - 当客户取消时,知道需要回收哪些设备
  4. 成本跟踪 - 将批发成本链接到特定序列号
  5. 折旧 - 跟踪设备在租赁期间的价值
  6. 保修 - 通过序列号识别缺陷单位

带库存的附加组件配置流程:

当客户将“WiFi 6 调制解调器租赁”添加到他们的光纤服务时:

  1. 选择附加组件 - 客户点击“添加到服务”
  2. 库存选择器出现 - 与独立服务相同:
  3. 处理付款 - 收取 £10.00 的月租费
  4. 调制解调器分配 - 更新库存:
    • service_id: 链接到光纤服务
    • customer_id: 链接到客户
    • item_state: “已分配”
  5. 触发发货 - 通知履行系统发货调制解调器
  6. 安装 - 客户收到调制解调器,插入 ONT
  7. 定期计费 - 每月收取 £10,直到附加组件取消

取消配置硬件附加组件:

当客户取消调制解调器租赁时:

  1. 取消发起 - 客户点击“移除附加组件”
  2. 开始退货流程
    • 发送电子邮件,附带退货说明
    • 生成预付费运输标签
    • 在处罚之前提供 14 天宽限期
  3. 设备归还
    • 更新库存:item_state = “在库”(经过翻新后)
    • item_state = “损坏”(如果有缺陷)
    • 一旦翻新,链接到下一个客户
  4. 未归还
    • 14 天后,收取 £150 替换费
    • 库存标记:item_state = “丢失”
    • 收回批发成本(£45)+ 替换价值

附加组件的定价:

附加组件的定价可以与独立服务不同:

  • 虚拟附加组件通常没有设置费用
  • 硬件附加组件可能有设备的批发设置费用
  • 定期租赁附加组件使用 contract_days 作为计费频率

阶段 2:配置过程

当客户订��“预付费移动 20GB”产品时,OmniCRM 通过 Ansible 协调配置。

配置流程图

客户订购 → 库存选择 → 创建配置作业 ↓ ↓ 付款授权 ← 变量组装 ← 执行 Ansible 剧本 ↓ ↓ 创建服务记录 → OCS 账户设置 → 库存分配 → 服务激活

步骤配置流程

1. 客户发起订单

从客户页面:

  • 员工点击“添加服务”
  • 从产品轮播中选择“预付费移动 20GB”
  • 显示产品详细信息和定价

2. 库存选择

系统提示所需库存:

  • SIM 卡 - 下拉菜单显示可用的 SIM 卡
    • 示例:“SIM-00123 - ICCID: 8944...\”
  • 手机号码 - 下拉菜单显示可用的电话号码
    • 示例:“+44 7700 900123”

员工或客户从可用库存中选择项目。

3. 确认定价

系统显示最终定价:

  • 设置费用:£0.00(免费激活)
  • 月费用:£15.00
  • 今日到期:£15.00(第一个月)
  • 续订日期:从今天起 30 天

如果启用自动续订提示,客户选择:

  • 每 30 天自动续订此服务

4. 点击配置按钮

当点击“配置”时,API:

  • 创建状态为“运行”的 Provision 记录(status=1)
  • 合并来自产品 + 请求 + 库存选择的变量
  • 生成后台线程以执行 Ansible 剧本
  • 返回 provision_id 到 UI 以进行状态跟踪

5. 变量组装

系统合并来自多个来源的变量:

来自产品:

{
"days": 30,
"data_gb": 20,
"voice_minutes": "unlimited",
"sms_count": "unlimited"
}

来自请求:

{
"product_id": 42,
"customer_id": 123,
"SIM Card": 5001,
"Mobile Number": 5002
}

系统添加:

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"initiating_user": 7
}

最终传递给 Ansible 的变量:

{
"product_id": 42,
"customer_id": 123,
"SIM Card": 5001,
"Mobile Number": 5002,
"days": 30,
"data_gb": 20,
"voice_minutes": "unlimited",
"sms_count": "unlimited",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"initiating_user": 7
}

6. 执行 Ansible 剧本

剧本 play_local_mobile_sim.yaml 使用这些变量执行。

理解 Ansible 配置剧本

让我们检查一个实��的配置剧本,以了解幕后发生的事情。

移动 SIM 配置剧本示例

位置: OmniCRM-API/Provisioners/plays/play_local_mobile_sim.yaml

高级结构:

- name: 移动 SIM 配置
hosts: localhost
gather_facts: no
become: False

tasks:
- name: 主块
block:
# 1. 加载配置
# 2. 从 API 获取产品详细信息
# 3. 从 API 获取客户详细信息
# 4. 从 API 获取库存详细信息
# 5. 在 OCS 中创建账户(CGRateS)
# 6. 向 OCS 添加余额和津贴
# 7. 在 CRM 中创建服务记录
# 8. 将库存分配给服务
# 9. 记录交易
# 10. 发送欢迎通知

rescue:
# 失败时回滚
# - 删除 OCS 账户
# - 释放库存
# - 记录错误

详细剧本逐步解析:

任务 1:加载配置

- name: 包含 crm_config 的变量
ansible.builtin.include_vars:
file: "../../crm_config.yaml"
name: crm_config

加载系统配置,包括:

  • OCS/CGRateS URL 和凭据
  • CRM 基本 URL
  • 租户配置

任务 2:获取产品详细信息

- name: 从 CRM API 获取产品信息
uri:
url: "{{ crm_config.crm.base_url }}/crm/product/product_id/{{ product_id }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
return_content: yes
register: api_response_product

这做了什么:

  • 调用 GET /crm/product/product_id/42
  • 检索完整的产品定义
  • 存储在 api_response_product 变量中

为什么: 即使我们从产品中有 provisioning_json_vars,我们仍然获取完整的产品以获取:

  • 最新定价(可能在订单开始后已更改)
  • 服务命名所需的产品名称
  • 文档的功能列表
  • 用于利润跟踪的批发成本

任务 3:设置包事实

- name: 设置包事实
set_fact:
package_name: "{{ api_response_product.json.product_name }}"
monthly_cost: "{{ api_response_product.json.retail_cost }}"
setup_cost: "{{ api_response_product.json.retail_setup_cost }}"

提取常用值以便于可读性。

任务 4:获取库存详细信息

- name: 从 CRM API 获取 SIM 信息
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ hostvars[inventory_hostname]['SIM Card'] }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: api_response_sim

- name: 从库存响应中设置 IMSI
set_fact:
imsi: "{{ api_response_sim.json.itemtext2 }}"
iccid: "{{ api_response_sim.json.itemtext1 }}"

这做了什么:

  • 查找 SIM 卡库存 ID 5001
  • 检索 SIM 详细信息:
    • itemtext1 = ICCID(SIM 卡号)
    • itemtext2 = IMSI(用户身份)
  • 对手机号码库存执行相同操作(检索电话号码)

这有什么重要性:

  • IMSI 是在 HSS(家庭用户服务器)中配置用户所需的
  • ICCID 在服务备注中记录以便于故障排除
  • 电话号码(MSISDN)显示给客户并用于路由

任务 5:生成服务 UUID

- name: 生成 UUID 事实
set_fact:
uuid: "{{ 99999999 | random | to_uuid }}"

- name: 设置服务 UUID
set_fact:
service_uuid: "Local_Mobile_SIM_{{ uuid[0:8] }}"

这做了什么:

  • 生成随机 UUID
  • 创建类似 Local_Mobile_SIM_a3f2c1d8 的 service_uuid

为什么:

  • 服务 UUID 是 OCS/CGRateS 中的唯一标识符
  • 用于所有计费操作
  • 必须在所有服务中全局唯一

任务 6:在 OCS 中创建账户

- name: 在 OCS 中创建账户
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
headers:
Content-Type: "application/json"
body:
{
"method": "ApierV2.SetAccount",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"ActionPlanIds": [],
"ExtraOptions": {
"AllowNegative": false,
"Disabled": false
},
"ReloadScheduler": true
}]
}
register: ocs_create_response

这做了什么:

  • 调用 CGRateS JSON-RPC API
  • 使用 service_uuid 创建新账户
  • 将账户设置为活动状态(未禁用)
  • 防止负余额(预付费模式)

为什么:

  • OCS 账户是所有计费发生的地方
  • 在此存储余额(数据、语音、短信、资金)
  • 使用实时跟踪和计费

任务 7:添加数据余额

- name: 添加 20GB 数据余额
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "DATA_20GB_Monthly",
"Value": 21474836480,
"ExpiryTime": "+720h",
"Weight": 10,
"DestinationIDs": "*any"
}
}]
}

这做了什么:

  • 向账户添加 20GB 数据余额
  • 值:21474836480 字节(20 * 1024 * 1024 * 1024)
  • 在 720 小时(30 天)后到期
  • 权重 10(优先消耗较高的权重)

任务 8:添加无限语音和短信

- name: 添加无限语音
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Account": "{{ service_uuid }}",
"BalanceType": "*voice",
"Balance": {
"ID": "VOICE_Unlimited",
"Value": 999999999,
"ExpiryTime": "+720h"
}
}]
}
  • 添加 999,999,999 秒的语音(基本上是无限的)
  • 在 30 天后到期

任务 9:在 CRM 中创建服务记录

- name: 通过 API 添加服务
uri:
url: "{{ crm_config.crm.base_url }}/crm/service/"
method: PUT
body_format: json
headers:
Authorization: "Bearer {{ access_token }}"
body:
{
"customer_id": "{{ customer_id }}",
"product_id": "{{ product_id }}",
"service_name": "Mobile - {{ phone_number }}",
"service_type": "mobile",
"service_uuid": "{{ service_uuid }}",
"service_status": "Active",
"service_provisioned_date": "{{ provision_datetime }}",
"retail_cost": "{{ monthly_cost }}",
"wholesale_cost": "{{ api_response_product.json.wholesale_cost }}",
"icon": "fa-solid fa-sim-card"
}
register: service_creation_response

这创建了什么:

  • 与客户关联的服务记录
  • 通过 service_uuid 链接到 OCS
  • 存储零售和批发成本
  • 将状态设置为“活动”
  • 返回 service_id 以进行后续操作

任务 10:将库存分配给服务

- name: 将 SIM 卡分配给服务
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ hostvars[inventory_hostname]['SIM Card'] }}"
method: PATCH
body_format: json
headers:
Authorization: "Bearer {{ access_token }}"
body:
{
"service_id": "{{ service_creation_response.json.service_id }}",
"customer_id": "{{ customer_id }}",
"item_state": "Assigned"
}

这做了什么:

  • 更新 SIM 卡库存记录
  • service_id 设置为将 SIM 链接到服务
  • 将状态从“在库”更改为“已分配”
  • 对手机号码库存重复此操作

���什么:

  • 跟踪哪个 SIM 分配给哪个客户
  • 防止库存的双重分配
  • 启用库存报告和审计

任务 11:记录设置成本交易

- name: 添加设置成本交易
uri:
url: "{{ crm_config.crm.base_url }}/crm/transaction/"
method: PUT
body_format: json
headers:
Authorization: "Bearer {{ access_token }}"
body:
{
"customer_id": "{{ customer_id }}",
"service_id": "{{ service_creation_response.json.service_id }}",
"title": "{{ package_name }} - Setup",
"description": "激活费用",
"retail_cost": "{{ setup_cost }}",
"wholesale_cost": "{{ api_response_product.json.wholesale_setup_cost }}"
}

这做了什么:

  • 记录 £0.00 的设置费用(零售)到客户
  • 记录 £1.00 的批发成本
  • 创建交易记录以便开票

任务 12:救援块(错误处理)

rescue:
- name: 失败时删除 OCS 账户
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "ApierV2.RemoveAccount",
"params": [{
"Account": "{{ service_uuid }}"
}]
}

- name: 使配置失败
fail:
msg: "配置��败,已回滚 OCS 账户"

这做了什么:

  • 如果任何任务失败,救援块执行
  • 删除部分创建的 OCS 账户
  • 将库存释放回“在库”
  • 使配置作业失败并显示错误消息

为什么:

  • 防止 OCS 中孤立账户
  • 确保在错误时进行干净回滚
  • 维护数据一致性

配置完成:创建了什么

成功配置后,系统具有:

1. OCS 账户(CGRateS):

  • 账户 ID:Local_Mobile_SIM_a3f2c1d8
  • 余额:
    • 20GB 数据(在 30 天后到期)
    • 无限语音(999M 秒,在 30 天后到期)
    • 无限短信(999M 消息,在 30 天后到期)

2. CRM 服务记录:

  • 服务 ID:1234
  • 客户:John Doe(customer_id: 123)
  • 产品:预付费移动 20GB(product_id: 42)
  • 服务名称:“Mobile - +44 7700 900123”
  • 服务 UUID:Local_Mobile_SIM_a3f2c1d8
  • 状态:活动
  • 月费用:£15.00(零售),£5.00(批发)
  • 利润:£10.00/月

3. 库存分配:

  • SIM 卡 5001:分配给服务 1234,客户 123
  • 手机号码 5002:分配给服务 1234,客户 123

4. 交易记录:

  • 创建设置成本交易
  • 记录第一个月费用

5. 客户现在可以:

  • 在自助服务门户中查看服务
  • 查看 20GB 数据余额
  • 拨打电话和发送短信
  • 充值或添加附加组件
  • 实时查看使用情况

阶段 3:添加附加组件和充值

服务激活后,客户可以购买附加组件以增强其服务。

附加组件配置流程

假设客户已使用 20GB 限额中的 18GB,并希望购买“5GB 数据提升”附加组件。

1. 客户导航到服务

  • 打开“Mobile - +44 7700 900123”服务页面
  • 查看当前使用情况:20GB 中使用 18GB(90%)
  • 点击“添加附加组件”或“充值”

2. 系统过滤可用附加组件

仅显示以下附加组件:

  • category = "addon"
  • service_type = "mobile"(匹配服务类型)
  • residential = true(如果客户是住宅)
  • enabled = true

客户看到:“5GB 数据提升 - £5.00”

3. 客户选择附加组件

  • 点击“5GB 数据提升”
  • 确认购买 £5.00
  • 系统捕获付款授权

4. 附加组件配置启动

系统调用 play_topup_charge_then_action.yaml,并传递变量:

{
"product_id": 43, # 5GB 数据提升产品
"customer_id": 123,
"service_id": 1234, # 现有服务
"access_token": "eyJ...",
"data_gb": 5, # 来自 provisioning_json_vars
"days": 7 # 来自 provisioning_json_vars
}

与独立服务的关键区别:

  • 包含 service_id(要修改的现有服务)
  • 不需要库存
  • 不创建服务(修改现有服务)

附加组件配置剧本逐步解析

任务 1:获取服务详细信息

- name: 从 CRM API 获取服务信息
uri:
url: "http://localhost:5000/crm/service/service_id/{{ service_id }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: api_response_service

- name: 设置服务事实
set_fact:
service_uuid: "{{ api_response_service.json.service_uuid }}"
customer_id: "{{ api_response_service.json.customer_id }}"

为什么:

  • 需要 service_uuid 以向正确的 OCS 账户添加余额
  • 验证服务是否存在且处于活动状态
  • 确保服务属于客户

任务 2:向客户收费

- name: 获取客户的默认支付方式
uri:
url: "http://localhost:5000/crm/stripe/customer_id/{{ customer_id }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: api_response_stripe

- name: 获取默认卡 ID
set_fact:
customer_stripe_id: "{{ api_response_stripe.json | json_query(query) }}"
vars:
query: "data[?default_payment_method==`true`].customer_stripe_id | [0]"

- name: 向卡收费
uri:
url: "http://localhost:5000/crm/stripe/charge_card/{{ customer_stripe_id }}"
method: POST
body_format: json
headers:
Authorization: "Bearer {{ access_token }}"
body:
{
"retail_cost": 5.00,
"description": "5GB 数据提升",
"customer_id": "{{ customer_id }}",
"service_id": "{{ service_id }}",
"product_id": "{{ product_id }}",
"wholesale_cost": 1.50,
"invoice": true
}
register: charge_response

- name: 断言付款成功
assert:
that:
- charge_response.status == 200

这做了什么:

  • 查找客户的默认 Stripe 付款方式
  • 向卡收费 £5.00
  • 记录批发成本 £1.50 以便于利润跟踪
  • 创建与服务关联的交易
  • 添加到下一个发票中
  • 如果付款失败,则使配置失败

为什么先收费:

  • 在确认付款之前不交付信用
  • 防止欺诈
  • 将付款与附加组件配置匹配

任务 3:向 OCS 添加数据余额

- name: 添加 5GB 数据余额
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "ApierV1.AddBalance",
"params": [{
"Account": "{{ service_uuid }}",
"BalanceType": "*data",
"Balance": {
"ID": "DATA_5GB_Boost_{{ uuid }}",
"Value": 5368709120,
"ExpiryTime": "+168h",
"Weight": 20
}
}]
}

这做了什么:

  • 向账户添加 5GB(5368709120 字节)
  • 在 168 小时(7 天)后到期
  • 权重 20(优先消耗较高的权重 - 提升在每月限额之前消耗)

客户在附加组件后的余额:

  • 原始每月:剩余 2GB(在 25 天后到期)
  • 新提升:5GB(在 7 天后到期)
  • 可用总量:7GB
  • 使用顺序:首先消耗提升,然后是每月限额

任务 4:记录交易

- name: 添加附加组件交易
uri:
url: "http://localhost:5000/crm/transaction/"
method: PUT
body_format: json
headers:
Authorization: "Bearer {{ access_token }}"
body:
{
"customer_id": "{{ customer_id }}",
"service_id": "{{ service_id }}",
"title": "5GB 数据提升",
"description": "额外 5GB 数据,有效期 7 天",
"retail_cost": 5.00,
"wholesale_cost": 1.50
}

这做了什么:

  • 记录 £5.00 的费用到客户
  • 记录 £1.50 的批发成本
  • 将交易链接到服务以便于报告

完整附加组件流程摘要

  1. 客户从过滤列表中选择附加组件
  2. 付款获得授权并收费
  3. 数据余额添加到 OCS 账户
  4. 在 CRM 中记录交易
  5. 客户立即看到更新的余额:可用 7GB

财务跟踪:

  • 服务每月费用:£15 零售,£5 批发
  • 附加组件购买:£5 零售,£1.50 批发

自动续订:定期附加组件

某些附加组件可以设置为自动续订(每月数据计划、订阅等)。

产品配置:

{
"product_name": "每月 10GB 数据计划",
"category": "addon",
"retail_cost": 10.00,
"contract_days": 30,
"auto_renew": "true",
"provisioning_play": "play_topup_charge_then_action"
}

配置创建 ActionPlan:

- name: 为自动续订创建 ActionPlan
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "ApierV1.SetActionPlan",
"params": [{
"Id": "ServiceID_{{ service_uuid }}__ProductID_{{ product_id }}__MonthlyRenewal",
"ActionPlan": [{
"ActionsId": "Action_{{ product_slug }}",
"Years": "*any",
"Months": "*any",
"MonthDays": "*any",
"WeekDays": "*any",
"Time": "00:00:00",
"Weight": 10
}],
"Overwrite": false,
"ReloadScheduler": true
}]
}

这做了什么:

  • 在 OCS 中创建计划任务
  • 每 30 天执行 Action_{{ product_slug }}
  • 动作收费客户并重新应用数据余额
  • 直到客户取消为止

客户管理:

  • 客户在服务视图中看到“下次续订:2025 年 2 月 1 日 - £10.00”
  • 可以点击“取消自动续订”以停止未来收费
  • 可以点击“立即续订”以立即应用下个月的配额

阶段 4:取消配置服务

当客户取消服务时,系统必须干净地移除所有资源。

取消配置触发器

取消配置可以由以下原因触发:

  1. 客户取消 - 客户点击“取消服务”
  2. 行政操作 - 员工标记服务以进行停用
  3. 未付款 - 服务因未续订而到期
  4. 合同结束 - 固定期限合同达到结束日期

取消配置流程

1. 客户发起取消

  • 导航到服务
  • 点击“取消服务”
  • 系统提示:“您确定吗?任何剩余余额将被没收。”
  • 客户确认

2. 宽限期(可选)

某些运营商实施宽限期:

  • 服务标记为“待取消”
  • 在 7-30 天内保持活动状态
  • 客户可以在宽限期内撤销取消
  • 宽限期后自动取消配置

3. 创建取消配置作业

系统创建配置作业,内容如下:

{
"action": "deprovision",
"service_id": 1234,
"customer_id": 123,
"service_uuid": "Local_Mobile_SIM_a3f2c1d8"
}

调用在 service.deprovisioning_play 中指定的剧本或原始剧本的救援块。

4. Ansible 取消配置剧本

- name: 取消配置移动服务
hosts: localhost
tasks:
- name: 禁用 OCS 账户
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "ApierV2.SetAccount",
"params": [{
"Account": "{{ service_uuid }}",
"ExtraOptions": { "Disabled": true }
}]
}

- name: 删除 ActionPlans(停止自动续订)
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "ApierV1.RemoveActionPlan",
"params": [{
"Id": "ServiceID_{{ service_uuid }}__*"
}]
}

- name: 更新 CRM 中的服务状态
uri:
url: "http://localhost:5000/crm/service/{{ service_id }}"
method: PATCH
body:
{
"service_status": "Deactivated",
"service_deactivate_date": "{{ current_datetime }}"
}

- name: 释放库存到库存
uri:
url: "http://localhost:5000/crm/inventory/inventory_id/{{ sim_card_id }}"
method: PATCH
body:
{
"service_id": null,
"customer_id": null,
"item_state": "Decommissioned"
}

这做了什么:

  1. 禁用 OCS 账户 - 停止所有收费,阻止使用
  2. 删除 ActionPlans - 取消自动续订
  3. 更新 CRM 服务 - 状态“已停用”,记录日期
  4. 释放库存 - SIM 标记为“退役”,可供重用(翻新后)

5. 取消配置后

系统执行清理:

  • 客户不再在自助服务门户中看到服务
  • 服务仍保留在 CRM 中以便于历史报告
  • 交易和发票保留以便于会计
  • 库存可以翻新并重用
  • OCS 账户可以在保留期后归档

部分与完全取消配置

部分取消配置(暂停):

  • 用于未付款或临时暂停
  • OCS 账户被禁用但未删除
  • 保留余额
  • 收到付款时可以重新启用
- name: 暂停服务
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "ApierV2.SetAccount",
"params": [{
"Account": "{{ service_uuid }}",
"ExtraOptions": { "Disabled": true }
}]
}

完全取消配置(永久取消):

  • 用于永久取消
  • OCS 账户完全删除
  • 余额没收
  • 无法重新启用
- name: 删除 OCS 账户
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body:
{
"method": "ApierV2.RemoveAccount",
"params": [{
"Account": "{{ service_uuid }}"
}]
}

产品管理的最佳实践

产品生命周期管理

产品状态:

  • enabled: true - 产品可供新订单
  • enabled: false - 产品禁用,现有服务继续

禁用产品:

  • 将产品标记为 enabled: false 以防止新订单
  • 现有服务保持活动状态
  • 客户仍然可以续订/修改现有服务
  • 对于逐步淘汰旧产品非常有用

库存管理

库存状态:

  • New - 新库存,准备分配
  • In Stock - 可供配置
  • Assigned - 与客户服务关联
  • Decommissioned - 可以翻新并重用
  • Damaged - 需要修理或处置

重用库存:

取消配置后:

  • SIM 卡:翻新并标记为“在库”
  • 电话号码:在端口期后释放(30 天)
  • 设备:测试、翻新、标记为“已使用”

配置指标

监控:

  • 配置成功率
  • 平均配置时间
  • 常见故障点
  • 库存周转率