TreatmentType and ProsthesisType database shcema and data updated. Lab dispatch wired through new data.

This commit is contained in:
2026-07-06 20:40:19 +03:30
parent 3e81c110a3
commit 667b08ed0c
48 changed files with 1813 additions and 275 deletions

View File

@@ -1,84 +1,83 @@
import { LabTaskStatus, Prisma } from '@prisma/client';
import { normalizeTeeth } from '../treatments/treatment.utils';
import { CatalogEntityKind, LabTaskStatus, Prisma } from '@prisma/client';
import { normalizeCatalogLocale } from '../catalog/catalog-label.service';
type TransactionClient = Prisma.TransactionClient;
export async function generateLabCaseTasks(
tx: TransactionClient,
labCaseId: string,
localeInput?: string | null,
): Promise<number> {
const existingCount = await tx.labCaseTask.count({ where: { labCaseId } });
if (existingCount > 0) {
return 0;
}
const labCase = await tx.labCase.findUnique({
where: { id: labCaseId },
const locale = normalizeCatalogLocale(localeInput);
const toothProsthesisRows = await tx.labCaseToothProsthesis.findMany({
where: { labCaseId },
include: {
details: {
include: {
detail: {
select: { id: true, treatmentType: true, teeth: true },
},
},
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 } } },
},
},
});
if (!labCase?.details.length) {
return 0;
}
const stepsByProsthesisCode = new Map(
prosthesisTypes.map((type) => [
type.code,
type.steps.map((s) => ({
stepOrder: s.stepOrder,
workflowStepCode: s.labWorkflowStep.code,
})),
]),
);
const treatmentTypeCodes = [...new Set(labCase.details.map((d) => d.detail.treatmentType))];
const allStepCodes = [
...new Set(
prosthesisTypes.flatMap((type) =>
type.steps.map((s) => s.labWorkflowStep.code),
),
),
];
const labDependentTypes = await tx.treatmentType.findMany({
where: { code: { in: treatmentTypeCodes }, labDependent: true },
select: { id: true, code: true },
});
if (labDependentTypes.length === 0) {
return 0;
}
const labDependentCodes = new Set(labDependentTypes.map((t) => t.code));
const workflowSteps = await tx.treatmentWorkflowStep.findMany({
where: { treatmentTypeId: { in: labDependentTypes.map((t) => t.id) } },
orderBy: [{ treatmentTypeId: 'asc' }, { stepOrder: 'asc' }],
include: { treatmentType: { select: { code: true } } },
});
const stepsByTypeCode = new Map<string, { stepOrder: number; label: string }[]>();
for (const step of workflowSteps) {
const code = step.treatmentType.code;
const list = stepsByTypeCode.get(code) ?? [];
list.push({ stepOrder: step.stepOrder, label: step.label });
stepsByTypeCode.set(code, list);
}
const stepLabels = await resolveStepLabels(tx, allStepCodes, locale);
const taskRows: Prisma.LabCaseTaskCreateManyInput[] = [];
for (const link of labCase.details) {
const detail = link.detail;
if (!labDependentCodes.has(detail.treatmentType)) {
for (const row of toothProsthesisRows) {
const typeSteps = stepsByProsthesisCode.get(row.prosthesisTypeCode) ?? [];
if (typeSteps.length === 0) {
continue;
}
const teeth = normalizeTeeth(detail.teeth);
const typeSteps = stepsByTypeCode.get(detail.treatmentType) ?? [];
for (const tooth of teeth) {
for (const step of typeSteps) {
taskRows.push({
labCaseId,
treatmentDetailId: detail.id,
tooth,
treatmentType: detail.treatmentType,
stepOrder: step.stepOrder,
stepLabel: step.label,
status: LabTaskStatus.PENDING,
});
}
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,
});
}
}
@@ -89,3 +88,37 @@ export async function generateLabCaseTasks(
await tx.labCaseTask.createMany({ data: taskRows });
return taskRows.length;
}
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;
}