2026-07-06 20:40:19 +03:30
|
|
|
import { CatalogEntityKind, LabTaskStatus, Prisma } from '@prisma/client';
|
|
|
|
|
import { normalizeCatalogLocale } from '../catalog/catalog-label.service';
|
2026-06-28 16:46:42 +03:30
|
|
|
|
|
|
|
|
type TransactionClient = Prisma.TransactionClient;
|
|
|
|
|
|
|
|
|
|
export async function generateLabCaseTasks(
|
|
|
|
|
tx: TransactionClient,
|
|
|
|
|
labCaseId: string,
|
2026-07-06 20:40:19 +03:30
|
|
|
localeInput?: string | null,
|
2026-06-28 16:46:42 +03:30
|
|
|
): Promise<number> {
|
|
|
|
|
const existingCount = await tx.labCaseTask.count({ where: { labCaseId } });
|
|
|
|
|
if (existingCount > 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 20:40:19 +03:30
|
|
|
const locale = normalizeCatalogLocale(localeInput);
|
|
|
|
|
|
|
|
|
|
const toothProsthesisRows = await tx.labCaseToothProsthesis.findMany({
|
|
|
|
|
where: { labCaseId },
|
2026-06-28 16:46:42 +03:30
|
|
|
include: {
|
2026-07-06 20:40:19 +03:30
|
|
|
detail: { select: { id: true, treatmentType: true } },
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (toothProsthesisRows.length === 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const prosthesisCodes = [...new Set(toothProsthesisRows.map((r) => r.prosthesisTypeCode))];
|
|
|
|
|
|
|
|
|
|
const prosthesisTypes = await tx.prosthesisType.findMany({
|
|
|
|
|
where: { code: { in: prosthesisCodes }, isActive: true },
|
|
|
|
|
include: {
|
|
|
|
|
steps: {
|
|
|
|
|
orderBy: { stepOrder: 'asc' },
|
|
|
|
|
include: { labWorkflowStep: { select: { code: true } } },
|
2026-06-28 16:46:42 +03:30
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-06 20:40:19 +03:30
|
|
|
const stepsByProsthesisCode = new Map(
|
|
|
|
|
prosthesisTypes.map((type) => [
|
|
|
|
|
type.code,
|
|
|
|
|
type.steps.map((s) => ({
|
|
|
|
|
stepOrder: s.stepOrder,
|
|
|
|
|
workflowStepCode: s.labWorkflowStep.code,
|
|
|
|
|
})),
|
|
|
|
|
]),
|
|
|
|
|
);
|
2026-06-28 16:46:42 +03:30
|
|
|
|
2026-07-06 20:40:19 +03:30
|
|
|
const allStepCodes = [
|
|
|
|
|
...new Set(
|
|
|
|
|
prosthesisTypes.flatMap((type) =>
|
|
|
|
|
type.steps.map((s) => s.labWorkflowStep.code),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
];
|
2026-06-28 16:46:42 +03:30
|
|
|
|
2026-07-06 20:40:19 +03:30
|
|
|
const stepLabels = await resolveStepLabels(tx, allStepCodes, locale);
|
2026-06-28 16:46:42 +03:30
|
|
|
|
|
|
|
|
const taskRows: Prisma.LabCaseTaskCreateManyInput[] = [];
|
|
|
|
|
|
2026-07-06 20:40:19 +03:30
|
|
|
for (const row of toothProsthesisRows) {
|
|
|
|
|
const typeSteps = stepsByProsthesisCode.get(row.prosthesisTypeCode) ?? [];
|
|
|
|
|
if (typeSteps.length === 0) {
|
2026-06-28 16:46:42 +03:30
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 20:40:19 +03:30
|
|
|
for (const step of typeSteps) {
|
|
|
|
|
taskRows.push({
|
|
|
|
|
labCaseId,
|
|
|
|
|
treatmentDetailId: row.treatmentDetailId,
|
|
|
|
|
tooth: row.tooth,
|
|
|
|
|
treatmentType: row.detail.treatmentType,
|
|
|
|
|
prosthesisTypeCode: row.prosthesisTypeCode,
|
|
|
|
|
workflowStepCode: step.workflowStepCode,
|
|
|
|
|
stepOrder: step.stepOrder,
|
|
|
|
|
stepLabel: stepLabels.get(step.workflowStepCode) ?? step.workflowStepCode,
|
|
|
|
|
status: LabTaskStatus.PENDING,
|
|
|
|
|
});
|
2026-06-28 16:46:42 +03:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (taskRows.length === 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await tx.labCaseTask.createMany({ data: taskRows });
|
|
|
|
|
return taskRows.length;
|
|
|
|
|
}
|
2026-07-06 20:40:19 +03:30
|
|
|
|
|
|
|
|
async function resolveStepLabels(
|
|
|
|
|
tx: TransactionClient,
|
|
|
|
|
stepCodes: string[],
|
|
|
|
|
locale: string,
|
|
|
|
|
): Promise<Map<string, string>> {
|
|
|
|
|
if (stepCodes.length === 0) {
|
|
|
|
|
return new Map();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rows = await tx.catalogTranslation.findMany({
|
|
|
|
|
where: {
|
|
|
|
|
entityKind: CatalogEntityKind.LAB_WORKFLOW_STEP,
|
|
|
|
|
entityCode: { in: stepCodes },
|
|
|
|
|
locale: { in: [locale, 'en'] },
|
|
|
|
|
},
|
|
|
|
|
select: { entityCode: true, locale: true, label: true },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const byCode = new Map<string, { en?: string; locale?: string }>();
|
|
|
|
|
for (const row of rows) {
|
|
|
|
|
const entry = byCode.get(row.entityCode) ?? {};
|
|
|
|
|
if (row.locale === 'en') entry.en = row.label;
|
|
|
|
|
if (row.locale === locale) entry.locale = row.label;
|
|
|
|
|
byCode.set(row.entityCode, entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const result = new Map<string, string>();
|
|
|
|
|
for (const code of stepCodes) {
|
|
|
|
|
const entry = byCode.get(code);
|
|
|
|
|
result.set(code, entry?.locale ?? entry?.en ?? code);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|