feature: Phase5 - Lab Cases inbox + task board

This commit is contained in:
2026-06-28 17:49:40 +03:30
parent 7b19d6953c
commit 478cfa085a
9 changed files with 431 additions and 83 deletions

View File

@@ -72,23 +72,7 @@ export class CasesService {
const limit = Math.min(Math.max(query.limit ?? 20, 1), 100);
const skip = (page - 1) * limit;
const where: Prisma.LabCaseWhereInput = {
sentAt: { not: null },
sends: { some: { organizationId: labOrganizationId } },
...(query.clinicOrganizationId
? { treatment: { organizationId: query.clinicOrganizationId } }
: {}),
...(query.treatmentType
? {
details: {
some: { detail: { treatmentType: query.treatmentType } },
},
}
: {}),
...(query.q?.trim()
? this.buildSearchWhere(query.q.trim())
: {}),
};
const where = this.buildListWhere(labOrganizationId, query);
const [items, total] = await Promise.all([
this.prisma.labCase.findMany({
@@ -128,6 +112,50 @@ export class CasesService {
};
}
async listFilterOptions(labOrganizationId: string, actorUserId: string) {
await this.assertCanReadCases(actorUserId, labOrganizationId);
const rows = await this.prisma.labCase.findMany({
where: {
sentAt: { not: null },
sends: { some: { organizationId: labOrganizationId } },
},
select: {
treatment: {
select: {
organization: { select: { id: true, name: true } },
},
},
details: {
select: { detail: { select: { treatmentType: true } } },
},
},
});
const clinicsById = new Map<string, { id: string; name: string }>();
const typeCodes = new Set<string>();
for (const row of rows) {
clinicsById.set(row.treatment.organization.id, row.treatment.organization);
for (const link of row.details) {
typeCodes.add(link.detail.treatmentType);
}
}
const treatmentTypes = this.treatmentCatalog
.list()
.filter((entry) => entry.labDependent && typeCodes.has(entry.code))
.map((entry) => ({ code: entry.code, labDependent: entry.labDependent }));
return {
success: true,
data: {
clinics: [...clinicsById.values()].sort((a, b) => a.name.localeCompare(b.name)),
treatmentTypes,
},
};
}
async getOne(labCaseId: string, labOrganizationId: string, actorUserId: string) {
await this.assertCanReadCases(actorUserId, labOrganizationId);
@@ -209,6 +237,46 @@ export class CasesService {
};
}
private buildListWhere(
labOrganizationId: string,
query: ListLabCasesDto,
): Prisma.LabCaseWhereInput {
const sentAtFilter: Prisma.DateTimeNullableFilter = { not: null };
if (query.sentFrom) {
const from = new Date(query.sentFrom);
if (Number.isNaN(from.getTime())) {
throw new BadRequestException('Invalid sentFrom date');
}
sentAtFilter.gte = from;
}
if (query.sentTo) {
const to = new Date(query.sentTo);
if (Number.isNaN(to.getTime())) {
throw new BadRequestException('Invalid sentTo date');
}
to.setHours(23, 59, 59, 999);
sentAtFilter.lte = to;
}
return {
sentAt: sentAtFilter,
sends: { some: { organizationId: labOrganizationId } },
...(query.clinicOrganizationId
? { treatment: { organizationId: query.clinicOrganizationId } }
: {}),
...(query.treatmentType
? {
details: {
some: { detail: { treatmentType: query.treatmentType } },
},
}
: {}),
...(query.q?.trim() ? this.buildSearchWhere(query.q.trim()) : {}),
};
}
private buildSearchWhere(q: string): Prisma.LabCaseWhereInput {
const orConditions: Prisma.LabCaseWhereInput[] = [
{