You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

136 lines
8.1 KiB

# -*- coding: utf-8 -*-
"""第3批:新建商机(2)+ 状态流转(11)"""
import io, sys
sys.path.insert(0, 'D:/code/crm-backend-matt/.scratch')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
from bru_lib import write_bru, bru_form, build_docs, env_json, req_form_example, req_query_example
# ── 新建商机 ─────────────────────────────────────────────────────────
print('== 新建商机 ==')
CREATE_PARAMS = [
('oppName', 'string', '', '-', '商机名称'),
('oppSource', 'string', '', '-', '商机来源字典 code'),
('oppType', 'string', '', '-', '商机类型字典 code'),
('industryCode', 'string', '', '-', '行业字典 code'),
('bidForm', 'string', '', '-', '招标形式字典 code'),
('localityType', 'string', '', '-', '项目属地字典 code'),
('partyAClear', 'number', '', '0', '甲方是否明确:1是 0否'),
('partyA', 'string', '', '-', '甲方名称(partyAClear=1 时建议填)'),
('provinceCode', 'string', '', '-', '省份国标 code'),
('cityCode', 'string', '', '-', '市/区国标 code'),
('projectAmount', 'number', '', '-', '预计项目金额'),
('ownerUserId', 'string', '', '-', '负责人用户 ID(不传则默认当前登录人)'),
('sourceLeadId', 'string', '', '-', '来源线索 ID(从线索转商机时带入)'),
('primaryCustomerId','string','','-', '主要意向客户 ID'),
('remark', 'string', '', '-', '备注'),
]
CREATE_KV = [
('oppName','示例商机'),('oppSource','source_01'),('oppType','type_01'),
('industryCode','ind_01'),('projectAmount','1000000'),('primaryCustomerId','1'),
]
docs = build_docs(
'新建商机', 'POST', '/api/opportunity',
'顶部「新建商机」按钮弹窗「确认」触发。新建后商机初始状态由系统判断:若当前用户有领取权限则直接进入「推进中」,否则进入「待领取」公海池。\n'
'阶段模板绑定:按负责人部门匹配发布中模板版本自动绑定(不传 ownerUserId 按当前用户部门)。',
CREATE_PARAMS,
req_form_example('POST', '/api/opportunity', CREATE_KV),
'新建商机 ID(Long,序列化为 string)',
env_json('"1"'),
)
write_bru('商机模块/新建商机', '新建商机.bru', bru_form(1, '新建商机', 'post', '/api/opportunity', CREATE_KV, docs))
docs = build_docs(
'可关联线索下拉', 'GET', '/api/opportunity/convertible-leads',
'新建商机弹窗「来源线索」下拉数据源:返回当前用户可关联的线索列表(已转商机的线索不再出现)。',
[],
req_query_example('GET', '/api/opportunity/convertible-leads', []),
[('id','string','线索 ID'),('leadName','string','线索名称'),('phone','string','联系电话(脱敏)')],
env_json('[\n {"id":"1","leadName":"示例线索","phone":"138****0001"}\n ]'),
)
write_bru('商机模块/新建商机', '可关联线索下拉.bru', bru_form(2, '可关联线索下拉', 'get', '/api/opportunity/convertible-leads', [], docs))
# ── 状态流转 ──────────────────────────────────────────────────────────
print('== 状态流转 ==')
def null_post(seq, name, path, params, kv, desc):
d = build_docs(name, 'POST', path, desc, params,
req_form_example('POST', path, kv), None, env_json('null'))
write_bru('商机模块/状态流转', f'{name}.bru', bru_form(seq, name, 'post', path, kv, d))
null_post(1, '领取商机', '/api/opportunity/claim',
[('id','string','','-','商机 ID'),
('ownerNameSnapshot','string','','-','领取人姓名快照(冗余存储防后续改名)'),
('ownerDeptId','string','','-','领取人部门 ID')],
[('id','1'),('ownerNameSnapshot','张三'),('ownerDeptId','1')],
'公海池商机「领取」(E1):`oppStatus: 1待领取 → 2推进中`,写入领取人快照,绑定阶段模板。')
null_post(2, '批量领取', '/api/opportunity/claim-batch',
[('ids','string','','-','商机 ID 列表,逗号分隔'),
('ownerNameSnapshot','string','','-','领取人姓名快照'),
('ownerDeptId','string','','-','领取人部门 ID')],
[('ids','1,2'),('ownerNameSnapshot','张三'),('ownerDeptId','1')],
'批量领取:逐条执行领取逻辑,每条成功/失败独立记录;返回 null 前端轮询刷新列表。')
null_post(3, '分配商机', '/api/opportunity/assign',
[('id','string','','-','商机 ID'),
('toUserId','string','','-','被分配人用户 ID'),
('toUserNameSnapshot','string','','-','被分配人姓名快照'),
('toDeptId','string','','-','被分配人部门 ID')],
[('id','1'),('toUserId','2'),('toUserNameSnapshot','李四'),('toDeptId','1')],
'管理员分配商机(E2):公海或推进中商机均可分配,负责人变更,记操作日志。')
null_post(4, '批量分配', '/api/opportunity/assign-batch',
[('ids','string','','-','商机 ID 列表,逗号分隔'),
('toUserId','string','','-','被分配人用户 ID'),
('toUserNameSnapshot','string','','-','被分配人姓名快照'),
('toDeptId','string','','-','被分配人部门 ID')],
[('ids','1,2'),('toUserId','2'),('toUserNameSnapshot','李四'),('toDeptId','1')],
'批量分配:逐条执行分配逻辑,独立成功/失败。')
null_post(5, '抛公海', '/api/opportunity/release-pool',
[('id','string','','-','商机 ID'),
('poolReason','string','','-','进入公海原因字典 code')],
[('id','1'),('poolReason','reason_01')],
'手动抛公海(E3):`oppStatus: 2推进中/3暂缓中 → 1待领取`,清空负责人快照,记入池原因。')
null_post(6, '暂缓', '/api/opportunity/pause',
[('id','string','','-','商机 ID'),
('remark','string','','-','暂缓原因说明')],
[('id','1'),('remark','客户内部调整,暂缓推进')],
'暂缓商机(E4):`oppStatus: 2推进中 → 3暂缓中`,商机暂停推进但不进公海,阶段轴 2 冻结。')
null_post(7, '取消暂缓', '/api/opportunity/resume',
[('id','string','','-','商机 ID')],
[('id','1')],
'取消暂缓(E5):`oppStatus: 3暂缓中 → 2推进中`,恢复阶段轴 2 计时。')
null_post(8, '关闭商机', '/api/opportunity/close',
[('id','string','','-','商机 ID'),
('closeReason','string','','-','关闭原因字典 code'),
('remark','string','','-','关闭说明')],
[('id','1'),('closeReason','reason_close_01'),('remark','竞争失败')],
'关闭商机(E6):`oppStatus → 4已关闭`,终态不可逆(只能「重启」回推进中)。')
null_post(9, '批量关闭', '/api/opportunity/close-batch',
[('ids','string','','-','商机 ID 列表,逗号分隔'),
('closeReason','string','','-','关闭原因字典 code'),
('remark','string','','-','关闭说明')],
[('ids','1,2'),('closeReason','reason_close_01')],
'批量关闭:逐条执行关闭逻辑,独立成功/失败。')
null_post(10, '重启商机', '/api/opportunity/reopen',
[('id','string','','-','商机 ID')],
[('id','1')],
'重启商机(E7):`oppStatus: 4已关闭 → 2推进中`,重新激活商机,阶段轴 2 继续计时。')
null_post(11, '移交商机', '/api/opportunity/handover',
[('id','string','','-','商机 ID'),
('toUserId','string','','-','接收人用户 ID'),
('toUserNameSnapshot','string','','-','接收人姓名快照'),
('toDeptId','string','','-','接收人部门 ID'),
('expectedOwnerUserId','string','','-','乐观锁:当前负责人 ID(防脏移交;若移交前已被他人移交则拒绝)')],
[('id','1'),('toUserId','2'),('toUserNameSnapshot','李四'),('toDeptId','1'),('expectedOwnerUserId','1')],
'移交商机(E9):负责人主动将商机转给他人,`expectedOwnerUserId` 做乐观并发校验防脏移交。')
print('batch3 done')