const { pushPaidReimbursementToErp } = require('./erp'); const { sendInstantMessageByChannel } = require('../notifications/channels'); class IntegrationDispatchError extends Error { constructor({ code, message, retryable, statusCode, response }) { super(message || code || 'integration_dispatch_failed'); this.name = 'IntegrationDispatchError'; this.code = code || 'integration_dispatch_failed'; this.retryable = typeof retryable === 'boolean' ? retryable : true; this.statusCode = Number.isFinite(statusCode) ? Number(statusCode) : null; this.response = response ?? null; } } function toDispatchError(result) { return new IntegrationDispatchError({ code: result?.code, message: result?.message, retryable: result?.retryable, statusCode: result?.httpStatus, response: result?.response, }); } async function dispatchOutboxEvent({ prisma, config, eventType, payload }) { if (eventType === 'erp.reimbursement.paid') { const result = await pushPaidReimbursementToErp(config, payload); if (!result.ok) { throw toDispatchError(result); } return { channel: 'erp', code: result.code, response: result.response ?? null, }; } if (eventType === 'notification.im') { const channelId = String(payload?.channelId ?? '').trim(); const channel = channelId ? await prisma.notificationChannel.findUnique({ where: { id: channelId }, select: { id: true, channel_type: true, name: true, enabled: true, config_json: true, template_json: true, }, }) : null; const result = await sendInstantMessageByChannel({ config, channel, payload, }); if (!result.ok) { throw toDispatchError(result); } return { channel: 'im', code: result.code, response: result.response ?? null, skipped: result.skipped ?? false, previewMessage: result.previewMessage ?? null, }; } throw new IntegrationDispatchError({ code: 'unsupported_outbox_event', message: `unsupported_outbox_event:${eventType}`, retryable: false, }); } module.exports = { IntegrationDispatchError, dispatchOutboxEvent, };