improvement: duedate added for shipped cases. cases and tasks ui and ux updated accordingly.
This commit is contained in:
@@ -4,7 +4,7 @@ import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { LabTaskStatus, LinkStatus } from '@prisma/client';
|
||||
import { LabTaskStatus, LinkStatus, Prisma } from '@prisma/client';
|
||||
import { createReadStream, existsSync, mkdirSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { randomUUID } from 'crypto';
|
||||
@@ -15,7 +15,12 @@ import { TreatmentCatalogService } from '../treatment-catalog/treatment-catalog.
|
||||
import {
|
||||
SaveTreatmentDraftDto,
|
||||
SaveTreatmentLabCasesDto,
|
||||
UpdateLabCaseDueDateDto,
|
||||
} from './dto/treatment.dto';
|
||||
import {
|
||||
isLabCaseFullyCompleted,
|
||||
parseDueDateInput,
|
||||
} from '../../common/lab-case-due-date';
|
||||
import {
|
||||
generateTreatmentTitle,
|
||||
normalizeTeeth,
|
||||
@@ -408,9 +413,15 @@ export class TreatmentsService {
|
||||
|
||||
for (const [index, lc] of dto.labCases.entries()) {
|
||||
if (lc.id && sentLabCaseIds.has(lc.id)) {
|
||||
if (lc.dueDate !== undefined) {
|
||||
await this.updateLabCaseDueDateInTx(tx, lc.id, organizationId, lc.dueDate);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const dueDate =
|
||||
lc.dueDate !== undefined ? parseDueDateInput(lc.dueDate) : undefined;
|
||||
|
||||
const row = lc.id
|
||||
? await tx.labCase.update({
|
||||
where: { id: lc.id },
|
||||
@@ -418,6 +429,7 @@ export class TreatmentsService {
|
||||
clientKey: lc.clientId,
|
||||
sortOrder: index,
|
||||
destinationOrganizationId: lc.destinationOrganizationId ?? null,
|
||||
...(dueDate !== undefined ? { dueDate } : {}),
|
||||
},
|
||||
})
|
||||
: await tx.labCase.create({
|
||||
@@ -426,6 +438,7 @@ export class TreatmentsService {
|
||||
clientKey: lc.clientId,
|
||||
sortOrder: index,
|
||||
destinationOrganizationId: lc.destinationOrganizationId ?? null,
|
||||
...(dueDate !== undefined ? { dueDate } : {}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -586,6 +599,88 @@ export class TreatmentsService {
|
||||
return { success: true, data: this.mapLabCase(refreshed) };
|
||||
}
|
||||
|
||||
async updateLabCaseDueDate(
|
||||
labCaseId: string,
|
||||
dto: UpdateLabCaseDueDateDto,
|
||||
organizationId: string,
|
||||
actorUserId: string,
|
||||
) {
|
||||
await this.assertCanEditTreatment(actorUserId, organizationId);
|
||||
|
||||
const updated = await this.prisma.$transaction(async (tx) => {
|
||||
await this.updateLabCaseDueDateInTx(tx, labCaseId, organizationId, dto.dueDate ?? null);
|
||||
return tx.labCase.findFirstOrThrow({
|
||||
where: { id: labCaseId },
|
||||
include: {
|
||||
details: {
|
||||
include: {
|
||||
detail: {
|
||||
select: { id: true, clientKey: true, treatmentType: true, teeth: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
sends: {
|
||||
orderBy: [{ sentAt: 'asc' }],
|
||||
include: { organization: { select: { id: true, name: true } } },
|
||||
},
|
||||
toothProsthesis: true,
|
||||
tasks: { select: { id: true, status: true } },
|
||||
attachments: {
|
||||
include: {
|
||||
attachment: {
|
||||
select: {
|
||||
id: true,
|
||||
fileName: true,
|
||||
mimeType: true,
|
||||
sizeBytes: true,
|
||||
createdAt: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return { success: true, data: this.mapLabCase(updated) };
|
||||
}
|
||||
|
||||
private async updateLabCaseDueDateInTx(
|
||||
tx: Prisma.TransactionClient,
|
||||
labCaseId: string,
|
||||
organizationId: string,
|
||||
dueDateInput?: string | null,
|
||||
) {
|
||||
const labCase = await tx.labCase.findFirst({
|
||||
where: {
|
||||
id: labCaseId,
|
||||
treatment: { organizationId },
|
||||
sentAt: { not: null },
|
||||
},
|
||||
include: { tasks: { select: { status: true } } },
|
||||
});
|
||||
|
||||
if (!labCase) {
|
||||
throw new NotFoundException('Lab case not found');
|
||||
}
|
||||
|
||||
if (isLabCaseFullyCompleted(labCase.tasks)) {
|
||||
throw new BadRequestException('Due date cannot be changed after all tasks are completed');
|
||||
}
|
||||
|
||||
let dueDate: Date | null;
|
||||
try {
|
||||
dueDate = parseDueDateInput(dueDateInput ?? null);
|
||||
} catch {
|
||||
throw new BadRequestException('Invalid due date');
|
||||
}
|
||||
|
||||
await tx.labCase.update({
|
||||
where: { id: labCaseId },
|
||||
data: { dueDate },
|
||||
});
|
||||
}
|
||||
|
||||
async uploadDetailAttachments(
|
||||
appointmentId: string,
|
||||
detailClientKey: string,
|
||||
@@ -804,6 +899,7 @@ export class TreatmentsService {
|
||||
sortOrder?: number;
|
||||
destinationOrganizationId?: string | null;
|
||||
sentAt?: Date | null;
|
||||
dueDate?: Date | null;
|
||||
details?: Array<{
|
||||
treatmentDetailId: string;
|
||||
detail?: { id: string; clientKey: string | null; treatmentType: string; teeth: unknown };
|
||||
@@ -827,12 +923,16 @@ export class TreatmentsService {
|
||||
createdAt: Date;
|
||||
};
|
||||
}>;
|
||||
tasks?: Array<{ id: string; status: LabTaskStatus }>;
|
||||
}) {
|
||||
const taskProgress = this.mapTaskProgress(lc.tasks ?? []);
|
||||
return {
|
||||
id: lc.id,
|
||||
clientId: lc.clientKey ?? lc.id,
|
||||
destinationOrganizationId: lc.destinationOrganizationId ?? null,
|
||||
sentAt: lc.sentAt?.toISOString() ?? null,
|
||||
dueDate: lc.dueDate?.toISOString() ?? null,
|
||||
taskProgress,
|
||||
treatmentDetailId: lc.details?.[0]?.treatmentDetailId ?? null,
|
||||
detail: lc.details?.[0]
|
||||
? {
|
||||
|
||||
Reference in New Issue
Block a user