Add public API keys, outbound webhooks, and bulk SMS campaigns with settings UI and org modules.

This commit is contained in:
2026-09-26 16:12:29 +03:30
parent ccddd009e3
commit ef600d149d
23 changed files with 2434 additions and 5 deletions
+32 -1
View File
@@ -17,6 +17,7 @@ import { toJsonCustomFields } from '../common/custom-fields';
import { NotificationsService } from '../notifications/notifications.service';
import { AutomationsService } from '../automations/automations.service';
import { MessageAutomationsService } from '../message-automations/message-automations.service';
import { WebhooksService } from '../public-api/webhooks.service';
import {
type Actor,
canReassignOwner,
@@ -41,6 +42,7 @@ export class DealsService {
private readonly notifications: NotificationsService,
private readonly automations: AutomationsService,
private readonly messageAutomations: MessageAutomationsService,
private readonly webhooks: WebhooksService,
) {}
async get(
@@ -161,6 +163,15 @@ export class DealsService {
};
await this.automations.runTrigger('deal_created', createdCtx);
await this.messageAutomations.onEvent('deal_created', createdCtx);
this.webhooks.emit(organizationId, 'deal.created', {
id: created.id,
title: created.title,
status: created.status,
amount: created.amount == null ? null : Number(created.amount),
currency: created.currency,
stageId: created.stageId,
pipelineId: created.pipelineId,
});
return this.pipelines.toDealDto(created);
}
@@ -240,7 +251,17 @@ export class DealsService {
await tx.deal.update({ where: { id }, data });
});
return this.get(organizationId, id, actor);
const updated = await this.get(organizationId, id, actor);
this.webhooks.emit(organizationId, 'deal.updated', {
id: updated.id,
title: updated.title,
status: updated.status,
amount: updated.amount,
currency: updated.currency,
stageId: updated.stageId,
pipelineId: updated.pipelineId,
});
return updated;
}
async move(
@@ -321,10 +342,20 @@ export class DealsService {
if (status === 'won' && deal.status !== 'won') {
await this.automations.runTrigger('deal_won', ctx);
await this.messageAutomations.onEvent('deal_won', ctx);
this.webhooks.emit(organizationId, 'deal.won', {
id: deal.id,
title: deal.title,
stageId: dto.stageId,
});
}
if (status === 'lost' && deal.status !== 'lost') {
await this.automations.runTrigger('deal_lost', ctx);
await this.messageAutomations.onEvent('deal_lost', ctx);
this.webhooks.emit(organizationId, 'deal.lost', {
id: deal.id,
title: deal.title,
stageId: dto.stageId,
});
}
}
@@ -8,6 +8,7 @@ import { NotificationsModule } from '../notifications/notifications.module';
import { AuthModule } from '../auth/auth.module';
import { AutomationsModule } from '../automations/automations.module';
import { MessageAutomationsModule } from '../message-automations/message-automations.module';
import { PublicApiModule } from '../public-api/public-api.module';
@Module({
imports: [
@@ -15,6 +16,7 @@ import { MessageAutomationsModule } from '../message-automations/message-automat
AuthModule,
forwardRef(() => AutomationsModule),
MessageAutomationsModule,
PublicApiModule,
],
controllers: [PipelinesController, DealsController],
providers: [PipelinesService, DealsService, DealsExcelService],