Auspicious14 commited on
Commit
9037c9f
Β·
1 Parent(s): b5a54b6

fix(services): add facility validation and clean up code

Browse files

add checks to verify patients are linked to a facility across multiple services to prevent runtime null errors
standardize code formatting for imports, indentation, and line breaks across all service files
fix null handling in facilities service to safely access facility data and return accurate linked status
add missing trailing newline in facilities service file

src/anc-visit/anc-visit.service.ts CHANGED
@@ -1,4 +1,8 @@
1
- import { Injectable, NotFoundException } from "@nestjs/common";
 
 
 
 
2
  import { CreateAncVisitDto } from "./dto/create-anc-visit.dto";
3
  import { PrismaService } from "src/database/prisma.service";
4
  import { calculateRisk } from "./utils/calculate-risk";
@@ -7,190 +11,150 @@ import { calculateRisk } from "./utils/calculate-risk";
7
  export class AncVisitService {
8
  constructor(private readonly prisma: PrismaService) {}
9
 
10
- async create(
11
- dto: CreateAncVisitDto,
12
- healthcareWorkerId: string,
13
- ) {
14
- const healthcareWorker =
15
- await this.prisma.healthcareWorker.findUnique({
16
  where: {
17
  id: healthcareWorkerId,
18
  },
19
  });
20
 
21
- if (!healthcareWorker) {
22
- throw new NotFoundException(
23
- "Healthcare worker not found",
24
- );
25
- }
26
 
27
- const patient =
28
- await this.prisma.patient.findFirst({
29
  where: {
30
  id: dto.patientId,
31
- facilityId:
32
- healthcareWorker.facilityId,
33
  },
34
  });
35
 
36
- if (!patient) {
37
- throw new NotFoundException(
38
- "Patient not found",
39
- );
40
- }
41
 
42
- const riskLevel = calculateRisk({
43
- systolic:
44
- dto.bloodPressureSystolic,
45
- diastolic:
46
- dto.bloodPressureDiastolic,
47
- urineProtein:
48
- dto.urineProtein,
49
- });
50
-
51
- const visit =
52
- await this.prisma.aNCVisit.create({
53
  data: {
54
  patientId: patient.id,
55
- facilityId:
56
- patient.facilityId,
57
  healthcareWorkerId,
58
 
59
- visitDate: dto.visitDate
60
- ? new Date(dto.visitDate)
61
- : new Date(),
62
 
63
- gestationalAge:
64
- dto.gestationalAge,
65
  weight: dto.weight,
66
 
67
- bloodPressureSystolic:
68
- dto.bloodPressureSystolic,
69
 
70
- bloodPressureDiastolic:
71
- dto.bloodPressureDiastolic,
72
 
73
- urineProtein:
74
- dto.urineProtein,
75
 
76
- fundalHeight:
77
- dto.fundalHeight,
78
 
79
- fetalHeartRate:
80
- dto.fetalHeartRate,
81
 
82
- fetalMovement:
83
- dto.fetalMovement,
84
 
85
- haemoglobin:
86
- dto.haemoglobin,
87
 
88
- temperature:
89
- dto.temperature,
90
 
91
- remarks:
92
- dto.remarks,
93
 
94
- nextAppointmentDate:
95
- dto.nextAppointmentDate
96
- ? new Date(
97
- dto.nextAppointmentDate,
98
- )
99
- : null,
100
 
101
  riskLevel,
102
  },
103
  });
104
 
105
- /**
106
- * Update patient's latest risk snapshot
107
- */
108
- await this.prisma.patient.update({
109
- where: {
110
- id: patient.id,
111
- },
112
- data: {
113
- latestRiskLevel: riskLevel,
114
- lastVisitDate:
115
- visit.visitDate,
116
- },
117
- });
118
-
119
- /**
120
- * Create appointment
121
- */
122
- if (dto.nextAppointmentDate) {
123
- await this.prisma.appointment.create({
124
- data: {
125
- userId: patient.userId,
126
- patientId: patient.id,
127
- facilityId:
128
- patient.facilityId,
129
- title:
130
- "Antenatal Care Visit",
131
- type: "ANC",
132
- dateTime: new Date(
133
- dto.nextAppointmentDate,
134
- ),
135
- },
136
- });
137
- }
138
-
139
- /**
140
- * Close old unresolved alerts
141
- * if patient is no longer high risk.
142
- */
143
- if (
144
- riskLevel === "LOW" ||
145
- riskLevel === "MODERATE"
146
- ) {
147
- await this.prisma.alert.updateMany({
148
  where: {
149
- patientId: patient.id,
150
- isResolved: false,
151
  },
152
  data: {
153
- isResolved: true,
154
- resolvedAt: new Date(),
155
  },
156
  });
157
- }
158
 
159
- /**
160
- * Create new alert
161
- */
162
- if (
163
- riskLevel === "HIGH" ||
164
- riskLevel === "EMERGENCY"
165
- ) {
166
- const existingAlert =
167
- await this.prisma.alert.findFirst({
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  where: {
169
  patientId: patient.id,
170
  isResolved: false,
171
- type: riskLevel,
 
 
 
172
  },
173
  });
 
174
 
175
- if (!existingAlert) {
176
- await this.prisma.alert.create({
177
- data: {
178
- facilityId:
179
- patient.facilityId,
180
- patientId:
181
- patient.id,
 
182
  type: riskLevel,
183
- message:
184
- riskLevel === "EMERGENCY"
185
- ? "Severely elevated blood pressure detected."
186
- : "High-risk pregnancy detected during ANC visit.",
187
  },
188
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  }
190
- }
191
 
192
- return visit;
193
- }
194
 
195
  async getPatientVisits(patientId: string) {
196
  const patient = await this.prisma.patient.findUnique({
@@ -298,24 +262,18 @@ async create(
298
  return defaulters.sort((a, b) => b.daysOverdue - a.daysOverdue);
299
  }
300
 
301
- async getPatientSummary(
302
- patientId: string,
303
- ) {
304
- const patient =
305
- await this.prisma.patient.findUnique({
306
  where: {
307
  id: patientId,
308
  },
309
  });
310
 
311
- if (!patient) {
312
- throw new NotFoundException(
313
- "Patient not found",
314
- );
315
- }
316
 
317
- const visits =
318
- await this.prisma.aNCVisit.findMany({
319
  where: {
320
  patientId,
321
  },
@@ -324,76 +282,57 @@ async create(
324
  },
325
  });
326
 
327
- if (!visits.length) {
328
- return {
329
- totalVisits: 0,
330
- lastVisitDate: null,
331
- nextAppointmentDate: null,
332
- riskLevel: "LOW",
333
- missedAppointments: 0,
334
- bpTrend: "UNKNOWN",
335
- lastBloodPressure: null,
336
- };
337
- }
338
 
339
- const latestVisit =
340
- visits[visits.length - 1];
341
 
342
- const today = new Date();
343
 
344
- const missedAppointments =
345
- visits.filter(
346
- (v) =>
347
- v.nextAppointmentDate &&
348
- v.nextAppointmentDate < today,
349
  ).length;
350
 
351
- let bpTrend = "STABLE";
352
-
353
- const bpVisits = visits.filter(
354
- (v) =>
355
- v.bloodPressureSystolic &&
356
- v.bloodPressureDiastolic,
357
- );
358
-
359
- if (bpVisits.length >= 2) {
360
- const last =
361
- bpVisits[bpVisits.length - 1];
362
-
363
- const previous =
364
- bpVisits[bpVisits.length - 2];
365
-
366
- if (
367
- last.bloodPressureSystolic! >
368
- previous.bloodPressureSystolic!
369
- ) {
370
- bpTrend = "RISING";
371
- } else if (
372
- last.bloodPressureSystolic! <
373
- previous.bloodPressureSystolic!
374
- ) {
375
- bpTrend = "FALLING";
376
  }
377
- }
378
 
379
- return {
380
- totalVisits: visits.length,
381
- lastVisitDate:
382
- latestVisit.visitDate,
383
- nextAppointmentDate:
384
- latestVisit.nextAppointmentDate,
385
- riskLevel:
386
- latestVisit.riskLevel,
387
- missedAppointments,
388
- bpTrend,
389
- lastBloodPressure: {
390
- systolic:
391
- latestVisit
392
- .bloodPressureSystolic,
393
- diastolic:
394
- latestVisit
395
- .bloodPressureDiastolic,
396
- },
397
- };
398
- }
399
  }
 
1
+ import {
2
+ BadRequestException,
3
+ Injectable,
4
+ NotFoundException,
5
+ } from "@nestjs/common";
6
  import { CreateAncVisitDto } from "./dto/create-anc-visit.dto";
7
  import { PrismaService } from "src/database/prisma.service";
8
  import { calculateRisk } from "./utils/calculate-risk";
 
11
  export class AncVisitService {
12
  constructor(private readonly prisma: PrismaService) {}
13
 
14
+ async create(dto: CreateAncVisitDto, healthcareWorkerId: string) {
15
+ const healthcareWorker = await this.prisma.healthcareWorker.findUnique({
 
 
 
 
16
  where: {
17
  id: healthcareWorkerId,
18
  },
19
  });
20
 
21
+ if (!healthcareWorker) {
22
+ throw new NotFoundException("Healthcare worker not found");
23
+ }
 
 
24
 
25
+ const patient = await this.prisma.patient.findFirst({
 
26
  where: {
27
  id: dto.patientId,
28
+ facilityId: healthcareWorker.facilityId,
 
29
  },
30
  });
31
 
32
+ if (!patient) {
33
+ throw new NotFoundException("Patient not found");
34
+ }
 
 
35
 
36
+ if (!patient.facilityId) {
37
+ throw new BadRequestException("Patient is not linked to a facility");
38
+ }
39
+
40
+ const riskLevel = calculateRisk({
41
+ systolic: dto.bloodPressureSystolic,
42
+ diastolic: dto.bloodPressureDiastolic,
43
+ urineProtein: dto.urineProtein,
44
+ });
45
+
46
+ const visit = await this.prisma.aNCVisit.create({
47
  data: {
48
  patientId: patient.id,
49
+ facilityId: patient.facilityId,
 
50
  healthcareWorkerId,
51
 
52
+ visitDate: dto.visitDate ? new Date(dto.visitDate) : new Date(),
 
 
53
 
54
+ gestationalAge: dto.gestationalAge,
 
55
  weight: dto.weight,
56
 
57
+ bloodPressureSystolic: dto.bloodPressureSystolic,
 
58
 
59
+ bloodPressureDiastolic: dto.bloodPressureDiastolic,
 
60
 
61
+ urineProtein: dto.urineProtein,
 
62
 
63
+ fundalHeight: dto.fundalHeight,
 
64
 
65
+ fetalHeartRate: dto.fetalHeartRate,
 
66
 
67
+ fetalMovement: dto.fetalMovement,
 
68
 
69
+ haemoglobin: dto.haemoglobin,
 
70
 
71
+ temperature: dto.temperature,
 
72
 
73
+ remarks: dto.remarks,
 
74
 
75
+ nextAppointmentDate: dto.nextAppointmentDate
76
+ ? new Date(dto.nextAppointmentDate)
77
+ : null,
 
 
 
78
 
79
  riskLevel,
80
  },
81
  });
82
 
83
+ /**
84
+ * Update patient's latest risk snapshot
85
+ */
86
+ await this.prisma.patient.update({
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  where: {
88
+ id: patient.id,
 
89
  },
90
  data: {
91
+ latestRiskLevel: riskLevel,
92
+ lastVisitDate: visit.visitDate,
93
  },
94
  });
 
95
 
96
+ /**
97
+ * Create appointment
98
+ */
99
+ if (dto.nextAppointmentDate) {
100
+ await this.prisma.appointment.create({
101
+ data: {
102
+ userId: patient.userId,
103
+ patientId: patient.id,
104
+ facilityId: patient.facilityId,
105
+ title: "Antenatal Care Visit",
106
+ type: "ANC",
107
+ dateTime: new Date(dto.nextAppointmentDate),
108
+ },
109
+ });
110
+ }
111
+
112
+ /**
113
+ * Close old unresolved alerts
114
+ * if patient is no longer high risk.
115
+ */
116
+ if (riskLevel === "LOW" || riskLevel === "MODERATE") {
117
+ await this.prisma.alert.updateMany({
118
  where: {
119
  patientId: patient.id,
120
  isResolved: false,
121
+ },
122
+ data: {
123
+ isResolved: true,
124
+ resolvedAt: new Date(),
125
  },
126
  });
127
+ }
128
 
129
+ /**
130
+ * Create new alert
131
+ */
132
+ if (riskLevel === "HIGH" || riskLevel === "EMERGENCY") {
133
+ const existingAlert = await this.prisma.alert.findFirst({
134
+ where: {
135
+ patientId: patient.id,
136
+ isResolved: false,
137
  type: riskLevel,
 
 
 
 
138
  },
139
  });
140
+
141
+ if (!existingAlert) {
142
+ await this.prisma.alert.create({
143
+ data: {
144
+ facilityId: patient.facilityId,
145
+ patientId: patient.id,
146
+ type: riskLevel,
147
+ message:
148
+ riskLevel === "EMERGENCY"
149
+ ? "Severely elevated blood pressure detected."
150
+ : "High-risk pregnancy detected during ANC visit.",
151
+ },
152
+ });
153
+ }
154
  }
 
155
 
156
+ return visit;
157
+ }
158
 
159
  async getPatientVisits(patientId: string) {
160
  const patient = await this.prisma.patient.findUnique({
 
262
  return defaulters.sort((a, b) => b.daysOverdue - a.daysOverdue);
263
  }
264
 
265
+ async getPatientSummary(patientId: string) {
266
+ const patient = await this.prisma.patient.findUnique({
 
 
 
267
  where: {
268
  id: patientId,
269
  },
270
  });
271
 
272
+ if (!patient) {
273
+ throw new NotFoundException("Patient not found");
274
+ }
 
 
275
 
276
+ const visits = await this.prisma.aNCVisit.findMany({
 
277
  where: {
278
  patientId,
279
  },
 
282
  },
283
  });
284
 
285
+ if (!visits.length) {
286
+ return {
287
+ totalVisits: 0,
288
+ lastVisitDate: null,
289
+ nextAppointmentDate: null,
290
+ riskLevel: "LOW",
291
+ missedAppointments: 0,
292
+ bpTrend: "UNKNOWN",
293
+ lastBloodPressure: null,
294
+ };
295
+ }
296
 
297
+ const latestVisit = visits[visits.length - 1];
 
298
 
299
+ const today = new Date();
300
 
301
+ const missedAppointments = visits.filter(
302
+ (v) => v.nextAppointmentDate && v.nextAppointmentDate < today,
 
 
 
303
  ).length;
304
 
305
+ let bpTrend = "STABLE";
306
+
307
+ const bpVisits = visits.filter(
308
+ (v) => v.bloodPressureSystolic && v.bloodPressureDiastolic,
309
+ );
310
+
311
+ if (bpVisits.length >= 2) {
312
+ const last = bpVisits[bpVisits.length - 1];
313
+
314
+ const previous = bpVisits[bpVisits.length - 2];
315
+
316
+ if (last.bloodPressureSystolic! > previous.bloodPressureSystolic!) {
317
+ bpTrend = "RISING";
318
+ } else if (
319
+ last.bloodPressureSystolic! < previous.bloodPressureSystolic!
320
+ ) {
321
+ bpTrend = "FALLING";
322
+ }
 
 
 
 
 
 
 
323
  }
 
324
 
325
+ return {
326
+ totalVisits: visits.length,
327
+ lastVisitDate: latestVisit.visitDate,
328
+ nextAppointmentDate: latestVisit.nextAppointmentDate,
329
+ riskLevel: latestVisit.riskLevel,
330
+ missedAppointments,
331
+ bpTrend,
332
+ lastBloodPressure: {
333
+ systolic: latestVisit.bloodPressureSystolic,
334
+ diastolic: latestVisit.bloodPressureDiastolic,
335
+ },
336
+ };
337
+ }
 
 
 
 
 
 
 
338
  }
src/appointments/appointments.service.ts CHANGED
@@ -1,8 +1,12 @@
1
- import { Injectable, NotFoundException } from '@nestjs/common';
2
- import { PrismaService } from '../database/prisma.service';
3
- import { CreateAppointmentDto } from './dto/create-appointment.dto';
4
- import { UpdateAppointmentDto } from './dto/update-appointment.dto';
5
- import { Appointment } from '@prisma/client';
 
 
 
 
6
 
7
  @Injectable()
8
  export class AppointmentsService {
@@ -12,30 +16,28 @@ export class AppointmentsService {
12
  healthcareWorkerId: string,
13
  dto: CreateAppointmentDto,
14
  ): Promise<Appointment> {
15
- const worker =
16
- await this.prisma.healthcareWorker.findUnique({
17
- where: {
18
- id: healthcareWorkerId,
19
- },
20
- });
21
 
22
  if (!worker) {
23
- throw new NotFoundException(
24
- "Healthcare worker not found",
25
- );
26
  }
27
 
28
- const patient =
29
- await this.prisma.patient.findUnique({
30
- where: {
31
- id: dto.patientId,
32
- },
33
- });
34
 
35
  if (!patient) {
36
- throw new NotFoundException(
37
- "Patient not found",
38
- );
 
 
39
  }
40
 
41
  return this.prisma.appointment.create({
@@ -52,20 +54,15 @@ export class AppointmentsService {
52
  });
53
  }
54
 
55
- async findAll(
56
- healthcareWorkerId: string,
57
- ): Promise<Appointment[]> {
58
- const worker =
59
- await this.prisma.healthcareWorker.findUnique({
60
- where: {
61
- id: healthcareWorkerId,
62
- },
63
- });
64
 
65
  if (!worker) {
66
- throw new NotFoundException(
67
- "Healthcare worker not found",
68
- );
69
  }
70
 
71
  return this.prisma.appointment.findMany({
@@ -82,33 +79,26 @@ export class AppointmentsService {
82
  });
83
  }
84
 
85
- async findOne(
86
- id: string,
87
- healthcareWorkerId: string,
88
- ) {
89
- const worker =
90
- await this.prisma.healthcareWorker.findUnique({
91
- where: {
92
- id: healthcareWorkerId,
93
- },
94
- });
95
-
96
- const appointment =
97
- await this.prisma.appointment.findFirst({
98
- where: {
99
- id,
100
- facilityId: worker?.facilityId,
101
- },
102
- include: {
103
- patient: true,
104
- facility: true,
105
- },
106
- });
107
 
108
  if (!appointment) {
109
- throw new NotFoundException(
110
- "Appointment not found",
111
- );
112
  }
113
 
114
  return appointment;
@@ -119,10 +109,7 @@ export class AppointmentsService {
119
  healthcareWorkerId: string,
120
  dto: UpdateAppointmentDto,
121
  ) {
122
- await this.findOne(
123
- id,
124
- healthcareWorkerId,
125
- );
126
 
127
  return this.prisma.appointment.update({
128
  where: {
@@ -137,14 +124,8 @@ export class AppointmentsService {
137
  });
138
  }
139
 
140
- async remove(
141
- id: string,
142
- healthcareWorkerId: string,
143
- ) {
144
- await this.findOne(
145
- id,
146
- healthcareWorkerId,
147
- );
148
 
149
  await this.prisma.appointment.delete({
150
  where: {
 
1
+ import {
2
+ BadRequestException,
3
+ Injectable,
4
+ NotFoundException,
5
+ } from "@nestjs/common";
6
+ import { PrismaService } from "../database/prisma.service";
7
+ import { CreateAppointmentDto } from "./dto/create-appointment.dto";
8
+ import { UpdateAppointmentDto } from "./dto/update-appointment.dto";
9
+ import { Appointment } from "@prisma/client";
10
 
11
  @Injectable()
12
  export class AppointmentsService {
 
16
  healthcareWorkerId: string,
17
  dto: CreateAppointmentDto,
18
  ): Promise<Appointment> {
19
+ const worker = await this.prisma.healthcareWorker.findUnique({
20
+ where: {
21
+ id: healthcareWorkerId,
22
+ },
23
+ });
 
24
 
25
  if (!worker) {
26
+ throw new NotFoundException("Healthcare worker not found");
 
 
27
  }
28
 
29
+ const patient = await this.prisma.patient.findUnique({
30
+ where: {
31
+ id: dto.patientId,
32
+ },
33
+ });
 
34
 
35
  if (!patient) {
36
+ throw new NotFoundException("Patient not found");
37
+ }
38
+
39
+ if (!patient.facilityId) {
40
+ throw new BadRequestException("Patient is not linked to a facility");
41
  }
42
 
43
  return this.prisma.appointment.create({
 
54
  });
55
  }
56
 
57
+ async findAll(healthcareWorkerId: string): Promise<Appointment[]> {
58
+ const worker = await this.prisma.healthcareWorker.findUnique({
59
+ where: {
60
+ id: healthcareWorkerId,
61
+ },
62
+ });
 
 
 
63
 
64
  if (!worker) {
65
+ throw new NotFoundException("Healthcare worker not found");
 
 
66
  }
67
 
68
  return this.prisma.appointment.findMany({
 
79
  });
80
  }
81
 
82
+ async findOne(id: string, healthcareWorkerId: string) {
83
+ const worker = await this.prisma.healthcareWorker.findUnique({
84
+ where: {
85
+ id: healthcareWorkerId,
86
+ },
87
+ });
88
+
89
+ const appointment = await this.prisma.appointment.findFirst({
90
+ where: {
91
+ id,
92
+ facilityId: worker?.facilityId,
93
+ },
94
+ include: {
95
+ patient: true,
96
+ facility: true,
97
+ },
98
+ });
 
 
 
 
 
99
 
100
  if (!appointment) {
101
+ throw new NotFoundException("Appointment not found");
 
 
102
  }
103
 
104
  return appointment;
 
109
  healthcareWorkerId: string,
110
  dto: UpdateAppointmentDto,
111
  ) {
112
+ await this.findOne(id, healthcareWorkerId);
 
 
 
113
 
114
  return this.prisma.appointment.update({
115
  where: {
 
124
  });
125
  }
126
 
127
+ async remove(id: string, healthcareWorkerId: string) {
128
+ await this.findOne(id, healthcareWorkerId);
 
 
 
 
 
 
129
 
130
  await this.prisma.appointment.delete({
131
  where: {
src/facilities/facilities.service.ts CHANGED
@@ -56,7 +56,12 @@ export class FacilitiesService {
56
 
57
  async update(
58
  id: string,
59
- data: { name?: string; address?: string; phone?: string; isActive?: boolean },
 
 
 
 
 
60
  ) {
61
  return this.prisma.facility.update({ where: { id }, data });
62
  }
@@ -230,14 +235,18 @@ export class FacilitiesService {
230
  },
231
  });
232
 
233
- if (!patient) return { linked: false };
234
-
 
 
 
 
235
  return {
236
- linked: true,
237
  facilityId: patient.facilityId,
238
- facilityName: patient.facility.name,
239
- facilityAddress: patient.facility.address,
240
- facilityPhone: patient.facility.phone,
241
  patientCode: patient.patientId,
242
  linkedAt: patient.createdAt,
243
  };
@@ -262,4 +271,4 @@ export class FacilitiesService {
262
  `Patient ${userId} unlinked from facility ${patient.facilityId}`,
263
  );
264
  }
265
- }
 
56
 
57
  async update(
58
  id: string,
59
+ data: {
60
+ name?: string;
61
+ address?: string;
62
+ phone?: string;
63
+ isActive?: boolean;
64
+ },
65
  ) {
66
  return this.prisma.facility.update({ where: { id }, data });
67
  }
 
235
  },
236
  });
237
 
238
+
239
+ if (!patient || !patient.facility) {
240
+ return {
241
+ linked: false,
242
+ };
243
+ }
244
  return {
245
+ linked: !!patient.facility,
246
  facilityId: patient.facilityId,
247
+ facilityName: patient.facility?.name ?? null,
248
+ facilityAddress: patient.facility?.address ?? null,
249
+ facilityPhone: patient.facility?.phone ?? null,
250
  patientCode: patient.patientId,
251
  linkedAt: patient.createdAt,
252
  };
 
271
  `Patient ${userId} unlinked from facility ${patient.facilityId}`,
272
  );
273
  }
274
+ }
src/patients/patients.service.ts CHANGED
@@ -200,6 +200,11 @@ export class PatientsService {
200
  }
201
 
202
  async getDefaulters(facilityId: string) {
 
 
 
 
 
203
  const sevenDaysAgo = new Date();
204
 
205
  sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
 
200
  }
201
 
202
  async getDefaulters(facilityId: string) {
203
+
204
+ if (!facilityId) {
205
+ return [];
206
+ }
207
+
208
  const sevenDaysAgo = new Date();
209
 
210
  sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
src/referral/referral.service.ts CHANGED
@@ -1,12 +1,14 @@
1
  // ─── referrals.service.ts ───────────────────────────────────────────────────
2
 
3
- import { Injectable, NotFoundException } from "@nestjs/common";
 
 
 
 
4
  import { PrismaService } from "../database/prisma.service";
5
 
6
  import { CreateReferralDto } from "./dto/create-referral-dto";
7
 
8
-
9
-
10
  export interface UpdateReferralDto {
11
  status: "PENDING" | "ACCEPTED" | "COMPLETED" | "CANCELLED";
12
  }
@@ -15,63 +17,56 @@ export interface UpdateReferralDto {
15
  export class ReferralsService {
16
  constructor(private readonly prisma: PrismaService) {}
17
 
18
- async create(
19
- dto: CreateReferralDto,
20
- facilityId: string,
21
- ) {
22
- const patient =
23
- await this.prisma.patient.findFirst({
24
  where: {
25
  id: dto.patientId,
26
  facilityId,
27
  },
28
  });
29
 
30
- if (!patient) {
31
- throw new NotFoundException(
32
- 'Patient not found',
33
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
- return this.prisma.referral.create({
37
- data: {
38
- patientId: patient.id,
39
- fromFacilityId: facilityId,
40
- toFacilityId:
41
- dto.toFacilityId,
42
- reason: dto.reason,
43
- notes: dto.notes,
44
- },
45
- });
46
- }
47
-
48
- async accept(
49
- referralId: string,
50
- ) {
51
- return this.prisma.referral.update({
52
- where: {
53
- id: referralId,
54
- },
55
- data: {
56
- status: 'ACCEPTED',
57
- acceptedAt: new Date(),
58
- },
59
- });
60
- }
61
 
62
- async complete(
63
- referralId: string,
64
- ) {
65
- return this.prisma.referral.update({
66
- where: {
67
- id: referralId,
68
- },
69
- data: {
70
- status: 'COMPLETED',
71
- completedAt: new Date(),
72
- },
73
- });
74
- }
75
 
76
  async findAll(facilityId?: string) {
77
  return this.prisma.referral.findMany({
@@ -151,5 +146,3 @@ async complete(
151
  return { total, pending, accepted, completed, cancelled };
152
  }
153
  }
154
-
155
-
 
1
  // ─── referrals.service.ts ───────────────────────────────────────────────────
2
 
3
+ import {
4
+ BadRequestException,
5
+ Injectable,
6
+ NotFoundException,
7
+ } from "@nestjs/common";
8
  import { PrismaService } from "../database/prisma.service";
9
 
10
  import { CreateReferralDto } from "./dto/create-referral-dto";
11
 
 
 
12
  export interface UpdateReferralDto {
13
  status: "PENDING" | "ACCEPTED" | "COMPLETED" | "CANCELLED";
14
  }
 
17
  export class ReferralsService {
18
  constructor(private readonly prisma: PrismaService) {}
19
 
20
+ async create(dto: CreateReferralDto, facilityId: string) {
21
+ const patient = await this.prisma.patient.findFirst({
 
 
 
 
22
  where: {
23
  id: dto.patientId,
24
  facilityId,
25
  },
26
  });
27
 
28
+ if (!patient) {
29
+ throw new NotFoundException("Patient not found");
30
+ }
31
+
32
+ if (!patient.facilityId) {
33
+ throw new BadRequestException("Patient is not linked to a facility");
34
+ }
35
+
36
+ return this.prisma.referral.create({
37
+ data: {
38
+ patientId: patient.id,
39
+ fromFacilityId: facilityId,
40
+ toFacilityId: dto.toFacilityId,
41
+ reason: dto.reason,
42
+ notes: dto.notes,
43
+ },
44
+ });
45
  }
46
 
47
+ async accept(referralId: string) {
48
+ return this.prisma.referral.update({
49
+ where: {
50
+ id: referralId,
51
+ },
52
+ data: {
53
+ status: "ACCEPTED",
54
+ acceptedAt: new Date(),
55
+ },
56
+ });
57
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ async complete(referralId: string) {
60
+ return this.prisma.referral.update({
61
+ where: {
62
+ id: referralId,
63
+ },
64
+ data: {
65
+ status: "COMPLETED",
66
+ completedAt: new Date(),
67
+ },
68
+ });
69
+ }
 
 
70
 
71
  async findAll(facilityId?: string) {
72
  return this.prisma.referral.findMany({
 
146
  return { total, pending, accepted, completed, cancelled };
147
  }
148
  }