diff --git a/packages/twenty-apps/internal/twenty-partners/package.json b/packages/twenty-apps/internal/twenty-partners/package.json index 341d5b3b22..8c03674f2c 100644 --- a/packages/twenty-apps/internal/twenty-partners/package.json +++ b/packages/twenty-apps/internal/twenty-partners/package.json @@ -1,6 +1,6 @@ { "name": "twenty-partners", - "version": "1.1.3", + "version": "1.1.14", "license": "MIT", "engines": { "node": "^24.5.0", diff --git a/packages/twenty-apps/internal/twenty-partners/src/logic-functions/__tests__/import-opportunity-from-tft.test.ts b/packages/twenty-apps/internal/twenty-partners/src/logic-functions/__tests__/import-opportunity-from-tft.test.ts index bb735762d6..debd417db6 100644 --- a/packages/twenty-apps/internal/twenty-partners/src/logic-functions/__tests__/import-opportunity-from-tft.test.ts +++ b/packages/twenty-apps/internal/twenty-partners/src/logic-functions/__tests__/import-opportunity-from-tft.test.ts @@ -78,7 +78,9 @@ describe('import-opportunity-from-tft handler', () => { .mockResolvedValueOnce({ createPerson: { id: 'person-1' } }) .mockResolvedValueOnce({ createOpportunity: { id: 'opp-1' } }); - const result = await handler(authedEvent(baseInput())); + const result = await handler( + authedEvent(baseInput({ useCase: 'Migrate from HubSpot, ~30 sales users' })), + ); expect(result).toEqual({ ok: true, created: true, id: 'opp-1' }); @@ -91,6 +93,7 @@ describe('import-opportunity-from-tft handler', () => { amount: { amountMicros: 5000000, currencyCode: 'EUR' }, closeDate: '2026-07-01T00:00:00.000Z', stage: 'MEETING', + need: 'Migrate from HubSpot, ~30 sales users', companyId: 'company-1', pointOfContactId: 'person-1', }); @@ -119,4 +122,28 @@ describe('import-opportunity-from-tft handler', () => { expect(data).not.toHaveProperty('amount'); expect(data).not.toHaveProperty('closeDate'); }); + + it('drops null useCase instead of failing validation', async () => { + queryMock + .mockResolvedValueOnce({ opportunities: { edges: [] } }) + .mockResolvedValueOnce({ companies: { edges: [] } }) + .mockResolvedValueOnce({ people: { edges: [] } }); + mutationMock + .mockResolvedValueOnce({ createCompany: { id: 'company-1' } }) + .mockResolvedValueOnce({ createPerson: { id: 'person-1' } }) + .mockResolvedValueOnce({ createOpportunity: { id: 'opp-1' } }); + + const body = { ...baseInput(), useCase: null }; + const result = await handler({ + body, + headers: { 'x-application-secret': SECRET }, + }); + + expect(result).toEqual({ ok: true, created: true, id: 'opp-1' }); + const data = mutationMock.mock.calls.find( + ([arg]) => 'createOpportunity' in arg, + )?.[0].createOpportunity.__args.data; + expect(data).not.toHaveProperty('need'); + expect(data).not.toHaveProperty('useCase'); + }); }); diff --git a/packages/twenty-apps/internal/twenty-partners/src/logic-functions/import-opportunity-from-tft.logic-function.ts b/packages/twenty-apps/internal/twenty-partners/src/logic-functions/import-opportunity-from-tft.logic-function.ts index aa82dd4da4..0b43b2c11d 100644 --- a/packages/twenty-apps/internal/twenty-partners/src/logic-functions/import-opportunity-from-tft.logic-function.ts +++ b/packages/twenty-apps/internal/twenty-partners/src/logic-functions/import-opportunity-from-tft.logic-function.ts @@ -32,6 +32,7 @@ export const importOpportunityFromTftSchema = z.preprocess(dropNulls, z.object({ currencyCode: z.string().optional(), closeDate: z.string().optional(), stage: z.string().optional(), + useCase: z.string().optional(), company: z .object({ name: z.string().optional(), @@ -198,6 +199,9 @@ export const handler = async ( if (isNonEmptyString(input.stage)) { opportunityData.stage = input.stage as CoreSchema.OpportunityStageEnum; } + if (isNonEmptyString(input.useCase)) { + opportunityData.need = input.useCase.trim(); + } if (companyId !== undefined) opportunityData.companyId = companyId; if (pointOfContactId !== undefined) opportunityData.pointOfContactId = pointOfContactId;