fix(bridge): 商机漏建兜底与匿名线索
This commit is contained in:
@@ -487,15 +487,54 @@ test('search_email_history: scopes to verified email, ignores args.email', async
|
||||
assert.equal(out.count, 0);
|
||||
});
|
||||
|
||||
test('create_opportunity: requires verified contact', async () => {
|
||||
test('create_opportunity: unverified lead is created from contact name (policy A)', async () => {
|
||||
const twenty = fakeTwenty();
|
||||
const tools = createTools(baseCfg, { rpc: fakeRpc(() => []), twenty });
|
||||
const tool = tools.find((t) => t.name === 'create_opportunity');
|
||||
const out = await tool.handler(
|
||||
{ company: 'Anon Co', contactName: 'Anna Klein', productNeed: '500 rings' },
|
||||
{ verified: false, conversationUuid: `conv-anon-${Date.now()}` }
|
||||
);
|
||||
assert.equal(out.created, true);
|
||||
assert.equal(twenty.calls.filter((c) => c[0] === 'createOpportunity').length, 1);
|
||||
const note = twenty.calls.find((c) => c[0] === 'createNote');
|
||||
assert.match(note[1], /Contact: Anna Klein/);
|
||||
assert.doesNotMatch(note[1], /<>/);
|
||||
});
|
||||
|
||||
test('create_opportunity: unverified lead keeps the email provided in chat', async () => {
|
||||
const twenty = fakeTwenty();
|
||||
const tools = createTools(baseCfg, { rpc: fakeRpc(() => []), twenty });
|
||||
const tool = tools.find((t) => t.name === 'create_opportunity');
|
||||
const out = await tool.handler(
|
||||
{ company: 'Anon Co', contactName: 'Anna Klein', email: 'anna@anon.test', productNeed: '500 rings' },
|
||||
{ verified: false, conversationUuid: `conv-anon-mail-${Date.now()}` }
|
||||
);
|
||||
assert.equal(out.created, true);
|
||||
const person = twenty.calls.find((c) => c[0] === 'createPerson');
|
||||
assert.equal(person[1].email, 'anna@anon.test');
|
||||
});
|
||||
|
||||
test('create_opportunity: still requires company + contact + need', async () => {
|
||||
const tools = createTools(baseCfg, { rpc: fakeRpc(() => []), twenty: fakeTwenty() });
|
||||
const tool = tools.find((t) => t.name === 'create_opportunity');
|
||||
await assert.rejects(
|
||||
() => tool.handler({ company: 'A', contactName: 'B', productNeed: 'C' }, { verified: false }),
|
||||
(err) => err instanceof ToolError && err.status === 403
|
||||
() => tool.handler({ company: 'A', productNeed: 'C' }, { verified: false, conversationUuid: 'conv-missing' }),
|
||||
(err) => err instanceof ToolError && err.status === 400
|
||||
);
|
||||
});
|
||||
|
||||
test('collect_info: stores the email slot', async () => {
|
||||
const tools = createTools(baseCfg, { rpc: fakeRpc(() => []), twenty: fakeTwenty() });
|
||||
const tool = tools.find((t) => t.name === 'collect_info');
|
||||
const out = await tool.handler(
|
||||
{ company: 'Acme BV', contactName: 'John Doe', email: 'john@acme.test', productNeed: 'gold hoops' },
|
||||
{ conversationUuid: 'conv-collect-email', verified: false }
|
||||
);
|
||||
assert.equal(out.slots.email, 'john@acme.test');
|
||||
assert.deepEqual(out.missing, []);
|
||||
});
|
||||
|
||||
test('create_opportunity: dedupes by existing opportunity', async () => {
|
||||
const twenty = fakeTwenty({ personId: 'person-1', existingOpps: [{ id: 'opp-old', name: 'Old', stage: 'NEW' }] });
|
||||
const tools = createTools(baseCfg, { rpc: fakeRpc(() => []), twenty });
|
||||
|
||||
Reference in New Issue
Block a user