dingdanquanliucheng/backend/app/services/bootstrap.py
wsb1224 ea1c5a7835 fix: salesman角色添加order:update权限,修复修改物流单号403问题
业务员修改物流单号时PUT /api/orders/{id}/tracking返回403,
根因是salesman角色缺少order:update权限码。在DEFAULT_ROLE_PERMISSIONS、
DEFAULT_ROLE_MENU_CODES和DEFAULT_MENUS三处同步补全。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-06 14:31:43 +08:00

232 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
系统引导数据定义模块。
职责:
定义系统首次初始化时需要写入数据库的基础数据,包括默认角色、系统配置、
产品分类、菜单权限、管理员账号以及角色-菜单映射关系。
这些数据在系统启动的 bootstrap 阶段被写入数据库,作为系统运行的基础。
依赖:
本模块为纯数据定义模块,无外部依赖。
被引用方:
- bootstrap_data.py 脚本:系统初始化时读取并写入数据库
- ConfigService读取 DEFAULT_CONFIGS 作为配置回退默认值
"""
# ---------------------------------------------------------------------------
# 默认角色列表
# ---------------------------------------------------------------------------
DEFAULT_ROLES = [
{"role_name": "管理员", "role_code": "admin", "status": 1, "remark": "系统管理"},
{"role_name": "业务员", "role_code": "salesman", "status": 1, "remark": "录单和本人订单"},
{"role_name": "管理层", "role_code": "manager", "status": 1, "remark": "审批和经营数据"},
{"role_name": "司机", "role_code": "driver", "status": 1, "remark": "司机任务执行"},
{"role_name": "会计", "role_code": "kuaiji", "status": 1, "remark": "财务和报表"},
{"role_name": "物流", "role_code": "wuliu", "status": 1, "remark": "物流管理"},
]
# ---------------------------------------------------------------------------
# 默认系统配置列表
# ---------------------------------------------------------------------------
DEFAULT_CONFIGS = [
{"config_key": "arrears_generate_mode", "config_value": "pending_logistics", "config_name": "欠款生成模式", "remark": "shipped=发货后记账pending_logistics=待绑定物流单号后记账", "status": 1},
{"config_key": "arrears_settlement_start_type", "config_value": "order_date", "config_name": "欠款起算节点", "remark": "order_date=订单日期delivery_date=发货日期reconciliation_date=对账日期", "status": 1},
{"config_key": "arrears_overdue_days", "config_value": "30", "config_name": "欠款超期天数", "remark": "超过该天数未结算触发欠款提醒", "status": 1},
{"config_key": "logistics_timeout_hours", "config_value": "48", "config_name": "物流超时小时数", "remark": "首个物流节点超过该小时数无流转提醒", "status": 1},
{"config_key": "inactive_customer_days", "config_value": "90", "config_name": "沉默客户周期", "remark": "超过该天数未下单触发检查", "status": 1},
{"config_key": "inactive_customer_amount_threshold", "config_value": "1000", "config_name": "沉默客户金额阈值", "remark": "低于该金额不提醒", "status": 1},
{"config_key": "reminder_method", "config_value": "system", "config_name": "提醒方式", "remark": "system=系统通知wechat=微信订阅消息sms=短信", "status": 1},
{"config_key": "profit_alert_threshold", "config_value": "0", "config_name": "利润预警阈值", "remark": "利润率低于该值时审批页面标红预警0=不预警", "status": 1},
{"config_key": "allow_cancel_statuses", "config_value": "draft,pending_approve,approved,pending_driver,accepted,picked_up,pending_logistics,in_transit,shipped", "config_name": "允许取消的订单状态", "remark": "逗号分隔的状态编码列表", "status": 1},
{"config_key": "report_category_mapping", "config_value": "{}", "config_name": "报表分类映射", "remark": "按产品分类配置统计口径", "status": 1},
{"config_key": "logistics_trace_provider", "config_value": "internal", "config_name": "物流轨迹服务商", "remark": "internal=内置kuaidi100或kdniao=快递100", "status": 1},
{"config_key": "wechat_template_order_status", "config_value": "TkCDtUd1d2MPzMMy_QwvaoHxvweBY-uA9p3jk3nsKi0", "config_name": "微信模板-订单状态变更", "remark": "微信小程序订阅消息模板ID", "status": 1},
{"config_key": "wechat_template_approval", "config_value": "xNlOt-_6jMTh5VKf9F_pX4aMtwpjXZKUBBTp8QtzTag", "config_name": "微信模板-审批通知", "remark": "微信小程序订阅消息模板ID", "status": 1},
{"config_key": "wechat_template_task_assigned", "config_value": "uzivHUxL1A3cBguMvC6HDO4aXqvmCV8X3o538SpDEX4", "config_name": "微信模板-任务分配", "remark": "微信小程序订阅消息模板ID", "status": 1},
{"config_key": "wechat_template_logistics_timeout", "config_value": "1NtPbIS_LtmsJhl4V4V3poWO_EZYYFNbKoLzO1TLTDc", "config_name": "微信模板-物流超时", "remark": "微信小程序订阅消息模板ID", "status": 1},
{"config_key": "wechat_template_arrears", "config_value": "ulYRf4HgTXNWYSqT0KYVKJiHnG19_12tjcDXMYD2kHo", "config_name": "微信模板-欠款提醒", "remark": "微信小程序订阅消息模板ID", "status": 1},
{"config_key": "wechat_template_inactive_customer", "config_value": "pWYFYbZNJvnOGD-4ycNf8zxmseIiuogFAXa9biVscBc", "config_name": "微信模板-沉默客户", "remark": "微信小程序订阅消息模板ID", "status": 1},
{"config_key": "wechat_sa_template_order_status", "config_value": "", "config_name": "服务号模板-订单状态变更", "remark": "微信服务号模板消息模板ID", "status": 1},
{"config_key": "wechat_sa_template_approval", "config_value": "", "config_name": "服务号模板-审批通知", "remark": "微信服务号模板消息模板ID", "status": 1},
{"config_key": "wechat_sa_template_task_assigned", "config_value": "", "config_name": "服务号模板-任务分配", "remark": "微信服务号模板消息模板ID", "status": 1},
{"config_key": "wechat_sa_template_logistics_timeout", "config_value": "", "config_name": "服务号模板-物流超时", "remark": "微信服务号模板消息模板ID", "status": 1},
{"config_key": "wechat_sa_template_arrears", "config_value": "", "config_name": "服务号模板-欠款提醒", "remark": "微信服务号模板消息模板ID", "status": 1},
{"config_key": "wechat_sa_template_inactive_customer", "config_value": "", "config_name": "服务号模板-沉默客户", "remark": "微信服务号模板消息模板ID", "status": 1},
{"config_key": "payment_channels", "config_value": '[{"name":"现金","is_ecommerce":false},{"name":"银行转账","is_ecommerce":false},{"name":"微信","is_ecommerce":false},{"name":"支付宝","is_ecommerce":false},{"name":"月结","is_ecommerce":false},{"name":"淘宝","is_ecommerce":true},{"name":"京东","is_ecommerce":true},{"name":"拼多多","is_ecommerce":true},{"name":"抖音","is_ecommerce":true}]', "config_name": "收款渠道配置", "remark": "JSON数组每个渠道包含name和is_ecommerce字段", "status": 1},
]
# ---------------------------------------------------------------------------
# 默认产品分类列表
# ---------------------------------------------------------------------------
DEFAULT_CATEGORIES = [
{"category_name": "工业品", "category_code": "industry", "sort_no": 1, "status": 1, "remark": "默认分类"},
{"category_name": "日用品", "category_code": "daily", "sort_no": 2, "status": 1, "remark": "默认分类"},
]
# ---------------------------------------------------------------------------
# 默认菜单及权限列表
# 包含页面菜单page和按钮权限button两类
# 通过 parent_id 建立父子层级关系。
# 仅包含 web-admin 后台管理系统的页面菜单。
# ---------------------------------------------------------------------------
DEFAULT_MENUS = [
# 工作台
{"id": 1, "parent_id": 0, "menu_name": "后台首页", "menu_path": "/dashboard", "menu_type": "page", "permission_code": "dashboard:view", "icon": "dashboard", "sort_no": 1, "status": 1},
# 主数据
{"id": 2, "parent_id": 0, "menu_name": "客户管理", "menu_path": "/customers", "menu_type": "page", "permission_code": "customer:list", "icon": "customers", "sort_no": 2, "status": 1},
{"id": 3, "parent_id": 0, "menu_name": "基础资料", "menu_path": "/master-data", "menu_type": "page", "permission_code": "master-data:list", "icon": "master-data", "sort_no": 3, "status": 1},
{"id": 4, "parent_id": 0, "menu_name": "定价规则", "menu_path": "/pricing-rules", "menu_type": "page", "permission_code": "pricing-rules:view", "icon": "pricing-rules", "sort_no": 4, "status": 1},
# 订单与审批
{"id": 5, "parent_id": 0, "menu_name": "订单中心", "menu_path": "/orders", "menu_type": "page", "permission_code": "order:list", "icon": "orders", "sort_no": 5, "status": 1},
{"id": 6, "parent_id": 0, "menu_name": "创建订单", "menu_path": "/orders/create", "menu_type": "page", "permission_code": "order:create", "icon": "order-create", "sort_no": 6, "status": 1},
{"id": 7, "parent_id": 0, "menu_name": "批量匹配物流", "menu_path": "/orders/batch-match", "menu_type": "page", "permission_code": "order:batch-match", "icon": "batch-match", "sort_no": 7, "status": 1},
{"id": 8, "parent_id": 0, "menu_name": "提醒中心", "menu_path": "/reminders", "menu_type": "page", "permission_code": "reminder:list", "icon": "reminder", "sort_no": 8, "status": 1},
# 配置与权限
{"id": 9, "parent_id": 0, "menu_name": "配置管理", "menu_path": "/config", "menu_type": "page", "permission_code": "config:view", "icon": "config", "sort_no": 9, "status": 1},
{"id": 10, "parent_id": 0, "menu_name": "权限与审计", "menu_path": "/audit", "menu_type": "page", "permission_code": "audit:view", "icon": "audit", "sort_no": 10, "status": 1},
{"id": 11, "parent_id": 0, "menu_name": "系统管理", "menu_path": "/system", "menu_type": "page", "permission_code": "system:view", "icon": "system", "sort_no": 11, "status": 1},
# 报表
{"id": 12, "parent_id": 0, "menu_name": "报表统计", "menu_path": "/reports/performance", "menu_type": "page", "permission_code": "report:performance:view", "icon": "report", "sort_no": 12, "status": 1},
{"id": 13, "parent_id": 0, "menu_name": "报表核对", "menu_path": "/reports/audit", "menu_type": "page", "permission_code": "report:audit:view", "icon": "report-audit", "sort_no": 13, "status": 1},
# AI 功能
{"id": 14, "parent_id": 0, "menu_name": "AI识别", "menu_path": "/ai-recognition", "menu_type": "page", "permission_code": "ai:recognize", "icon": "ai", "sort_no": 14, "status": 1},
# 按钮权限 - 订单相关
{"id": 20, "parent_id": 5, "menu_name": "提交审核", "menu_path": "", "menu_type": "button", "permission_code": "order:submit", "icon": "", "sort_no": 20, "status": 1},
{"id": 21, "parent_id": 5, "menu_name": "取消审批", "menu_path": "", "menu_type": "button", "permission_code": "order:cancel-approve", "icon": "", "sort_no": 21, "status": 1},
{"id": 24, "parent_id": 5, "menu_name": "订单更新", "menu_path": "", "menu_type": "button", "permission_code": "order:update", "icon": "", "sort_no": 24, "status": 1},
# 按钮权限 - 基础资料
{"id": 22, "parent_id": 3, "menu_name": "定价规则编辑", "menu_path": "", "menu_type": "button", "permission_code": "master-data:update", "icon": "", "sort_no": 22, "status": 1},
# 按钮权限 - 报表
{"id": 23, "parent_id": 12, "menu_name": "导出业绩报表", "menu_path": "", "menu_type": "button", "permission_code": "report:performance:export", "icon": "", "sort_no": 23, "status": 1},
# 按钮权限 - AI
{"id": 24, "parent_id": 14, "menu_name": "AI结果修正", "menu_path": "", "menu_type": "button", "permission_code": "ai:correct", "icon": "", "sort_no": 24, "status": 1},
{"id": 25, "parent_id": 14, "menu_name": "AI订单解析", "menu_path": "", "menu_type": "button", "permission_code": "ai:parse-order", "icon": "", "sort_no": 25, "status": 1},
# 按钮权限 - 系统管理
{"id": 30, "parent_id": 11, "menu_name": "用户列表", "menu_path": "", "menu_type": "button", "permission_code": "system:user:list", "icon": "", "sort_no": 30, "status": 1},
{"id": 31, "parent_id": 11, "menu_name": "角色管理", "menu_path": "", "menu_type": "button", "permission_code": "system:role:list", "icon": "", "sort_no": 31, "status": 1},
{"id": 32, "parent_id": 11, "menu_name": "菜单管理", "menu_path": "", "menu_type": "button", "permission_code": "system:menu:list", "icon": "", "sort_no": 32, "status": 1},
{"id": 33, "parent_id": 11, "menu_name": "用户新增", "menu_path": "", "menu_type": "button", "permission_code": "system:user:create", "icon": "", "sort_no": 33, "status": 1},
{"id": 34, "parent_id": 11, "menu_name": "用户编辑", "menu_path": "", "menu_type": "button", "permission_code": "system:user:update", "icon": "", "sort_no": 34, "status": 1},
{"id": 35, "parent_id": 11, "menu_name": "用户重置密码", "menu_path": "", "menu_type": "button", "permission_code": "system:user:reset-password", "icon": "", "sort_no": 35, "status": 1},
{"id": 36, "parent_id": 11, "menu_name": "角色新增", "menu_path": "", "menu_type": "button", "permission_code": "system:role:create", "icon": "", "sort_no": 36, "status": 1},
{"id": 37, "parent_id": 11, "menu_name": "角色编辑", "menu_path": "", "menu_type": "button", "permission_code": "system:role:update", "icon": "", "sort_no": 37, "status": 1},
{"id": 38, "parent_id": 11, "menu_name": "角色授权", "menu_path": "", "menu_type": "button", "permission_code": "system:role:assign-menus", "icon": "", "sort_no": 38, "status": 1},
{"id": 39, "parent_id": 11, "menu_name": "菜单新增", "menu_path": "", "menu_type": "button", "permission_code": "system:menu:create", "icon": "", "sort_no": 39, "status": 1},
{"id": 40, "parent_id": 11, "menu_name": "菜单编辑", "menu_path": "", "menu_type": "button", "permission_code": "system:menu:update", "icon": "", "sort_no": 40, "status": 1},
]
# ---------------------------------------------------------------------------
# 默认管理员账号
# ---------------------------------------------------------------------------
DEFAULT_ADMIN_USER = {
"username": "admin01",
"real_name": "系统管理员",
"mobile": "13900000001",
"role_id": 1,
"status": 1,
}
# ---------------------------------------------------------------------------
# 默认业务员账号
# ---------------------------------------------------------------------------
DEFAULT_SALES_USER = {
"username": "sales01",
"real_name": "业务员A",
"mobile": "13800000002",
"role_id": 2,
"status": 1,
}
# ---------------------------------------------------------------------------
# 角色-菜单权限编码映射
# 定义每个角色拥有的权限编码列表bootstrap 阶段用于初始化角色授权关系。
# ---------------------------------------------------------------------------
DEFAULT_ROLE_MENU_CODES = {
"admin": [item["permission_code"] for item in DEFAULT_MENUS],
"salesman": [
"order:list",
"order:create",
"order:submit",
"order:update",
"customer:list",
"reminder:list",
"ai:parse-order",
"logistics:trace:list",
],
"manager": [
"order:list",
"order:create",
"order:submit",
"order:cancel-approve",
"customer:list",
"reminder:list",
"report:performance:view",
"report:performance:export",
"ai:recognize",
"ai:correct",
"ai:parse-order",
],
"driver": [],
"kuaiji": [
"dashboard:view",
"order:list",
"customer:list",
"report:performance:view",
"report:performance:export",
"report:audit:view",
"config:view",
],
"wuliu": [
"dashboard:view",
"order:list",
"order:create",
"order:batch-match",
"customer:list",
"ai:parse-order",
"reminder:list",
"config:view",
],
}
def build_bootstrap_summary() -> dict:
"""汇总所有引导数据,返回一个完整的 bootstrap 数据包。
将默认角色、系统配置、产品分类、菜单权限、角色-菜单映射和管理员账号
整合到一个字典中,供 bootstrap 脚本或系统初始化流程一次性写入数据库。
返回:
dict: 包含 roles、configs、categories、menus、role_menu_codes、
admin_user 六个键的字典
被调用方:
- bootstrap_data.py 脚本(系统初始化时调用)
"""
return {
"roles": DEFAULT_ROLES,
"configs": DEFAULT_CONFIGS,
"categories": DEFAULT_CATEGORIES,
"menus": DEFAULT_MENUS,
"role_menu_codes": DEFAULT_ROLE_MENU_CODES,
"admin_user": DEFAULT_ADMIN_USER,
"sales_user": DEFAULT_SALES_USER,
}