Skip to content

Commit 546f6b7

Browse files
committed
Reorganise the parent details for clinic bookings
This commit moves the Parent object to the ClinicBooking, removing it from the ClinicAppointment (but adding parental relationship properties to the appointment). This should simplify various areas, removing the need to propagate contact details to multiple appointments in the same booking. The changes here required changes to the generation of fake data too and triggered a bit of fixing.
1 parent 9bce9f3 commit 546f6b7

10 files changed

Lines changed: 131 additions & 109 deletions

File tree

app/controllers/book-into-a-clinic.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { kebabToCamelCase } from '../utils/string.js'
99
export const bookIntoClinicController = {
1010
/**
1111
* Record the session preset
12+
*
1213
* @param {*} request
1314
* @param {*} response
1415
* @param {*} next
@@ -164,7 +165,7 @@ export const bookIntoClinicController = {
164165
{
165166
[`/${session_preset_slug}/new/${appointment_uuid}/vaccination-choice`]:
166167
{
167-
data: 'appointment.parent.hasParentalResponsibility',
168+
data: 'appointment.parentHasParentalResponsibility',
168169
value: 'true'
169170
}
170171
},
@@ -203,7 +204,7 @@ export const bookIntoClinicController = {
203204
// Parent journey
204205
[`/${session_preset_slug}/${booking_uuid}/new/parent`]: {
205206
[`/${session_preset_slug}/${booking_uuid}/new/offer-health-questions`]:
206-
() => !booking?.parentTel
207+
() => !booking?.parent?.tel
207208
},
208209
[`/${session_preset_slug}/${booking_uuid}/new/contact-preference`]: {},
209210

app/generators/clinic-appointment.js

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,31 @@ import { addMinutes } from 'date-fns'
33
import _ from 'lodash'
44

55
import { ParentalRelationship, SessionType } from '../enums.js'
6-
import { ClinicAppointment, Parent } from '../models.js'
6+
import { ClinicAppointment } from '../models.js'
77
import { getAge } from '../utils/date.js'
88

9-
import { generateParent } from './parent.js'
10-
119
const clinicSlotLength = Number(process.env.CLINIC_SLOT_LENGTH) || 10
1210

1311
/**
1412
* Generate fake clinic appointment
1513
*
16-
* @param {string} booking_uuid - The UUID of the booking this appointment belongs to
17-
* @param {Parent|null} parentFromFirstAppointment - The parent from the first appointment created in the same booking, if this appointment is not the first
14+
* @param {ClinicBooking} booking - The booking this appointment will belong to
1815
* @param {object} context - The other data already defined (sessions, children, etc.)
1916
* @returns {ClinicAppointment} A new, fake clinic appointment
2017
*/
21-
export function generateClinicAppointment(
22-
booking_uuid,
23-
parentFromFirstAppointment,
24-
context
25-
) {
18+
export function generateClinicAppointment(booking, context) {
2619
const uuid = faker.string.uuid()
2720

2821
// Choose a clinic session to book this appointment into
2922
const clinicSessions = Object.values(context.sessions).filter(
30-
(s) => s.type === SessionType.Clinic
23+
(s) =>
24+
s.type === SessionType.Clinic &&
25+
s.presetNames.includes(booking.sessionPreset.name)
3126
)
3227
const clinicSession = faker.helpers.arrayElement(clinicSessions)
28+
if (!clinicSession) {
29+
return null
30+
}
3331
const session_id = clinicSession.id
3432

3533
// Work out the expected age range for children attending this session
@@ -60,80 +58,87 @@ export function generateClinicAppointment(
6058
? undefined
6159
: faker.date.birthdate({ min: minAge, max: maxAge, mode: 'age' })
6260

63-
// Parent details and relationship
64-
let parent
65-
if (!parentFromFirstAppointment) {
66-
// This is the first appointment for the booking, so we're free to CREATE the parent details
67-
if (matchedPatient) {
68-
parent =
69-
(matchedPatient.parent1 || matchedPatient.parent2) ??
70-
generateParent(matchedPatient.lastName, faker.datatype.boolean(0.5))
71-
} else {
72-
parent = generateParent(unmatchedLastName, faker.datatype.boolean(0.5))
73-
}
74-
} else {
75-
// Copy parent details from the first appointment and possibly adapt the relationship
76-
parent = new Parent(parentFromFirstAppointment)
77-
parent.uuid = faker.string.uuid()
78-
79-
// Set up the relationship to the child for this appointment
80-
if (
81-
[ParentalRelationship.Mum, ParentalRelationship.Dad].includes(
82-
parentFromFirstAppointment.relationship
83-
)
84-
) {
61+
// Set up the relationship to the child for this appointment
62+
const parent = booking.parent
63+
let parentalRelationship,
64+
parentalRelationshipOther,
65+
parentHasParentalResponsibility
66+
if (parent) {
67+
const mumOrDad = [
68+
ParentalRelationship.Mum,
69+
ParentalRelationship.Dad
70+
].includes(parent.relationship)
71+
if (mumOrDad) {
8572
// Mum or Dad initially, and most likely to stay that way
8673
if (faker.datatype.boolean(0.1)) {
87-
parent.relationship = faker.helpers.arrayElement([
74+
parentalRelationship = faker.helpers.arrayElement([
8875
ParentalRelationship.Fosterer,
8976
ParentalRelationship.Guardian,
9077
ParentalRelationship.Other
9178
])
92-
parent.relationshipOther =
93-
parent.relationship === ParentalRelationship.Other
79+
parentalRelationshipOther =
80+
parentalRelationship === ParentalRelationship.Other
9481
? 'Grandparent'
9582
: undefined
83+
parentHasParentalResponsibility = true
9684
}
9785
} else {
9886
// Fosterer, Guardian or Other
99-
parent.relationship = parentFromFirstAppointment.relationship
100-
parent.relationshipOther = parentFromFirstAppointment.relationshipOther
87+
parentalRelationship = parent.relationship
88+
parentalRelationshipOther = parent.relationshipOther
89+
parentHasParentalResponsibility = parent.hasParentalResponsibility
10190
}
10291
}
10392

10493
// Slot details (NB: session date is expected to specify midday)
94+
const needsExtraTime = faker.datatype.boolean(0.2)
95+
let extraTimeReason
96+
if (needsExtraTime) {
97+
const phobia = faker.helpers.weightedArrayElement([
98+
{ value: 'needles', weight: 90 },
99+
{ value: 'nurses', weight: 8 },
100+
{ value: 'vaccines', weight: 2 }
101+
])
102+
extraTimeReason = `Suffers from anxiety regarding ${phobia}`
103+
}
105104
const startAt = addMinutes(
106105
clinicSession.date,
107106
faker.number.int({ min: 0, max: 60, multipleOf: clinicSlotLength })
108107
)
109-
const endAt = addMinutes(startAt, clinicSlotLength)
108+
const endAt = addMinutes(startAt, clinicSlotLength * (needsExtraTime ? 2 : 1))
110109

111110
// Have the child signed up for the clinic's primary programme plus a random selection of other programmes
111+
const primary_programme_ids = clinicSession.programme_ids
112112
const additionalProgramme_ids = Object.values(context.programmes)
113113
.filter((p) => p.hidden !== true)
114114
.map((p) => p.id)
115115
.filter(
116116
(id) =>
117117
!clinicSession.programme_ids.includes(id) && faker.datatype.boolean(0.2)
118118
)
119-
const programme_ids = [
120-
...clinicSession.programme_ids,
119+
const selected_programme_ids = [
120+
...primary_programme_ids,
121121
...additionalProgramme_ids
122122
]
123123

124124
return new ClinicAppointment(
125125
{
126126
uuid,
127-
booking_uuid,
127+
booking_uuid: booking.uuid,
128128
patient_uuid,
129129
unmatchedFirstName,
130130
unmatchedLastName,
131131
unmatchedDob,
132-
parent,
132+
needsExtraTime,
133+
extraTimeReason,
134+
parentalRelationship,
135+
parentalRelationshipOther,
136+
parentHasParentalResponsibility,
133137
session_id,
134138
startAt,
135139
endAt,
136-
programme_ids
140+
selected_programme_ids,
141+
primary_programme_ids
137142
},
138143
context
139144
)

app/generators/clinic-booking.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { fakerEN_GB as faker } from '@faker-js/faker'
22

3+
import { SessionPresets } from '../enums.js'
34
import { ClinicBooking } from '../models.js'
45

56
/**
@@ -11,11 +12,13 @@ import { ClinicBooking } from '../models.js'
1112
export function generateEmptyClinicBooking(context) {
1213
const uuid = faker.string.uuid()
1314
const bookingReference = ClinicBooking.generateReference()
15+
const sessionPreset = faker.helpers.arrayElement(SessionPresets)
1416

1517
return new ClinicBooking(
1618
{
1719
uuid,
18-
bookingReference
20+
bookingReference,
21+
sessionPreset
1922
},
2023
context
2124
)

app/models/clinic-appointment.js

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ import {
3030
* @property {object} [unmatchedDob_] - Child date of birth, if not matched to a patient record (for use with decorate)
3131
* @property {Boolean} needsExtraTime - Does the child need extra time for their vaccinations?
3232
* @property {string} [extraTimeReason] - The reason why the child needs extra time for their appointment
33-
* @property {Parent} [parent] - The parent/carer who booked this appointment
33+
* @property {ParentalRelationship} [parentalRelationship] - The relationship of the person booking the appointment to the child
34+
* @property {string} [parentalRelationshipOther] - User-defined parental relationship to the child for this appointment
35+
* @property {boolean} [parentHasParentalResponsibility] - Does the parent/carer have legal parental responsibility for the child?
3436
* @property {string} [session_id] - The ID of the clinic session in which the appointment's booked
3537
* @property {Date} [startAt] - Slot start time
3638
* @property {Date} [endAt] - Slot end time
37-
* @property {Array<string>} [primary_programme_ids] - IDs of programmes signed up for
39+
* @property {Array<string>} [primary_programme_ids] - IDs of primary programmes for this clinic booking
3840
* @property {Array<string>} [selected_programme_ids] - IDs of programmes signed up for
3941
* @property {object} [healthAnswers] - Answers to health questions
4042
*/
@@ -53,7 +55,10 @@ export class ClinicAppointment {
5355
this.needsExtraTime = options?.needsExtraTime
5456
this.extraTimeReason = options?.extraTimeReason
5557

56-
this.parent = options?.parent && new Parent(options.parent)
58+
this.parentalRelationship = options?.parentalRelationship
59+
this.parentalRelationshipOther = options?.parentalRelationshipOther
60+
this.parentHasParentalResponsibility =
61+
options?.parentHasParentalResponsibility
5762

5863
this.session_id = options?.session_id
5964
this.startAt = options?.startAt ? new Date(options.startAt) : undefined
@@ -120,17 +125,49 @@ export class ClinicAppointment {
120125
}
121126
}
122127

128+
/**
129+
* Get a parent object combining the parent's contact details held in the
130+
* booking with the parental relationship for this appointment's child
131+
*/
132+
get parent() {
133+
const booking = this.clinicBooking
134+
if (booking) {
135+
const parent = new Parent(booking.parent)
136+
return _.merge(parent, {
137+
relationship: this.parentalRelationship,
138+
relationshipOther: this.parentalRelationshipOther,
139+
hasParentalResponsibility: this.parentHasParentalResponsibility
140+
})
141+
}
142+
143+
return undefined
144+
}
145+
146+
/**
147+
* Get first name of the child booked into this appointment
148+
*
149+
* @returns {string} Child's first name
150+
*/
151+
get firstName() {
152+
return this.patient ? this.patient.firstName : this.unmatchedFirstName
153+
}
154+
155+
/**
156+
* Get last name of the child booked into this appointment
157+
*
158+
* @returns {string} Child's last name
159+
*/
160+
get lastName() {
161+
return this.patient ? this.patient.lastName : this.unmatchedLastName
162+
}
163+
123164
/**
124165
* Get full name of the child booked into this appointment
125166
*
126167
* @returns {string} Child's full name
127168
*/
128169
get fullName() {
129-
const patient = this.patient
130-
if (patient) {
131-
return `${patient.firstName} ${patient.lastName}`
132-
}
133-
return `${this.unmatchedFirstName} ${this.unmatchedLastName}`
170+
return `${this.firstName} ${this.lastName}`
134171
}
135172

136173
/**

app/models/clinic-booking.js

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import _ from 'lodash'
33

44
import allProgrammesData from '../datasets/programmes.js'
55
import { SessionPresets } from '../enums.js'
6-
import { ClinicAppointment, Programme } from '../models.js'
6+
import { ClinicAppointment, Parent, Programme } from '../models.js'
77

88
/**
99
* @class ClinicBooking
@@ -13,7 +13,7 @@ import { ClinicAppointment, Programme } from '../models.js'
1313
* @property {string} uuid - Clinic booking UUID
1414
* @property {string} bookingReference - Booking reference number
1515
* @property {SessionPreset} sessionPreset - the primary programme for which the parent was invited to book e.g. doubles
16-
* @property {number} childCount - the number of children that the parent wants to book in in one go
16+
* @property {Parent} parent - contact details for the parent making the booking; see appointments for parental relationship details
1717
* @property {Array<string>} [appointments_ids] - Unique IDs of children's appointments (one parent may book in multiple children under one booking)
1818
*/
1919
export class ClinicBooking {
@@ -23,8 +23,9 @@ export class ClinicBooking {
2323
this.bookingReference =
2424
options?.bookingReference || ClinicBooking.generateReference()
2525
this.sessionPreset = options?.sessionPreset ?? SessionPresets[0]
26+
this.parent =
27+
(options?.parent && new Parent(options.parent)) ?? new Parent({})
2628

27-
this.childCount = options?.childCount
2829
this.appointments_ids = options?.appointments_ids ?? []
2930
}
3031

@@ -114,35 +115,6 @@ export class ClinicBooking {
114115
)
115116
}
116117

117-
/**
118-
* Get the parent details from the first appointment
119-
*
120-
* This is only intended to allow us to present the parent's name, email and so on, but not to
121-
* represent the parent's relationship to all the children in this booking, as the relationship
122-
* may vary by chiuld.
123-
*
124-
* @returns {Parent|undefined} Parent details from the first appointment
125-
*/
126-
get firstParent() {
127-
return this.appointments?.[0]?.parent
128-
}
129-
130-
/**
131-
*
132-
*/
133-
set parentTel(value) {
134-
if (value) {
135-
this.appointments.forEach((appt) => (appt.parent.tel = value))
136-
}
137-
}
138-
139-
/**
140-
*
141-
*/
142-
get parentTel() {
143-
return this.firstParent?.tel
144-
}
145-
146118
/**
147119
* Get various formatted values for display in the page
148120
*

app/views/book-into-a-clinic/form/contact-preference.njk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
conditional: {
2121
html: textarea({
2222
label: { text: __("clinicBooking.parent.contactPreferenceDetails.label") },
23-
decorate: "booking.parentContactPreferenceDetails"
23+
decorate: "booking.parent.contactPreferenceDetails"
2424
})
2525
}
2626
}, {
2727
text: __("clinicBooking.parent.contactPreference.no")
2828
}],
29-
decorate: "booking.parentContactPreference"
29+
decorate: "booking.parent.contactPreference"
3030
}) }}
3131
{% endblock %}

0 commit comments

Comments
 (0)