自定义和配置
本指南解释了如何自定义和配置 OmniCRM,以匹配您的品牌形象、操作要求和集成需求。
环境变量 (.env 文件)
OmniCRM 使用环境变量来配置后端 API 和前端 UI。有两个单独的 .env 文件控制系统的不同方面。
后端 API 配置 (.env)
位于 OmniCRM 目录的根目录,此文件配置数据库连接和 CGRates 集成。
位置: /OmniCRM/.env
数据库配置:
# MySQL/MariaDB 数据库 (CRM 数据)
MYSQL_ROOT_PASSWORD=your_secure_password
MYSQL_USER=omnitouch
MYSQL_PASSWORD=your_database_password
MYSQL_DATABASE=crm
DB_SERVER=db
# PostgreSQL 数据库 (CGRates 数据)
POSTGRES_USER=cgrates
POSTGRES_PASSWORD=cgrates_password
POSTGRES_DB=cgrates_db
CGRates 配置:
# CGRates API 凭证
CGRATES_API_USER=admin
CGRATES_API_PASS=secret
CGRATES_DB_USER=cgrates
CGRATES_DB_PASS=cgrates_password
CGRATES_DB_NAME=cgrates_db
CGRATES_DB_PORT=5432
安全考虑:
- 绝不要将 .env 文件提交到版本控制 - 使用
.env.example作为模板 - 使用强密码 - 至少 16 个字符,包含大小写字母、数字和符号
- 定期更换凭证 - 尤其是在生产部署中
- 限制数据库访问 - 使用 IP 白名单和防火墙规则
前端 UI 配置 (.env)
位于 OmniCRM-UI 目录,此文件控制品牌、外观、集成和功能标志。
位置: /OmniCRM/OmniCRM-UI/.env
API 密钥和集成:
# Google Maps API (用于地址自动完成和地理编码)
REACT_APP_GOOGLE_API_KEY=your_google_api_key
# Stripe 支付网关
REACT_APP_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx
# 在 npm start 时禁用浏览器自动启动
BROWSER=none
品牌和公司信息:
# 公司品牌
REACT_APP_COMPANY_NAME="ShellFone"
REACT_APP_PORTAL_NAME="ShellManager"
REACT_APP_SELF_CARE_NAME="ShellCare"
REACT_APP_COMPANY_TAGLINE="Phones with Shells"
这些值在 UI 中的各个地方出现:
COMPANY_NAME- 显示在页面标题、电子邮件和客户通信中PORTAL_NAME- 管理员/员工门户的名称(例如,"ShellManager")SELF_CARE_NAME- 客户自助服务门户的名称(例如,"ShellCare")COMPANY_TAGLINE- 出现在登录屏幕和营销材料中
本地化和区域设置:
# 语言和区域
# 支持的语言:ar, ch, en, fr, gr, it, ru, sp
REACT_APP_DEFAULT_LANGUAGE=en
REACT_APP_LOCALE="en-GB"
# 默认位置 (用于地址自动完成)
REACT_APP_DEFAULT_LOCATION="Sydney, Australia"
REACT_APP_DEFAULT_COUNTRY="Australia"
# 货币设置
REACT_APP_CURRENCY_CODE="GBP"
REACT_APP_CURRENCY_SYMBOL="£"
颜色方案自定义:
# 主色 (主要品牌颜色)
REACT_APP_PRIMARY_COLOR=#405189
# 其他颜色选项 (注释示例)
# REACT_APP_SECONDARY_COLOR=#2bFFcf
# REACT_APP_TERTIARY_COLOR=#1a9fbf
# REACT_APP_SUCCESS_COLOR=#28a745
# REACT_APP_INFO_COLOR=#17a2b8
# REACT_APP_WARNING_COLOR=#ffc107
# REACT_APP_DANGER_COLOR=#dc3545
主色应用于:
- 导航标题
- 操作按钮
- 链接和高亮
- 活动状态
- 品牌元素
Web 应用集成:
配置最多 6 个快速访问的 Web 应用程序,这些应用程序出现在管理员仪表板中:
# Web 应用 1:GitHub
REACT_APP_WEB_APP_1_NAME="GitHub"
REACT_APP_WEB_APP_1_URL="https://github.com"
REACT_APP_WEB_APP_1_ICON_PATH="resources/webapp_icons/github.png"
# Web 应用 2:Xero
REACT_APP_WEB_APP_2_NAME="Xero"
REACT_APP_WEB_APP_2_URL="https://go.xero.com/"
REACT_APP_WEB_APP_2_ICON_PATH="resources/webapp_icons/xero.png"
# Web 应用 3-6:其他集成
# (类似配�� NAME、URL 和 ICON_PATH)
监控和分析:
# Grafana 仪表板集成
REACT_APP_GRAFANA_URLS=url1,url2,url3
REACT_APP_GRAFANA_LABELS=label1,label2,label3
REACT_APP_GRAFANA_API_KEY=your-api-key
功能标志:
# 支持和文档 URL
REACT_APP_FAQS_URL=https://docs.yourcompany.com/faqs
REACT_APP_SUPPORT_URL=https://support.yourcompany.com
# 社交登录 (Google、Facebook 等)
REACT_APP_ALLOW_SOCIAL_LOGINS=yes
徽标和启动图像自定义
OmniCRM 允许您用公司的徽标和启动屏幕替换默认的品牌图像,而无需修改代码。
徽标文件
徽标存储在 /OmniCRM-UI/src/assets/images/omnitouch/ 中,并使用回退系统:
默认徽标(始终存在):
DefaultLogoDark.png- 深色主题徽标(用于浅色背景)DefaultLogoLight.png- 浅色主题徽标(用于深色背景)
自定义徽标(可选,存在时优先):
logoSm.png- 用于折叠侧边栏的小徽标(推荐:100x100px)logoDark.png- 用于标题的全尺寸深色徽标(推荐:200x50px)logoLight.png- 用于身份验证屏幕的全尺寸浅色徽标(推荐:200x50px)
徽标回退工作原理:
系统首先尝试加载自定义徽标。如果自定义徽标文件不存在,则回退到���认:
// 来自 Header.js
const tryImport = (filename) => {
try {
return require(`../assets/images/omnitouch/${filename}`);
} catch (err) {
return null; // 回退到默认
}
};
const userLogoSm = tryImport("logoSm.png");
const userLogoDark = tryImport("logoDark.png");
const userLogoLight = tryImport("logoLight.png");
徽标出现的位置:
- logoSm.png - 折叠侧边栏、移动导航、小标题显示
- logoDark.png - 主标题栏(浅色模式)、管理员仪表板标题
- logoLight.png - 登录/注册屏幕、深色背景、身份验证轮播
替换徽标:
-
创建您的徽标文件:
- 使用 PNG 格式以支持透明度
- 符合上述推荐尺寸
- 确保徽标在常规和视网膜分辨率下清晰可见
-
添加到 OmniCRM:
# 将您的徽标文件复制到 omnitouch 图像目录
cp /path/to/your/logoSm.png OmniCRM-UI/src/assets/images/omnitouch/
cp /path/to/your/logoDark.png OmniCRM-UI/src/assets/images/omnitouch/
cp /path/to/your/logoLight.png OmniCRM-UI/src/assets/images/omnitouch/ -
重建 UI:
cd OmniCRM-UI
npm run build -
验证更改:
- 检查浅色模式标题(应��示
logoDark.png) - 检查深色模式标题(应显示
logoLight.png) - 检查折叠侧边栏(应显示
logoSm.png) - 检查登录屏幕(应显示
logoLight.png)
- 检查浅色模式标题(应��示
徽标设计最佳实践:
- 对比度 - 确保徽标在浅色和深色背景上都可见
- 简洁性 - 徽标在小尺寸下应易于识别
- 格式 - 使用带透明背景的 PNG
- 视网膜 - 为高 DPI 显示器提供 2 倍分辨率
- 一致性 - 在所有徽标变体中使用相同的品牌颜色
启动屏幕和身份验证背景
身份验证屏幕(登录、注册、密码重置)使用可自定义图像的轮播背景。
位置:
/OmniCRM-UI/src/pages/AuthenticationInner/authCarousel.js
默认配置:
import logoLight from "../../assets/images/logo-light.png";
// 在身份验证屏幕上显示的徽标
<img src={logoLight} alt="" height="18" />
自定义身份验证屏幕:
- 替换
/OmniCRM-UI/src/assets/images/中的logo-light.png - 将自定义背景 CSS 添加到
.auth-one-bg类 - 修改
authCarousel.js中的轮播引用,以匹配您的品牌语音
示例自定义:
/* 添加到您的自定义 CSS */
.auth-one-bg {
background-image: url('/assets/images/custom-auth-bg.jpg');
background-size: cover;
background-position: center;
}
CRM 配置文件 (crm_config.yaml)
crm_config.yaml 文件是 OmniCRM API 的中心配置,控制集成、供应、电子邮件模板和外部服务。
位置: /OmniCRM/OmniCRM-API/crm_config.yaml
数据库配置
database:
username: omnitouch
password: omnitouch2024
server: localhost
注意: 这应与您的 .env 数据库凭证匹配。在容器化部署中,服务器通常是 db(Docker 服务名称)。
服务类型
定义您部署的有效服务类型:
service_types:
- omnicharge
- mobile
- fixed
- fixed-voice
- hotspot
- dongle
这些在系统中用于:
- 产品分类
- 附加组件过滤(附加组件匹配服务类型)
- 供应工作流
- 报告和分析
HSS 集成(家庭用户服务器)
对于具有 HSS 集成的移动网络运营商:
hss:
hss_peers:
- 'http://10.179.2.140:8080'
apn_list: "1,2,3,4,5,6"
配置:
hss_peers- 用于用户供应的 HSS 端点列表apn_list- 可用于供应的 APN ID 的逗号分隔列表
Mailjet 电子邮件模板配置
OmniCRM 使用 Mailjet 发送事务性电子邮件。每种电子邮件类型都有自己的模���配置:
mailjet:
api_key: your_mailjet_api_key
api_secret: your_mailjet_api_secret
# 客户欢迎电子邮件
api_crmCommunicationCustomerWelcome:
from_email: "support@yourcompany.com"
from_name: "Your Company Support"
template_id: 5977509
subject: "Welcome to YourCompany"
# 客户发票电子邮件
api_crmCommunicationCustomerInvoice:
from_email: "billing@yourcompany.com"
from_name: "Your Company Billing"
template_id: 6759851
subject: "Your Invoice - "
# 发票提醒
api_crmCommunicationCustomerInvoiceReminder:
from_email: "billing@yourcompany.com"
from_name: "Your Company Billing"
template_id: 5977570
subject: "Invoice Payment Reminder"
# 用户欢迎电子邮件(员工/管理员)
api_crmCommunicationUserWelcome:
from_email: "admin@yourcompany.com"
from_name: "Your Company Admin"
template_id: 6118112
subject: "Welcome to the Team"
# 密码重置请求
api_crmCommunicationUserPasswordReset:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6735666
subject: "Password Reset Request"
# 密码重置成功确认
api_crmCommunicationUserPasswordResetSuccess:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6118378
subject: "Password Reset Successful"
# 密码更改通知
api_crmCommunicationUserPasswordChange:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6118423
subject: "Password Changed"
# 电子邮件验证
api_crmCommunicationEmailVerification:
from_email: "verify@yourcompany.com"
from_name: "Your Company Verification"
template_id: 6267350
subject: "Verify Your Email Address"
# 余额过期通知
api_crmCommunicationsBalanceExpired:
from_email: "alerts@yourcompany.com"
from_name: "Your Company Alerts"
template_id: 7238252
subject: "Service Balance Expired"
# 余额不足警告
api_crmCommunicationsBalanceLow:
from_email: "alerts@yourcompany.com"
from_name: "Your Company Alerts"
template_id: 7238263
subject: "Low Balance Warning"
创建 Mailjet 模板:
- 登录 Mailjet 仪表板 (<https://app.mailjet.com>)
- 导航到 Transactional → Templates
- 创建新模板或克隆现有模板
- 记下 模板 ID(数字值)
- 添加与 OmniCRM 数据结构匹配的模板变量
- 使用模板 ID 更新
crm_config.yaml
可用模板变量:
每种电子邮件类���接收特定变量。常见示例:
{{customer_name}}- 客户或用户姓名{{service_name}}- 服务或产品名称{{invoice_id}}- 发票编号{{invoice_amount}}- 发票总金额{{due_date}}- 付款截止日期{{reset_link}}- 密码重置 URL{{verification_link}}- 电子邮件验证 URL{{balance}}- 当前账户余额{{expiry_date}}- 余额或服务到期日期
供应配置
provisioning:
failure_list: ['admin@yourcompany.com', 'ops@yourcompany.com']
目的:
failure_list- 当 Ansible 供应失败时通知的电子邮件地址- 通知包括剧本名称、错误详细信息和客户信息
- 允许运维团队快速响应供应问题
发票配置
invoice:
template_filename: 'yourcompany_invoice_template.html'
目的:
指定用于 PDF 发票生成的 Jinja2 HTML 模板。
模板位置: /OmniCRM-API/invoice_templates/
有关创建自定义模板的详细信息,请参见 发票 PDF 生成 部分。
CRM 基础 URL
crm:
base_url: 'http://localhost:5000'
目的:
- 由 Ansible 剧本用于进行 API 回调
- 在电子邮件模板中用于生成指向 CRM 的链接
- 应为您 API 的公共可访问 URL(而不是内部容器名称)
示例:
- 开发:
http://localhost:5000 - 生产:
https://api.yourcompany.com - Docker:
http://omnicrm-api:5000(内部容器通信)
OCS 和 CGRates 配置
ocs:
ocsApi: 'http://10.179.2.142:8080/api'
ocsTenant: 'mnc380.mcc313.3gppnetwork.org'
cgrates: 'localhost:2080'
配置:
ocsApi- 用于用户管理的 OCS API 端点ocsTenant- 多租户 OCS 部署的租户标识符cgrates- CGRates JSON-RPC API 端点(主机:端口)
SMSC 配置 (SMS 网关)
smsc:
source_msisdn: 'YourCompany'
smsc_url: 'http://10.179.2.216/SMSc/'
api_key: 'your_smsc_api_key'
目的:
- 向客户发送 SMS 通知(余额不足、服务警报、2FA 代码)
source_msisdn- 显示给收件人的发件人 ID(字母数字或电话号码)smsc_url- SMSC 网关 API 端点api_key- SMSC API 的身份验证
JWT 密钥
jwt_secret: '2b93110f723db60172c8e9a1eaa80027a9a9c3f05b44e50dc3fcf38dba68d87e'
安全性:
- 用于签名和验证身份验证令牌
- 在生产中必须更改默认值
- 生成一个安全的随机字符串(至少 64 个字符)
- 切勿共享或提交到版本控制
生成新 JWT 密钥:
# 生成一个加密安全的随机密钥
python3 -c "import secrets; print(secrets.token_hex(32))"
Stripe 支付配置
stripe:
secret_key: 'sk_live_xxxxxxxxxx'
publishable_key: 'pk_live_xxxxxxxxxx'
currency: 'aud'
statement_descriptor_suffix: 'YOURCOMPANY'
配置:
secret_key- Stripe 秘密 API 密钥(服务器端,保密)publishable_key- Stripe 可发布密钥(客户端,安全暴露)currency- ISO 4217 货币代码(aud、usd、gbp、eur 等)statement_descriptor_suffix- 出现在客户信用卡对账单上的内容
对账单描述符的使用:
- 在客户银行对账单上显示为 "YOURCOMPANY"
- 最大 22 个字符
- 帮助客户识别费用
- 也用于发票 PDF 文件名(例如,
YOURCOMPANY_12345.pdf)
API 密钥和 IP 白名单
定义具有基于角色的访问和 IP 限制的 API 密钥:
api_keys:
"YOUR_API_KEY_1":
roles: ["admin"]
ips: ["127.0.0.1", "::1"]
"YOUR_API_KEY_2":
roles: ["customer_service_agent_1"]
ips: ["127.0.0.1", "::1", "10.0.1.0/24"]
# IP 白名单(独立,无需 API 密钥)
ip_whitelist:
"10.179.2.142":
roles: ["admin"]
目的:
- 允许外部系统通过 API 密钥进行身份验证
- 按 IP 地址限制访问
- 授予 API 消费者特定角色
- 对于集成(计费系统、监控、自动化)非常有用
安全最佳实践:
- 使用长且随机的 API 密钥(至少 32 个字符)
- 将 IP 限制为已知来源
- 授予最低必要���色
- 定期轮换 API 密钥
- 在日志中监控 API 密钥使用情况
发票 PDF 生成
OmniCRM 使用 Jinja2 HTML 模板和 WeasyPrint PDF 渲染生成专业的 PDF 发票。
PDF 生成工作原理
- 模板选择:
- 模板文件名在
crm_config.yaml中的invoice.template_filename下指定 - 模板从
/OmniCRM-API/invoice_templates/目录加载
- 模板文件名在
- 数据准备:
- 从数据库获取发票数据(ID、日期、金额、状态)
- 检索客户信息(姓名、地址)
- 编译交易列表(发票上的所有费用/信用)
- 模板渲染:
- Jinja2 使用发票数据渲染 HTML 模板
- 像
{{ invoice_number }}、{{ total_amount }}等变量被替换 - 渲染的 HTML 保存到
invoice_templates/rendered/以便调试
- PDF 生成:
- WeasyPrint 将渲染的 HTML 转换为 PDF
- PDF 支持 CSS 样式、图像、分页、页眉/页脚
- PDF 二进制数据在内存中生成
- 缓存:
- PDF 被 Base64 编码并存储在
Invoice_PDF_Cache表中 - 计算 SHA256 哈希以进行完整性验证
- 随后请求返回缓存的 PDF(即时交付)
- PDF 被 Base64 编码并存储在
- 缓存失效:
- 当发票被修改、作废或退款时,缓存失效
- 模板更改不会自动使现有缓存失效
发票模板结构
发票模板是带有嵌入变量和逻辑的 Jinja2 HTML 文件。
模板位置:
/OmniCRM-API/invoice_templates/yourcompany_invoice_template.html
可用变量:
{
'invoice_number': 12345,
'date': '2025-01-04',
'client': {
'name': 'John Smith',
'address': {
'address_line_1': '123 Main St',
'city': 'Sydney',
'state': 'NSW',
'zip_code': '2000',
'country': 'Australia'
}
},
'transaction_list': [
[
{
'transaction_id': 1,
'title': 'Mobile Service - Monthly Fee',
'retail_cost': 30.00,
'wholesale_cost': 10.00,
'created': '2025-01-01'
},
{
'transaction_id': 2,
'title': 'Data Addon - 5GB',
'retail_cost': 15.00,
'wholesale_cost': 5.00,
'created': '2025-01-15'
}
]
],
'total_amount': 45.00,
'due_date': '2025-01-31',
'start_date': '2025-01-01',
'end_date': '2025-01-31',
'paid': False,
'void': False
}
示例模板片段:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Invoice {{ invoice_number }}</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.invoice-details {
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
th {
background-color: #405189;
color: white;
}
.total {
text-align: right;
font-size: 18px;
font-weight: bold;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="header">
<img src="file:///path/to/logo.png" alt="Company Logo" height="60">
<h1>INVOICE</h1>
</div>
<div class="invoice-details">
<p><strong>Invoice Number:</strong> {{ invoice_number }}</p>
<p><strong>Date:</strong> {{ date }}</p>
<p><strong>Due Date:</strong> {{ due_date }}</p>
<p><strong>Billing Period:</strong> {{ start_date }} to {{ end_date }}</p>
</div>
<div class="customer-details">
<h3>Bill To:</h3>
<p>{{ client.name }}</p>
<p>{{ client.address.address_line_1 }}</p>
<p>{{ client.address.city }}, {{ client.address.state }} {{ client.address.zip_code }}</p>
<p>{{ client.address.country }}</p>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Date</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{% for transaction in transaction_list[0] %}
<tr>
<td>{{ transaction.title }}</td>
<td>{{ transaction.created }}</td>
<td>${{ "%.2f"|format(transaction.retail_cost) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="total">
<p>Total Amount Due: ${{ "%.2f"|format(total_amount) }}</p>
</div>
{% if paid %}
<div style="text-align: center; color: green; font-weight: bold;">
PAID
</div>
{% endif %}
{% if void %}
<div style="text-align: center; color: red; font-weight: bold;">
VOID
</div>
{% endif %}
</body>
</html>
模板最佳实践:
- 使用绝对路径的图像 -
file:///absolute/path/to/image.png - 内联 CSS - WeasyPrint 不可靠地加载外部样式表
- 使用示例数据进行测试 - 使用
invoice_templates/rendered/检查 HTML - 分页 - 使用
<div style="page-break-after: always;"></div>处理多页发票 - 页眉和页脚 - 使用
@pageCSS 规则处理重复元素 - 货币格式化 - 使用 Jinja2 过滤器:
{{ "%.2f"|format(amount) }}
创建自定义发票模板
-
复制示例模板:
cd /OmniCRM/OmniCRM-API/invoice_templates
cp norfone_invoice_template.html yourcompany_invoice_template.html -
编辑模板:
- 替换公司名称、徽标、联系信息
- 调整样式(颜色、字体、布局)以匹配品牌
- 根据需要添加或删除部分(税收明细、付款说明等)
-
更新配置:
编辑
crm_config.yaml:invoice:
template_filename: 'yourcompany_invoice_template.html' -
测试发票生成:
- 在 CRM 中创建测试发票
- 下载 PDF 并验证格式
- 检查
invoice_templates/rendered/{invoice_id}.html以便调试
-
使旧缓存失效(如有需要):
如果您已更改模板并希望重新生成现有发票:
-- 清除所有缓存的 PDF(强制重新生成)
DELETE FROM Invoice_PDF_Cache;
PDF 缓存系统
为了提高性能,OmniCRM 缓存生成的 PDF:
缓存行为:
- 第一次请求 - 生成 PDF,缓存并返回
- 后续请求 - 立即返回缓存的 PDF(无需重新生成)
- 缓存失效 - 当发票被修改、作废或退款时发生
- 缓存清理 - 旧缓存在 30 天不活动后自动清除
缓存存储:
- Base64 编码的 PDF 存储在
Invoice_PDF_Cache表中 - 用于完整性验证的 SHA256 内容哈希
- 包括文件名、创建时间戳、最后访问时间戳
手动缓存管理:
# 在 OmniCRM API 或 Python shell 中
from services.invoice_service import cleanup_old_pdf_cache, invalidate_invoice_cache
from utils.db_helpers import get_db_session
session = get_db_session()
# 清理超过 30 天的缓存
result = cleanup_old_pdf_cache(session, days_old=30)
print(result) # {'status': 'success', 'deleted_count': 15}
# 使特定发票缓存失效
invalidate_invoice_cache(session, invoice_id='12345')
API 端点:
生成/下载发票 PDF:
GET /invoice/pdf/{invoice_id}
响应: PDF 文件下载,文件名来自 Stripe 对账单描述符
缓存头:
- 第一次请求:响应较慢(生成时间)
- 缓存请求:即时响应
- 缓存命��/未命中对用户是透明的
故障排除
PDF 生成失败:
- 检查 WeasyPrint 是否已安装:
pip install weasyprint - 验证模板文件名是否与
crm_config.yaml匹配 - 检查
invoice_templates/rendered/以获取 HTML 渲染错误 - 查看 API 日志以获取 Jinja2 模板错误
PDF 中未出现图像:
- 使用绝对文件路径:
file:///full/path/to/image.png - 确保图像文件存在且可读
- 检查图像格式(PNG 和 JPEG 效果最佳)
- 验证图像路径中不包含特殊字符
样式问题:
- 所有 CSS 内联(不支持外部样式表)
- 避免复杂的 CSS 特性(flexbox、grid 可能无法正确渲染)
- 首先测试简单布局,逐渐增加复杂性
- 尽可能使用表格进行布局,而不是 div
缓存未失效:
- 验证在发票修改时是否调用
invalidate_invoice_cache() - 检查交易更新是否触发缓存失效
- 如有需要,手动从
Invoice_PDF_Cache表中删除
配置检查清单
在部署 OmniCRM 时使用此检查清单:
后端配置
- [ ] 复制
.env.example到.env - [ ] 设置强大的数据库密码
- [ ] 配置 CGRates 凭证
- [ ] 使用您的设置更新
crm_config.yaml:- [ ] 数据库连接
- [ ] 服务类型
- [ ] Mailjet API 密钥和模板 ID
- [ ] 供应失败通知电子邮件
- [ ] 发票模板文件名
- [ ] CRM 基础 URL(公共可访问)
- [ ] OCS/CGRates 端点
- [ ] SMSC 配置
- [ ] 生成新的 JWT 密钥
- [ ] Stripe 密钥(生产,不是测试)
- [ ] API 密钥和 IP 白名单
前端配置
- [ ] 复制
OmniCRM-UI/.env.example到OmniCRM-UI/.env - [ ] 设置 Google Maps API 密钥
- [ ] 设置 Stripe 可发布密钥
- [ ] 更新公司品牌:
- [ ] 公司名称
- [ ] 门户名称
- [ ] 自助服务名称
- [ ] 公司标语
- [ ] 配置本地化:
- [ ] 默认语言
- [ ] 区域
- [ ] 默认位置和国家
- [ ] 货币代码和符号
- [ ] 设置主要品牌颜色
- [ ] 配置 Web 应用集成(可选)
- [ ] 添加支持和常见问题 URL(可选)
品牌资产
- [ ] 创建徽标文件(logoSm.png、logoDark.png、logoLight.png)
- [ ] 将徽标上传到
OmniCRM-UI/src/assets/images/omnitouch/ - [ ] 创建自定义发票模板 HTML
- [ ] 将发票模板上传到
OmniCRM-API/invoice_templates/ - [ ] ��用发票模板文件名更新
crm_config.yaml - [ ] 测试发票 PDF 生成
- [ ] 重建 UI:
npm run build
安全
- [ ] 更改所有默认密码
- [ ] 生成唯一的 JWT 密钥
- [ ] 使用生产 Stripe 密钥(不是测试密钥)
- [ ] 轮换 Mailjet API 密钥
- [ ] 启用防火墙规则
- [ ] 配置 API 访问的 IP 白名单
- [ ] 设置 SSL/TLS 证书
- [ ] 为所有端点启用 HTTPS
- [ ] 审查 CORS 设置
- [ ] 实施速率限制
- [ ] 配置备份和恢复程序
测试
- [ ] 测试客户注册流程
- [ ] 测试服务供应的端到端
- [ ] 验证电子邮件通知是否正确发送
- [ ] 测试发票生成和 PDF 下载
- [ ] 验证支付处理(Stripe)
- [ ] 检查用户身份验证和 2FA
- [ ] 测试冒充和审计日志
- [ ] 验证 OCS 的使用数据同步
- [ ] 测试 ActionPlan 创建和续订
- [ ] 确认库存分配正常工作
部署
- [ ] 构建 Docker 镜像或部署到服务器
- [ ] 启动数据库容器(MySQL、PostgreSQL)
- [ ] 启动 CGRates
- [ ] 启动 OmniCRM API
- [ ] 启动 OmniCRM UI
- [ ] 配置反向代理(nginx、traefik)
- [ ] 设置监控(Grafana、Prometheus)
- [ ] 配置日志聚合
- [ ] 设置自动备份
- [ ] 文档部署架构
- [ ] 培训员工使用系统