TreatmentType and ProsthesisType database shcema and data updated. Lab dispatch wired through new data.
This commit is contained in:
@@ -10,6 +10,7 @@ import { join } from 'path';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { PrismaService } from '../../../prisma/prisma.service';
|
||||
import { generateLabCaseTasks } from '../cases/lab-case-task.generator';
|
||||
import { ProsthesisCatalogService } from '../prosthesis-catalog/prosthesis-catalog.service';
|
||||
import { TreatmentCatalogService } from '../treatment-catalog/treatment-catalog.service';
|
||||
import {
|
||||
SaveTreatmentDraftDto,
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
generateTreatmentTitle,
|
||||
normalizeTeeth,
|
||||
} from './treatment.utils';
|
||||
import { assertCompleteToothProsthesisMap } from './lab-case-send.validation';
|
||||
|
||||
const treatmentInclude = {
|
||||
details: {
|
||||
@@ -53,6 +55,7 @@ const treatmentInclude = {
|
||||
orderBy: [{ sentAt: 'asc' as const }],
|
||||
include: { organization: { select: { id: true, name: true } } },
|
||||
},
|
||||
toothProsthesis: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -64,6 +67,7 @@ export class TreatmentsService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly treatmentCatalog: TreatmentCatalogService,
|
||||
private readonly prosthesisCatalog: ProsthesisCatalogService,
|
||||
) {}
|
||||
|
||||
getOrganizationIdFromUser(user: { organizationId?: string }) {
|
||||
@@ -326,7 +330,7 @@ export class TreatmentsService {
|
||||
|
||||
const details = await this.prisma.treatmentDetail.findMany({
|
||||
where: { treatmentId: treatment.id, id: { in: detailIds } },
|
||||
select: { id: true, treatmentType: true },
|
||||
select: { id: true, treatmentType: true, teeth: true },
|
||||
});
|
||||
if (details.length !== uniqueDetailIds.size) {
|
||||
throw new BadRequestException('One or more treatment details were not found');
|
||||
@@ -336,12 +340,30 @@ export class TreatmentsService {
|
||||
this.treatmentCatalog.assertLabDependentTreatmentType(detail.treatmentType);
|
||||
}
|
||||
|
||||
const detailById = new Map(details.map((d) => [d.id, d]));
|
||||
const linkedOrgIds = await this.getActiveLinkedOrganizationIds(organizationId);
|
||||
|
||||
for (const lc of dto.labCases) {
|
||||
if (lc.destinationOrganizationId && !linkedOrgIds.has(lc.destinationOrganizationId)) {
|
||||
throw new BadRequestException('Destination organization is not an active linked counterpart');
|
||||
}
|
||||
|
||||
for (const row of lc.toothProsthesis ?? []) {
|
||||
if (!lc.treatmentDetailIds.includes(row.treatmentDetailId)) {
|
||||
throw new BadRequestException(
|
||||
'Tooth prosthesis must reference a detail included in this lab case',
|
||||
);
|
||||
}
|
||||
const detail = detailById.get(row.treatmentDetailId);
|
||||
if (!detail) {
|
||||
throw new BadRequestException('Tooth prosthesis references an unknown treatment detail');
|
||||
}
|
||||
const teeth = normalizeTeeth(detail.teeth);
|
||||
if (!teeth.includes(row.tooth)) {
|
||||
throw new BadRequestException(`Tooth ${row.tooth} is not on the selected treatment detail`);
|
||||
}
|
||||
this.prosthesisCatalog.assertKnownProsthesisType(row.prosthesisTypeCode);
|
||||
}
|
||||
}
|
||||
|
||||
const saved = await this.prisma.$transaction(async (tx) => {
|
||||
@@ -395,6 +417,18 @@ export class TreatmentsService {
|
||||
treatmentDetailId,
|
||||
})),
|
||||
});
|
||||
|
||||
await tx.labCaseToothProsthesis.deleteMany({ where: { labCaseId: row.id } });
|
||||
if (lc.toothProsthesis?.length) {
|
||||
await tx.labCaseToothProsthesis.createMany({
|
||||
data: lc.toothProsthesis.map((tp) => ({
|
||||
labCaseId: row.id,
|
||||
treatmentDetailId: tp.treatmentDetailId,
|
||||
tooth: tp.tooth,
|
||||
prosthesisTypeCode: tp.prosthesisTypeCode,
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return tx.treatment.findUniqueOrThrow({
|
||||
@@ -410,6 +444,7 @@ export class TreatmentsService {
|
||||
labCaseId: string,
|
||||
organizationId: string,
|
||||
actorUserId: string,
|
||||
actorLanguage?: string | null,
|
||||
) {
|
||||
await this.assertCanEditTreatment(actorUserId, organizationId);
|
||||
|
||||
@@ -421,7 +456,12 @@ export class TreatmentsService {
|
||||
include: {
|
||||
treatment: { select: { providerUserId: true } },
|
||||
sends: { select: { organizationId: true } },
|
||||
details: { select: { treatmentDetailId: true } },
|
||||
details: {
|
||||
include: {
|
||||
detail: { select: { id: true, treatmentType: true, teeth: true } },
|
||||
},
|
||||
},
|
||||
toothProsthesis: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -437,6 +477,8 @@ export class TreatmentsService {
|
||||
throw new BadRequestException('Lab case must include at least one treatment detail');
|
||||
}
|
||||
|
||||
assertCompleteToothProsthesisMap(labCase);
|
||||
|
||||
if (labCase.treatment.providerUserId !== actorUserId) {
|
||||
const membership = await this.getMembership(actorUserId, organizationId);
|
||||
if (!membership?.isOwner) {
|
||||
@@ -473,7 +515,7 @@ export class TreatmentsService {
|
||||
});
|
||||
}
|
||||
|
||||
await generateLabCaseTasks(tx, labCaseId);
|
||||
await generateLabCaseTasks(tx, labCaseId, actorLanguage);
|
||||
});
|
||||
|
||||
const refreshed = await this.prisma.labCase.findUniqueOrThrow({
|
||||
@@ -490,6 +532,7 @@ export class TreatmentsService {
|
||||
orderBy: [{ sentAt: 'asc' }],
|
||||
include: { organization: { select: { id: true, name: true } } },
|
||||
},
|
||||
toothProsthesis: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -722,6 +765,11 @@ export class TreatmentsService {
|
||||
sentAt: Date;
|
||||
organization?: { id: string; name: string };
|
||||
}>;
|
||||
toothProsthesis?: Array<{
|
||||
treatmentDetailId: string;
|
||||
tooth: string;
|
||||
prosthesisTypeCode: string;
|
||||
}>;
|
||||
}) {
|
||||
return {
|
||||
id: lc.id,
|
||||
@@ -736,6 +784,11 @@ export class TreatmentsService {
|
||||
treatmentType: d.detail?.treatmentType ?? '',
|
||||
teeth: d.detail ? normalizeTeeth(d.detail.teeth) : [],
|
||||
})),
|
||||
toothProsthesis: (lc.toothProsthesis ?? []).map((tp) => ({
|
||||
treatmentDetailId: tp.treatmentDetailId,
|
||||
tooth: tp.tooth,
|
||||
prosthesisTypeCode: tp.prosthesisTypeCode,
|
||||
})),
|
||||
sends:
|
||||
lc.sends?.map((s) => ({
|
||||
organizationId: s.organizationId,
|
||||
|
||||
Reference in New Issue
Block a user