Skip to content

Commit ed9e67e

Browse files
Add support for half day sessions
1 parent 947845d commit ed9e67e

File tree

4 files changed

+109
-41
lines changed

4 files changed

+109
-41
lines changed

app/config.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,12 @@ module.exports = {
2525

2626
// Clinic settings
2727
clinics: {
28-
// Timing
29-
startTime: '09:00',
30-
endTime: '17:00',
28+
// Timings
3129
slotDurationMinutes: 8,
32-
slotsPerDay: 32,
3330

34-
// Capacity
35-
targetBookings: 60,
36-
targetAttendance: 40,
31+
// Target percentages
32+
targetBookingPercent: 150, // 150% represents overbooking (e.g. 60 bookings for 40 slots)
33+
targetAttendancePercent: 100, // 100% of original capacity (not overbooking)
3734

3835
// Date range for generating data
3936
daysToGenerate: 7,

app/data/breast-screening-units.js

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,24 @@ module.exports = [
1515
},
1616
phoneNumber: "01865235621",
1717
abbreviation: "OXF",
18+
// Default operating hours for the BSU
19+
sessionPatterns: [
20+
{
21+
name: 'full_day',
22+
type: 'single',
23+
sessions: [
24+
{ startTime: "09:00", endTime: "17:00" }
25+
]
26+
},
27+
{
28+
name: 'split_day',
29+
type: 'paired',
30+
sessions: [
31+
{ startTime: "09:00", endTime: "12:00" },
32+
{ startTime: "13:00", endTime: "17:00" }
33+
]
34+
}
35+
],
1836
locations: [
1937
{
2038
id: "duif1ywp", // Must be hardcoded so it matches generated data
@@ -47,14 +65,34 @@ module.exports = [
4765
name: "Mobile Unit WX71 HCP",
4866
type: "mobile_unit",
4967
isMainSite: false,
50-
registration: "WX71 HCP"
68+
registration: "WX71 HCP",
69+
// Override BSU session patterns for this location
70+
sessionPatterns: [
71+
{
72+
name: 'full_day',
73+
type: 'single',
74+
sessions: [
75+
{ startTime: "09:00", endTime: "17:00" }
76+
]
77+
}
78+
]
5179
},
5280
{
5381
id: "acxcdcnj", // Must be hardcoded so it matches generated data
5482
name: "Mobile Unit WX71 HCR",
5583
type: "mobile_unit",
5684
isMainSite: false,
57-
registration: "WX71 HCR"
85+
registration: "WX71 HCR",
86+
// Override BSU session patterns for this location
87+
sessionPatterns: [
88+
{
89+
name: 'full_day',
90+
type: 'single',
91+
sessions: [
92+
{ startTime: "09:00", endTime: "17:00" }
93+
]
94+
}
95+
]
5896
}
5997
]
6098
}

app/lib/generate-seed-data.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ const generateData = async () => {
4444
breastScreeningUnits.forEach(unit => {
4545
const newClinics = generateClinicsForBSU({
4646
date: clinicDate,
47-
breastScreeningUnit: unit,
48-
config: config.clinics
47+
breastScreeningUnit: unit
4948
});
5049

5150
// Generate events for each clinic

app/lib/generators/clinic-generator.js

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ const generateId = require('../utils/id-generator');
55
const dayjs = require('dayjs');
66
const config = require('../../config');
77

8-
const generateTimeSlots = (date, config) => {
8+
9+
const generateTimeSlots = (date, sessionTimes) => {
10+
const { slotDurationMinutes } = config.clinics;
11+
912
const slots = [];
10-
const startTime = new Date(`${date.toISOString().split('T')[0]}T${config.startTime}`);
11-
const endTime = new Date(`${date.toISOString().split('T')[0]}T${config.endTime}`);
13+
const startTime = new Date(`${date.toISOString().split('T')[0]}T${sessionTimes.startTime}`);
14+
const endTime = new Date(`${date.toISOString().split('T')[0]}T${sessionTimes.endTime}`);
1215

1316
let currentTime = new Date(startTime);
1417
while (currentTime < endTime) {
@@ -18,9 +21,10 @@ const generateTimeSlots = (date, config) => {
1821
dateTime: new Date(currentTime).toISOString(),
1922
type: 'screening',
2023
capacity: 2,
21-
bookedCount: 0
24+
bookedCount: 0,
25+
period: `${sessionTimes.startTime}-${sessionTimes.endTime}`
2226
});
23-
currentTime.setMinutes(currentTime.getMinutes() + config.slotDurationMinutes);
27+
currentTime.setMinutes(currentTime.getMinutes() + slotDurationMinutes);
2428
}
2529
return slots;
2630
};
@@ -56,36 +60,66 @@ const generateMobileSiteName = () => {
5660
return faker.helpers.arrayElement(sites);
5761
};
5862

59-
// Generate multiple clinics for a BSU on a given day
60-
const generateClinicsForBSU = ({ date, breastScreeningUnit, config: clinicConfig }) => {
61-
// Determine number of clinics for this BSU today (1-2)
62-
const numberOfClinics = Math.random() < 0.3 ? 2 : 1;
63+
const determineSessionType = (sessionTimes) => {
64+
const startHour = parseInt(sessionTimes.startTime.split(':')[0], 10);
65+
return startHour < 12 ? 'morning' : 'afternoon';
66+
};
67+
68+
const generateClinic = (date, location, breastScreeningUnit, sessionTimes) => {
69+
const slots = generateTimeSlots(date, sessionTimes);
70+
71+
return {
72+
id: generateId(),
73+
date: date.toISOString().split('T')[0],
74+
breastScreeningUnitId: breastScreeningUnit.id,
75+
clinicType: location.type,
76+
locationId: location.id,
77+
siteName: location.type === 'mobile_unit' ? generateMobileSiteName() : null,
78+
slots,
79+
status: determineClinicStatus(date),
80+
staffing: {
81+
mamographers: [],
82+
radiologists: [],
83+
support: []
84+
},
85+
targetCapacity: {
86+
bookingPercent: config.clinics.targetBookingPercent,
87+
attendancePercent: config.clinics.targetAttendancePercent,
88+
totalSlots: slots.length * 2
89+
},
90+
notes: null,
91+
sessionTimes,
92+
sessionType: determineSessionType(sessionTimes)
93+
};
94+
};
95+
96+
const generateClinicsForBSU = ({ date, breastScreeningUnit }) => {
97+
// Determine number of clinic locations for this day (1-2)
98+
const numberOfLocations = Math.random() < 0.3 ? 2 : 1;
6399

64-
// Randomly select locations from available ones
100+
// Randomly select locations
65101
const selectedLocations = faker.helpers.arrayElements(
66102
breastScreeningUnit.locations,
67-
{ min: numberOfClinics, max: numberOfClinics }
103+
{ min: numberOfLocations, max: numberOfLocations }
68104
);
69105

70-
return selectedLocations.map(location => {
71-
return {
72-
id: generateId(),
73-
date: date.toISOString().split('T')[0],
74-
breastScreeningUnitId: breastScreeningUnit.id,
75-
clinicType: location.type,
76-
locationId: location.id,
77-
siteName: location.type === 'mobile_unit' ? generateMobileSiteName() : null,
78-
slots: generateTimeSlots(date, clinicConfig),
79-
status: determineClinicStatus(date),
80-
staffing: {
81-
mamographers: [],
82-
radiologists: [],
83-
support: []
84-
},
85-
targetBookings: clinicConfig.targetBookings,
86-
targetAttendance: clinicConfig.targetAttendance,
87-
notes: null
88-
};
106+
// Generate clinics for each location
107+
return selectedLocations.flatMap(location => {
108+
// Use location-specific patterns if available, otherwise use BSU patterns
109+
const sessionPatterns = location.sessionPatterns || breastScreeningUnit.sessionPatterns;
110+
111+
// Randomly select a pattern
112+
const selectedPattern = faker.helpers.arrayElement(sessionPatterns);
113+
114+
if (selectedPattern.type === 'single') {
115+
// For single sessions, create one clinic
116+
return [generateClinic(date, location, breastScreeningUnit, selectedPattern.sessions[0])];
117+
} else {
118+
// For paired sessions, create two clinics
119+
return selectedPattern.sessions.map(sessionTimes =>
120+
generateClinic(date, location, breastScreeningUnit, sessionTimes)
121+
);
122+
}
89123
});
90124
};
91125

0 commit comments

Comments
 (0)