import { beforeEach, describe, expect, it, vi } from 'vitest'; type QueryPlanRow = { table: string; where: Record; row: any; }; const withAdminTransactionMock = vi.fn(); let trxImpl: any = null; vi.mock('@alga-psa/db', () => ({ withAdminTransaction: (callback: (trx: any) => Promise) => withAdminTransactionMock(callback), })); vi.mock('@alga-psa/event-bus/publishers', () => ({ publishWorkflowEvent: vi.fn(), })); function whereMatches(actual: Record, expected: Record): boolean { return Object.entries(expected).every(([key, value]) => actual[key] === value); } function createTrxForQueryPlan(plan: QueryPlanRow[]) { const tablesCalled: string[] = []; const trx = (table: string) => { tablesCalled.push(table); let whereClause: Record = {}; const builder: any = { select: vi.fn(() => builder), where: vi.fn((value: Record) => { whereClause = value ?? {}; return builder; }), first: vi.fn(async () => { const match = plan.find((entry) => entry.table === table && whereMatches(whereClause, entry.where)); return match?.row ?? null; }), }; return builder; }; return { trx, tablesCalled }; } describe('resolveEffectiveInboundTicketDefaults precedence', () => { beforeEach(() => { vi.clearAllMocks(); withAdminTransactionMock.mockImplementation(async (callback: (trx: any) => Promise) => callback(trxImpl) ); }); it('T005: exact sender contact with contact override selects contact destination', async () => { const contactDefaults = { board_id: 'board-contact-1', status_id: 'status-1', priority_id: 'priority-1', client_id: 'client-contact', entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx, tablesCalled } = createTrxForQueryPlan([ { table: 'contacts', where: { tenant: 'tenant-1', contact_name_id: 'contact-1' }, row: { inbound_ticket_defaults_id: 'defaults-contact-1', client_id: 'client-contact' }, }, { table: 'inbound_ticket_defaults', where: { tenant: 'tenant-1', id: 'defaults-contact-1', is_active: true }, row: contactDefaults, }, ]); trxImpl = trx; const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); const result = await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults: { board_id: 'board-provider', status_id: 'status-provider', priority_id: 'priority-provider', }, matchedContactId: 'contact-1', matchedContactClientId: 'client-contact', domainMatchedClientId: null, }); expect(result.source).toBe('contact_override'); expect(result.defaults).toEqual(contactDefaults); expect(result.fallbackReason).toBeUndefined(); expect(tablesCalled).not.toContain('clients'); }); it("T006: exact sender contact without override selects contact's client destination", async () => { const clientDefaults = { board_id: 'board-client-1', status_id: 'status-1', priority_id: 'priority-1', client_id: 'client-2', entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx, tablesCalled } = createTrxForQueryPlan([ { table: 'contacts', where: { tenant: 'tenant-1', contact_name_id: 'contact-2' }, row: { inbound_ticket_defaults_id: null, client_id: 'client-2' }, }, { table: 'clients', where: { tenant: 'tenant-1', client_id: 'client-2' }, row: { inbound_ticket_defaults_id: 'defaults-client-2' }, }, { table: 'inbound_ticket_defaults', where: { tenant: 'tenant-1', id: 'defaults-client-2', is_active: true }, row: clientDefaults, }, ]); trxImpl = trx; const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); const result = await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults: { board_id: 'board-provider', status_id: 'status-provider', priority_id: 'priority-provider', }, matchedContactId: 'contact-2', matchedContactClientId: 'client-2', domainMatchedClientId: null, }); expect(result.source).toBe('client_default_from_contact'); expect(result.defaults).toEqual(clientDefaults); expect(result.fallbackReason).toBeUndefined(); expect(tablesCalled).toContain('clients'); }); it('T007: no exact contact + domain-matched client selects domain client destination', async () => { const domainClientDefaults = { board_id: 'board-domain-1', status_id: 'status-1', priority_id: 'priority-1', client_id: 'client-domain-1', entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx, tablesCalled } = createTrxForQueryPlan([ { table: 'clients', where: { tenant: 'tenant-1', client_id: 'client-domain-1' }, row: { inbound_ticket_defaults_id: 'defaults-domain-1' }, }, { table: 'inbound_ticket_defaults', where: { tenant: 'tenant-1', id: 'defaults-domain-1', is_active: true }, row: domainClientDefaults, }, ]); trxImpl = trx; const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); const result = await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults: { board_id: 'board-provider', status_id: 'status-provider', priority_id: 'priority-provider', }, matchedContactId: null, matchedContactClientId: null, domainMatchedClientId: 'client-domain-1', }); expect(result.source).toBe('client_default_from_domain'); expect(result.defaults).toEqual(domainClientDefaults); expect(result.fallbackReason).toBeUndefined(); expect(tablesCalled).not.toContain('contacts'); }); it('T008: no contact/domain destination falls back to provider default', async () => { const providerDefaults = { board_id: 'board-provider-default', status_id: 'status-provider-default', priority_id: 'priority-provider-default', client_id: null, entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx, tablesCalled } = createTrxForQueryPlan([]); trxImpl = trx; const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); const result = await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults, matchedContactId: null, matchedContactClientId: null, domainMatchedClientId: null, }); expect(result.source).toBe('provider_default'); expect(result.defaults).toEqual(providerDefaults); expect(result.fallbackReason).toBeUndefined(); expect(tablesCalled).toHaveLength(0); }); it('T009: falls back to provider default when contact override destination is inactive/invalid', async () => { const providerDefaults = { board_id: 'board-provider-default', status_id: 'status-provider-default', priority_id: 'priority-provider-default', client_id: null, entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx } = createTrxForQueryPlan([ { table: 'contacts', where: { tenant: 'tenant-1', contact_name_id: 'contact-9' }, row: { inbound_ticket_defaults_id: 'defaults-contact-invalid', client_id: null }, }, { table: 'inbound_ticket_defaults', where: { tenant: 'tenant-1', id: 'defaults-contact-invalid', is_active: true }, row: null, }, ]); trxImpl = trx; const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); const result = await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults, matchedContactId: 'contact-9', matchedContactClientId: null, domainMatchedClientId: null, }); expect(result.source).toBe('provider_default'); expect(result.defaults).toEqual(providerDefaults); expect(result.fallbackReason).toBe('invalid_or_inactive_contact_override'); }); it('T010: falls back to provider default when client destination is inactive/invalid', async () => { const providerDefaults = { board_id: 'board-provider-default', status_id: 'status-provider-default', priority_id: 'priority-provider-default', client_id: null, entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx } = createTrxForQueryPlan([ { table: 'contacts', where: { tenant: 'tenant-1', contact_name_id: 'contact-10' }, row: { inbound_ticket_defaults_id: null, client_id: 'client-10' }, }, { table: 'clients', where: { tenant: 'tenant-1', client_id: 'client-10' }, row: { inbound_ticket_defaults_id: 'defaults-client-invalid' }, }, { table: 'inbound_ticket_defaults', where: { tenant: 'tenant-1', id: 'defaults-client-invalid', is_active: true }, row: null, }, ]); trxImpl = trx; const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); const result = await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults, matchedContactId: 'contact-10', matchedContactClientId: 'client-10', domainMatchedClientId: null, }); expect(result.source).toBe('provider_default'); expect(result.defaults).toEqual(providerDefaults); expect(result.fallbackReason).toBe('invalid_or_inactive_client_default_from_contact'); }); it('T027: structured logs include destination source and fallback reason metadata', async () => { const providerDefaults = { board_id: 'board-provider-default', status_id: 'status-provider-default', priority_id: 'priority-provider-default', client_id: null, entered_by: 'user-1', category_id: null, subcategory_id: null, location_id: null, }; const { trx } = createTrxForQueryPlan([ { table: 'contacts', where: { tenant: 'tenant-1', contact_name_id: 'contact-27' }, row: { inbound_ticket_defaults_id: 'defaults-contact-invalid-27', client_id: null }, }, { table: 'inbound_ticket_defaults', where: { tenant: 'tenant-1', id: 'defaults-contact-invalid-27', is_active: true }, row: null, }, ]); trxImpl = trx; const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {}); const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); try { const { resolveEffectiveInboundTicketDefaults } = await import('../emailWorkflowActions'); await resolveEffectiveInboundTicketDefaults({ tenant: 'tenant-1', providerId: 'provider-1', providerDefaults, matchedContactId: 'contact-27', matchedContactClientId: null, domainMatchedClientId: null, }); expect(warnSpy).toHaveBeenCalledWith( 'resolveEffectiveInboundTicketDefaults: invalid contact override destination; using fallback', expect.objectContaining({ source: 'contact_override', fallback: 'provider_default', configuredDefaultsId: 'defaults-contact-invalid-27', }) ); expect(debugSpy).toHaveBeenCalledWith( 'resolveEffectiveInboundTicketDefaults: resolved destination', expect.objectContaining({ source: 'provider_default', fallbackReason: 'invalid_or_inactive_contact_override', }) ); } finally { debugSpy.mockRestore(); warnSpy.mockRestore(); } }); });