fix(api): guard unmoved deals before pipeline merge delete
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsDateString,
|
||||
IsIn,
|
||||
IsInt,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
@@ -362,5 +363,6 @@ export class MergePipelineDto {
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsIn(['retarget_all'])
|
||||
leadFormMode?: 'retarget_all';
|
||||
}
|
||||
|
||||
@@ -416,87 +416,101 @@ export class PipelinesService {
|
||||
);
|
||||
}
|
||||
|
||||
const targetStagesById = new Map(target.stages.map((stage) => [stage.id, stage]));
|
||||
const targetStagesById = new Map(
|
||||
target.stages.map((stage) => [stage.id, stage]),
|
||||
);
|
||||
let movedDeals = 0;
|
||||
let retargetedLeadForms = 0;
|
||||
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
const closedAt = new Date();
|
||||
for (const sourceStage of source.stages) {
|
||||
const targetStageId = dto.stageMap[sourceStage.id];
|
||||
const targetStage = targetStagesById.get(targetStageId);
|
||||
if (!targetStage) {
|
||||
throw new BadRequestException('نگاشت ستونها نامعتبر است');
|
||||
}
|
||||
const status = dealStatusForStage(targetStage);
|
||||
await this.prisma.$transaction(
|
||||
async (tx) => {
|
||||
const closedAt = new Date();
|
||||
for (const sourceStage of source.stages) {
|
||||
const targetStageId = dto.stageMap[sourceStage.id];
|
||||
const targetStage = targetStagesById.get(targetStageId);
|
||||
if (!targetStage) {
|
||||
throw new BadRequestException('نگاشت ستونها نامعتبر است');
|
||||
}
|
||||
const status = dealStatusForStage(targetStage);
|
||||
|
||||
if (status === 'open') {
|
||||
const result = await tx.deal.updateMany({
|
||||
if (status === 'open') {
|
||||
const result = await tx.deal.updateMany({
|
||||
where: {
|
||||
organizationId,
|
||||
pipelineId: source.id,
|
||||
stageId: sourceStage.id,
|
||||
},
|
||||
data: {
|
||||
pipelineId: target.id,
|
||||
stageId: targetStage.id,
|
||||
status,
|
||||
closedAt: null,
|
||||
},
|
||||
});
|
||||
movedDeals += result.count;
|
||||
continue;
|
||||
}
|
||||
|
||||
const opened = await tx.deal.updateMany({
|
||||
where: {
|
||||
organizationId,
|
||||
pipelineId: source.id,
|
||||
stageId: sourceStage.id,
|
||||
status: 'open',
|
||||
},
|
||||
data: {
|
||||
pipelineId: target.id,
|
||||
stageId: targetStage.id,
|
||||
status,
|
||||
closedAt: null,
|
||||
closedAt,
|
||||
},
|
||||
});
|
||||
movedDeals += result.count;
|
||||
continue;
|
||||
const alreadyClosed = await tx.deal.updateMany({
|
||||
where: {
|
||||
organizationId,
|
||||
pipelineId: source.id,
|
||||
stageId: sourceStage.id,
|
||||
status: { not: 'open' },
|
||||
},
|
||||
data: {
|
||||
pipelineId: target.id,
|
||||
stageId: targetStage.id,
|
||||
status,
|
||||
},
|
||||
});
|
||||
movedDeals += opened.count + alreadyClosed.count;
|
||||
}
|
||||
|
||||
const opened = await tx.deal.updateMany({
|
||||
where: {
|
||||
organizationId,
|
||||
pipelineId: source.id,
|
||||
stageId: sourceStage.id,
|
||||
status: 'open',
|
||||
},
|
||||
data: {
|
||||
pipelineId: target.id,
|
||||
stageId: targetStage.id,
|
||||
status,
|
||||
closedAt,
|
||||
},
|
||||
const leadForms = await tx.leadForm.updateMany({
|
||||
where: { organizationId, pipelineId: source.id },
|
||||
data: { pipelineId: target.id },
|
||||
});
|
||||
const alreadyClosed = await tx.deal.updateMany({
|
||||
where: {
|
||||
organizationId,
|
||||
pipelineId: source.id,
|
||||
stageId: sourceStage.id,
|
||||
status: { not: 'open' },
|
||||
},
|
||||
data: {
|
||||
pipelineId: target.id,
|
||||
stageId: targetStage.id,
|
||||
status,
|
||||
},
|
||||
});
|
||||
movedDeals += opened.count + alreadyClosed.count;
|
||||
}
|
||||
retargetedLeadForms = leadForms.count;
|
||||
|
||||
const leadForms = await tx.leadForm.updateMany({
|
||||
where: { organizationId, pipelineId: source.id },
|
||||
data: { pipelineId: target.id },
|
||||
});
|
||||
retargetedLeadForms = leadForms.count;
|
||||
if (source.isDefault) {
|
||||
await tx.pipeline.updateMany({
|
||||
where: { organizationId, isDefault: true },
|
||||
data: { isDefault: false },
|
||||
});
|
||||
await tx.pipeline.update({
|
||||
where: { id: target.id },
|
||||
data: { isDefault: true },
|
||||
});
|
||||
}
|
||||
|
||||
if (source.isDefault) {
|
||||
await tx.pipeline.updateMany({
|
||||
where: { organizationId, isDefault: true },
|
||||
data: { isDefault: false },
|
||||
const remaining = await tx.deal.count({
|
||||
where: { organizationId, pipelineId: source.id },
|
||||
});
|
||||
await tx.pipeline.update({
|
||||
where: { id: target.id },
|
||||
data: { isDefault: true },
|
||||
});
|
||||
}
|
||||
if (remaining > 0) {
|
||||
throw new BadRequestException(
|
||||
'برخی معاملهها منتقل نشدند؛ ادغام لغو شد.',
|
||||
);
|
||||
}
|
||||
|
||||
await tx.pipeline.delete({ where: { id: source.id } });
|
||||
});
|
||||
await tx.pipeline.delete({ where: { id: source.id } });
|
||||
},
|
||||
{ timeout: 30000 },
|
||||
);
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
|
||||
Reference in New Issue
Block a user