跳到主要内容

完整产品生命周期指南

本指南提供了 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": "预付费移动 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:指定库存要求

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

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

什么是库存项目?

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

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

库存要求的工作原理:

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

示例库存要求:

# 移动 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 为 "New" 或 "In Stock"(而不是 "Assigned" 或 "Damaged")
  • 未分配 - 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. 需要服务 ID:在剧本中创建服务之前,service_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 Code"
  4. 将此类型的库存项目添加到库存中

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

相同类型的多个项目

虽然 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 }}
  • 在剧本中添加缺少库存的错误处理

有关创建模板、添加项目和管理库存水平的完整详细信息,请参见 库存管理 <administration_inventory>

步骤 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": "预付费移动 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 数据提升",
"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 调制解调器租赁",
"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: "Assigned"
  5. 触发发货 - 通知履行系统发货调制解调器
  6. 安装 - 客户收到调制解调器,插入 ONT
  7. 递归计费 - 每月收取 £10,直到附加组件被取消

取消配置硬件附加组件:

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

  1. 发起取消 - 客户点击“移除附加组件”
  2. 开始退货流程
    • 发送带有退货说明的电子邮件
    • 生成预付费运输标签
    • 在罚款之前有 14 天的宽限期
  3. 设备归还
    • 库存更新:item_state = "In Stock"(经过翻新后)
    • item_state = "Damaged"(如果有缺陷)
    • 一旦翻新,链接到下一个客户
  4. 未归还
    • 14 天后,收取 £150 的更换费用
    • 库存标记:item_state = "Lost"
    • 收回批发成本(£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:

  • 创建状态为“运行”(status=1)的 Provision 记录
  • 合并来自产品 + 请求 + 库存选择的变量
  • 生成后台线程以执行 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 }} - 设置",
"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/api/payments/methods/default?customer_id={{ customer_id }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: api_response_payment_method

- name: 获取默认付款方式 ID
set_fact:
payment_method_id: "{{ api_response_payment_method.json.data.payment_method_id }}"

- name: 向客户收费
uri:
url: "http://localhost:5000/api/payments/charge"
method: POST
body_format: json
headers:
Authorization: "Bearer {{ access_token }}"
body:
{
"customer_id": "{{ customer_id | int }}",
"amount": 5.00,
"currency": "USD",
"payment_method_id": "{{ payment_method_id }}",
"metadata": {
"description": "5GB 数据提升",
"service_id": "{{ service_id | int }}",
"product_id": "{{ product_id | int }}",
"invoice": true
}
}
register: charge_response

- name: 确保付款成功
assert:
that:
- charge_response.json.success == true

这做了什么:

  • 查找客户的默认 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"
}

配置创建操作计划:

- name: 为自动续订创建操作计划
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: 删除操作计划(停止自动续订)
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. 删除操作计划 - 取消自动续订
  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 天)后释放
  • 设备:测试、翻新、标记为“已使用”

配置指标

监控:

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