Skip to content

Commit 5df06a2

Browse files
authored
APPT-2338 New recurrence document and example json (#1645)
The recurrence typed cosmos document with properties and format to be used in the upcoming recurrence work. Includes labels, recurrencePattern, version, exceptions, overrideSession and servicePatch classes. 'OverrideSession' has to be a different class from the Core one, as it is not allowed SlotLength to override, and services is an array of patchOperations. Partitioned by site.
1 parent 1cfb61b commit 5df06a2

4 files changed

Lines changed: 333 additions & 0 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{
2+
"id": "c5858f02-05d7-419b-865f-818599a6c0e0",
3+
"version": 1,
4+
"docType": "recurrence",
5+
"site": "6877d86e-c2df-4def-8508-e1eccf0ea6be",
6+
"label": "Summer Schedule For Permanent Staff",
7+
8+
"recurrencePattern": {
9+
"frequency": "Weekly",
10+
"interval": 1,
11+
"byDay": [
12+
1,
13+
2,
14+
3,
15+
//closed thursdays
16+
5
17+
],
18+
"startDate": "2026-05-01",
19+
"endDate": "2026-08-01",
20+
"session": {
21+
"from": "09:00",
22+
"until": "17:00",
23+
"slotLength": 10,
24+
"capacity": 5,
25+
"services": [
26+
"COVID:5_11",
27+
"RSV:Adult",
28+
"FLU:18_64",
29+
"COVID:18+"
30+
]
31+
}
32+
},
33+
"exceptions": [
34+
{
35+
//one-off closure for a single day
36+
//no session prop defined means closed, not overridden
37+
"date": "2026-05-09"
38+
},
39+
{
40+
//closure date range
41+
//no session prop can be defined when the dateRange props are used (override ranges are NOT permitted!!)
42+
"label": "Bank Holiday Closure",
43+
"dateRange": {
44+
"startDate": "2026-05-10",
45+
"endDate": "2026-05-13"
46+
}
47+
},
48+
{
49+
//one-off override
50+
"label": "Ran out of Covid stock",
51+
"date": "2026-06-01",
52+
//any defined props here override the parent session props
53+
//according to our override business logic
54+
//any undefined props use the parent session props
55+
"session": {
56+
"services": [
57+
{
58+
"operation": "remove",
59+
"service": "COVID:18+"
60+
}
61+
]
62+
}
63+
},
64+
{
65+
//one-off override
66+
"label": "One-off MeningitusB offering",
67+
"date": "2026-06-24",
68+
"session": {
69+
"services": [
70+
{
71+
"operation": "add",
72+
"service": "MenB"
73+
}
74+
]
75+
}
76+
},
77+
{
78+
//one-off override
79+
"label": "Closing early",
80+
"date": "2026-06-02",
81+
"session": {
82+
"from": "09:00",
83+
"until": "15:00"
84+
}
85+
},
86+
{
87+
//one-off override
88+
"label": "Extended opening hours",
89+
"date": "2026-06-13",
90+
"session": {
91+
"from": "07:00",
92+
"until": "20:00"
93+
}
94+
},
95+
{
96+
//one-off override
97+
"label": "Jonny and Paul are ill",
98+
"date": "2026-06-04",
99+
"session": {
100+
"capacity": 3
101+
}
102+
}
103+
],
104+
"createdOn": "2026-03-25T14:54:31.233324Z",
105+
"createdBy": "jonathan.dyson1@nhs.net",
106+
"lastUpdatedBy": "jonathan.dyson1@nhs.net",
107+
"lastUpdatedOn": "2026-03-25T14:54:31.233324Z"
108+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
{
2+
"id": "c5858f02-05d7-419b-865f-818599a6c0e0",
3+
"version": 1,
4+
"docType": "recurrence",
5+
"site": "6877d86e-c2df-4def-8508-e1eccf0ea6be",
6+
"label": "Summer Schedule For Permanent Staff",
7+
8+
"recurrencePattern": {
9+
"frequency": "Weekly",
10+
"interval": 1,
11+
"byDay": [
12+
1,
13+
2,
14+
3,
15+
{
16+
//future option for override every thursday has a different time schedule
17+
//all other days use the default session data
18+
"day": 4,
19+
"session": {
20+
"from": "10:00",
21+
"until": "16:00"
22+
}
23+
},
24+
5
25+
],
26+
"startDate": "2026-05-01",
27+
"endDate": "2026-08-01",
28+
"session": {
29+
"from": "09:00",
30+
"until": "17:00",
31+
"slotLength": 10,
32+
"capacity": 5,
33+
"services": [
34+
"COVID:5_11",
35+
"RSV:Adult",
36+
"FLU:18_64",
37+
"COVID:18+"
38+
]
39+
}
40+
},
41+
"exceptions": [
42+
{
43+
//one-off closure for a single day
44+
//no session prop defined means closed, not overridden
45+
"date": "2026-05-09"
46+
},
47+
{
48+
//closure date range
49+
//no session prop can be defined when the dateRange props are used (override ranges are NOT permitted!!)
50+
"label": "Bank Holiday Closure",
51+
"dateRange": {
52+
"startDate": "2026-05-10",
53+
"endDate": "2026-05-13"
54+
}
55+
},
56+
{
57+
//one-off override
58+
"label": "Ran out of Covid stock",
59+
"date": "2026-06-01",
60+
//any defined props here override the parent session props
61+
//according to our override business logic
62+
//any undefined props use the parent session props
63+
"session": {
64+
"services": [
65+
{
66+
"operation": "remove",
67+
"service": "COVID:18+"
68+
}
69+
]
70+
}
71+
},
72+
{
73+
//one-off override
74+
"label": "One-off Meningitus offering",
75+
"date": "2026-06-24",
76+
"session": {
77+
"services": [
78+
{
79+
"operation": "add",
80+
"service": "MenB"
81+
}
82+
]
83+
}
84+
},
85+
{
86+
//one-off override
87+
"label": "Closing early",
88+
"date": "2026-06-02",
89+
"session": {
90+
"from": "09:00",
91+
"until": "15:00"
92+
}
93+
},
94+
{
95+
//one-off override
96+
"label": "Extended opening hours",
97+
"date": "2026-06-13",
98+
"session": {
99+
"from": "07:00",
100+
"until": "20:00"
101+
}
102+
},
103+
{
104+
//one-off override
105+
"label": "Jonny and Paul are ill",
106+
"date": "2026-06-04",
107+
"session": {
108+
"capacity": 3
109+
}
110+
}
111+
],
112+
"createdOn": "2026-03-25T14:54:31.233324Z",
113+
"createdBy": "jonathan.dyson1@nhs.net",
114+
"lastUpdatedBy": "jonathan.dyson1@nhs.net",
115+
"lastUpdatedOn": "2026-03-25T14:54:31.233324Z"
116+
}

src/api/Nhs.Appointments.Persistance/Models/GeneralCosmosDocument.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ public class BookingDataCosmosDocument : LastUpdatedByCosmosDocument
2727
public string Site { get; set; }
2828
}
2929

30+
[CosmosDocument("recurrence_data", "site")]
31+
public class RecurrenceDataCosmosDocument : LastUpdatedByCosmosDocument
32+
{
33+
[JsonProperty("site")]
34+
public string Site { get; set; }
35+
}
36+
3037
[CosmosDocument("core_data", "docType")]
3138
public class CoreDataCosmosDocument : LastUpdatedByCosmosDocument
3239
{
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using Newtonsoft.Json;
2+
using Nhs.Appointments.Core.Availability;
3+
4+
namespace Nhs.Appointments.Persistance.Models;
5+
6+
[CosmosDocumentType("recurrence")]
7+
public class RecurrenceDocument : RecurrenceDataCosmosDocument
8+
{
9+
[JsonProperty("version")]
10+
public int Version { get; set; }
11+
12+
[JsonProperty("label")]
13+
public string Label { get; set; }
14+
15+
[JsonProperty("recurrencePattern")]
16+
public RecurrencePattern RecurrencePattern { get; set; }
17+
18+
[JsonProperty("exceptions")]
19+
public RecurrenceException[] RecurrenceExceptions { get; set; }
20+
21+
[JsonProperty("createdBy")]
22+
public string CreatedBy { get; set; }
23+
24+
[JsonProperty("createdOn")]
25+
public DateTime CreatedOn { get; set; }
26+
}
27+
28+
public class RecurrencePattern
29+
{
30+
[JsonProperty("startDate")]
31+
public DateOnly StartDate { get; set; }
32+
33+
[JsonProperty("endDate")]
34+
public DateOnly EndDate { get; set; }
35+
36+
[JsonProperty("frequency")]
37+
public string Frequency { get; set; }
38+
39+
[JsonProperty("interval")]
40+
public int Interval { get; set; }
41+
42+
[JsonProperty("byDay")]
43+
public DayOfWeek[] ByDay { get; set; }
44+
45+
[JsonProperty("session")]
46+
public Session Session { get; set; }
47+
}
48+
49+
public class RecurrenceException
50+
{
51+
[JsonProperty("label")]
52+
public string Label { get; set; }
53+
54+
[JsonProperty("date")]
55+
public DateOnly Date { get; set; }
56+
57+
[JsonProperty("dateRange")]
58+
public DateRange DateRange { get; set; }
59+
60+
[JsonProperty("session")]
61+
public OverrideSession OverrideSession { get; set; }
62+
}
63+
64+
public class DateRange
65+
{
66+
[JsonProperty("startDate")]
67+
public DateOnly StartDate { get; set; }
68+
69+
[JsonProperty("endDate")]
70+
public DateOnly EndDate { get; set; }
71+
}
72+
73+
public class OverrideSession
74+
{
75+
[JsonProperty("from")]
76+
public TimeOnly From { get; set; }
77+
78+
[JsonProperty("until")]
79+
public TimeOnly Until { get; set; }
80+
81+
[JsonProperty("services")]
82+
public ServicePatch[] ServicePatches { get; set; }
83+
84+
[JsonProperty("capacity")]
85+
public int Capacity { get; set; }
86+
}
87+
88+
public class ServicePatch
89+
{
90+
[JsonProperty("service")]
91+
public string Service { get; set; }
92+
93+
[JsonProperty("operation")]
94+
public PatchEnum Operation { get; set; }
95+
}
96+
97+
public enum PatchEnum
98+
{
99+
Undefined = 0,
100+
Add = 1,
101+
Remove = 2,
102+
}

0 commit comments

Comments
 (0)