@planning-inspectorate/data-model 2.14.0 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/docs/nsip-project-defs-meeting.md +39 -10
  2. package/docs/nsip-project.md +39 -10
  3. package/package.json +1 -1
  4. package/pins_data_model/models/model_appeal_document.py +1 -1
  5. package/pins_data_model/models/model_appeal_event.py +1 -1
  6. package/pins_data_model/models/model_appeal_event_estimate.py +1 -1
  7. package/pins_data_model/models/model_appeal_has.py +1 -1
  8. package/pins_data_model/models/model_appeal_representation.py +1 -1
  9. package/pins_data_model/models/model_appeal_s78.py +1 -1
  10. package/pins_data_model/models/model_dart_response.py +1 -1
  11. package/pins_data_model/models/model_entraid.py +1 -1
  12. package/pins_data_model/models/model_folder.py +1 -1
  13. package/pins_data_model/models/model_gettimesheets_response.py +1 -1
  14. package/pins_data_model/models/model_listed_building.py +1 -1
  15. package/pins_data_model/models/model_listed_buildings.py +1 -1
  16. package/pins_data_model/models/model_nsip_document.py +1 -1
  17. package/pins_data_model/models/model_nsip_exam_timetable.py +1 -1
  18. package/pins_data_model/models/model_nsip_invoice.py +1 -1
  19. package/pins_data_model/models/model_nsip_meeting.py +1 -1
  20. package/pins_data_model/models/model_nsip_project.py +8 -2
  21. package/pins_data_model/models/model_nsip_project_update.py +1 -1
  22. package/pins_data_model/models/model_nsip_representation.py +1 -1
  23. package/pins_data_model/models/model_nsip_subscription.py +1 -1
  24. package/pins_data_model/models/model_pins_inspector.py +1 -1
  25. package/pins_data_model/models/model_pins_lpa.py +1 -1
  26. package/pins_data_model/models/model_s51_advice.py +1 -1
  27. package/pins_data_model/models/model_service_user.py +1 -1
  28. package/schemas/commands/appellant-submission.schema.json +8 -0
  29. package/schemas/commands/lpa-questionnaire.schema.json +2 -2
  30. package/schemas/nsip-project.schema.json +8 -1
  31. package/src/schemas.d.ts +11 -3
  32. package/tests/appeals/commands/enforcement-listed-questionnaire.test.js +109 -0
  33. package/tests/appeals/commands/enforcement-listed-submission.test.js +187 -0
@@ -4,14 +4,15 @@
4
4
 
5
5
  # meeting Properties
6
6
 
7
- | Property | Type | Required | Nullable | Defined by |
8
- | :---------------------------------------------------- | :-------- | :------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
- | [meetingId](#meetingid) | `integer` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingid.md "nsip-project.schema.json#/$defs/meeting/properties/meetingId") |
10
- | [meetingAgenda](#meetingagenda) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingagenda.md "nsip-project.schema.json#/$defs/meeting/properties/meetingAgenda") |
11
- | [planningInspectorateRole](#planninginspectoraterole) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-planninginspectoraterole.md "nsip-project.schema.json#/$defs/meeting/properties/planningInspectorateRole") |
12
- | [meetingDate](#meetingdate) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/meetingDate") |
13
- | [meetingType](#meetingtype) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingtype.md "nsip-project.schema.json#/$defs/meeting/properties/meetingType") |
14
- | Additional Properties | Any | Optional | can be null | |
7
+ | Property | Type | Required | Nullable | Defined by |
8
+ | :-------------------------------------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
9
+ | [meetingId](#meetingid) | `integer` | Required | cannot be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingid.md "nsip-project.schema.json#/$defs/meeting/properties/meetingId") |
10
+ | [meetingAgenda](#meetingagenda) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingagenda.md "nsip-project.schema.json#/$defs/meeting/properties/meetingAgenda") |
11
+ | [planningInspectorateRole](#planninginspectoraterole) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-planninginspectoraterole.md "nsip-project.schema.json#/$defs/meeting/properties/planningInspectorateRole") |
12
+ | [meetingDate](#meetingdate) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/meetingDate") |
13
+ | [estimatedPrelimMeetingDate](#estimatedprelimmeetingdate) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-estimatedprelimmeetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/estimatedPrelimMeetingDate") |
14
+ | [meetingType](#meetingtype) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingtype.md "nsip-project.schema.json#/$defs/meeting/properties/meetingType") |
15
+ | Additional Properties | Any | Optional | can be null | |
15
16
 
16
17
  ## meetingId
17
18
 
@@ -19,11 +20,11 @@ Unique identifier for the meeting
19
20
 
20
21
  `meetingId`
21
22
 
22
- * is optional
23
+ * is required
23
24
 
24
25
  * Type: `integer`
25
26
 
26
- * can be null
27
+ * cannot be null
27
28
 
28
29
  * defined in: [NSIP Project](nsip-project-defs-meeting-properties-meetingid.md "nsip-project.schema.json#/$defs/meeting/properties/meetingId")
29
30
 
@@ -124,6 +125,34 @@ Meeting date
124
125
  "2023-07-27T20:30:00.000Z"
125
126
  ```
126
127
 
128
+ ## estimatedPrelimMeetingDate
129
+
130
+ Estimated Preliminary Meeting date
131
+
132
+ `estimatedPrelimMeetingDate`
133
+
134
+ * is optional
135
+
136
+ * Type: `string`
137
+
138
+ * can be null
139
+
140
+ * defined in: [NSIP Project](nsip-project-defs-meeting-properties-estimatedprelimmeetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/estimatedPrelimMeetingDate")
141
+
142
+ ### estimatedPrelimMeetingDate Type
143
+
144
+ `string`
145
+
146
+ ### estimatedPrelimMeetingDate Constraints
147
+
148
+ **date time**: the string must be a date time string, according to [RFC 3339, section 5.6](https://tools.ietf.org/html/rfc3339 "check the specification")
149
+
150
+ ### estimatedPrelimMeetingDate Examples
151
+
152
+ ```json
153
+ "2023-07-27T20:30:00.000Z"
154
+ ```
155
+
127
156
  ## meetingType
128
157
 
129
158
  Type of Meeting
@@ -3592,14 +3592,15 @@ Reference this group by using
3592
3592
  {"$ref":"nsip-project.schema.json#/$defs/meeting"}
3593
3593
  ```
3594
3594
 
3595
- | Property | Type | Required | Nullable | Defined by |
3596
- | :---------------------------------------------------- | :-------- | :------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3597
- | [meetingId](#meetingid) | `integer` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingid.md "nsip-project.schema.json#/$defs/meeting/properties/meetingId") |
3598
- | [meetingAgenda](#meetingagenda) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingagenda.md "nsip-project.schema.json#/$defs/meeting/properties/meetingAgenda") |
3599
- | [planningInspectorateRole](#planninginspectoraterole) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-planninginspectoraterole.md "nsip-project.schema.json#/$defs/meeting/properties/planningInspectorateRole") |
3600
- | [meetingDate](#meetingdate) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/meetingDate") |
3601
- | [meetingType](#meetingtype) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingtype.md "nsip-project.schema.json#/$defs/meeting/properties/meetingType") |
3602
- | Additional Properties | Any | Optional | can be null | |
3595
+ | Property | Type | Required | Nullable | Defined by |
3596
+ | :-------------------------------------------------------- | :-------- | :------- | :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3597
+ | [meetingId](#meetingid) | `integer` | Required | cannot be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingid.md "nsip-project.schema.json#/$defs/meeting/properties/meetingId") |
3598
+ | [meetingAgenda](#meetingagenda) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingagenda.md "nsip-project.schema.json#/$defs/meeting/properties/meetingAgenda") |
3599
+ | [planningInspectorateRole](#planninginspectoraterole) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-planninginspectoraterole.md "nsip-project.schema.json#/$defs/meeting/properties/planningInspectorateRole") |
3600
+ | [meetingDate](#meetingdate) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/meetingDate") |
3601
+ | [estimatedPrelimMeetingDate](#estimatedprelimmeetingdate) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-estimatedprelimmeetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/estimatedPrelimMeetingDate") |
3602
+ | [meetingType](#meetingtype) | `string` | Optional | can be null | [NSIP Project](nsip-project-defs-meeting-properties-meetingtype.md "nsip-project.schema.json#/$defs/meeting/properties/meetingType") |
3603
+ | Additional Properties | Any | Optional | can be null | |
3603
3604
 
3604
3605
  ### meetingId
3605
3606
 
@@ -3607,11 +3608,11 @@ Unique identifier for the meeting
3607
3608
 
3608
3609
  `meetingId`
3609
3610
 
3610
- * is optional
3611
+ * is required
3611
3612
 
3612
3613
  * Type: `integer`
3613
3614
 
3614
- * can be null
3615
+ * cannot be null
3615
3616
 
3616
3617
  * defined in: [NSIP Project](nsip-project-defs-meeting-properties-meetingid.md "nsip-project.schema.json#/$defs/meeting/properties/meetingId")
3617
3618
 
@@ -3712,6 +3713,34 @@ Meeting date
3712
3713
  "2023-07-27T20:30:00.000Z"
3713
3714
  ```
3714
3715
 
3716
+ ### estimatedPrelimMeetingDate
3717
+
3718
+ Estimated Preliminary Meeting date
3719
+
3720
+ `estimatedPrelimMeetingDate`
3721
+
3722
+ * is optional
3723
+
3724
+ * Type: `string`
3725
+
3726
+ * can be null
3727
+
3728
+ * defined in: [NSIP Project](nsip-project-defs-meeting-properties-estimatedprelimmeetingdate.md "nsip-project.schema.json#/$defs/meeting/properties/estimatedPrelimMeetingDate")
3729
+
3730
+ #### estimatedPrelimMeetingDate Type
3731
+
3732
+ `string`
3733
+
3734
+ #### estimatedPrelimMeetingDate Constraints
3735
+
3736
+ **date time**: the string must be a date time string, according to [RFC 3339, section 5.6](https://tools.ietf.org/html/rfc3339 "check the specification")
3737
+
3738
+ #### estimatedPrelimMeetingDate Examples
3739
+
3740
+ ```json
3741
+ "2023-07-27T20:30:00.000Z"
3742
+ ```
3743
+
3715
3744
  ### meetingType
3716
3745
 
3717
3746
  Type of Meeting
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planning-inspectorate/data-model",
3
- "version": "2.14.0",
3
+ "version": "2.16.0",
4
4
  "description": "JSON Schemas for the Planning Inspectorate's Data Model",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: appeal-document.schema.json
3
- # timestamp: 2026-02-04T16:06:56+00:00
3
+ # timestamp: 2026-02-05T18:48:25+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: appeal-event.schema.json
3
- # timestamp: 2026-02-04T16:06:56+00:00
3
+ # timestamp: 2026-02-05T18:48:25+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: appeal-event-estimate.schema.json
3
- # timestamp: 2026-02-04T16:06:56+00:00
3
+ # timestamp: 2026-02-05T18:48:25+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: appeal-has.schema.json
3
- # timestamp: 2026-02-04T16:06:56+00:00
3
+ # timestamp: 2026-02-05T18:48:25+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: appeal-representation.schema.json
3
- # timestamp: 2026-02-04T16:06:56+00:00
3
+ # timestamp: 2026-02-05T18:48:25+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: appeal-s78.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: dart-response.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: entraid.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: folder.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: gettimesheets-response.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: listed-building.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: listed-buildings.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-document.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-exam-timetable.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-invoice.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-meeting.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-project.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -310,7 +310,7 @@ class Meeting(BaseModel):
310
310
  model_config = ConfigDict(
311
311
  extra="allow",
312
312
  )
313
- meetingId: int | None = Field(None, examples=[123])
313
+ meetingId: int = Field(..., examples=[123])
314
314
  """
315
315
  Unique identifier for the meeting
316
316
  """
@@ -330,6 +330,12 @@ class Meeting(BaseModel):
330
330
  """
331
331
  Meeting date
332
332
  """
333
+ estimatedPrelimMeetingDate: AwareDatetime | None = Field(
334
+ None, examples=["2023-07-27T20:30:00.000Z"]
335
+ )
336
+ """
337
+ Estimated Preliminary Meeting date
338
+ """
333
339
  meetingType: MeetingType | None = None
334
340
  """
335
341
  Type of Meeting
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-project-update.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-representation.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: nsip-subscription.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: pins-inspector.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: pins-lpa.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: s51-advice.schema.json
3
- # timestamp: 2026-02-04T16:06:57+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: service-user.schema.json
3
- # timestamp: 2026-02-04T16:06:58+00:00
3
+ # timestamp: 2026-02-05T18:48:26+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -73,6 +73,14 @@
73
73
  { "$ref": "appeals-components/appellant-procedure-preference.schema.json" },
74
74
  { "$ref": "appeals-components/appeal-ldc.submission.schema.json" }
75
75
  ]
76
+ },
77
+ {
78
+ "$comment": "Enforcement listed building",
79
+ "allOf": [
80
+ { "properties": { "caseType": { "enum": ["F"] } } },
81
+ { "$ref": "appeals-components/appeal-enforcement-submission.schema.json" },
82
+ { "$ref": "appeals-components/appellant-procedure-preference.schema.json" }
83
+ ]
76
84
  }
77
85
  ]
78
86
  },
@@ -71,9 +71,9 @@
71
71
  ]
72
72
  },
73
73
  {
74
- "$comment": "Enforcement",
74
+ "$comment": "Enforcement + Enforcement listed building",
75
75
  "allOf": [
76
- { "properties": { "caseType": { "enum": ["C"] } } },
76
+ { "properties": { "caseType": { "enum": ["C", "F"] } } },
77
77
  { "$ref": "appeals-components/lpa-questionnaire-common.schema.json" },
78
78
  { "$ref": "appeals-components/lpa-questionnaire-has.schema.json" },
79
79
  { "$ref": "appeals-components/lpa-procedure-preference.schema.json" },
@@ -871,9 +871,10 @@
871
871
  "type": "object",
872
872
  "additionalProperties": true,
873
873
  "description": "A meeting related to the project",
874
+ "required": ["meetingId"],
874
875
  "properties": {
875
876
  "meetingId": {
876
- "type": ["integer", "null"],
877
+ "type": "integer",
877
878
  "description": "Unique identifier for the meeting",
878
879
  "examples": [123]
879
880
  },
@@ -894,6 +895,12 @@
894
895
  "format": "date-time",
895
896
  "examples": ["2023-07-27T20:30:00.000Z"]
896
897
  },
898
+ "estimatedPrelimMeetingDate": {
899
+ "type": ["string", "null"],
900
+ "description": "Estimated Preliminary Meeting date",
901
+ "format": "date-time",
902
+ "examples": ["2023-07-27T20:30:00.000Z"]
903
+ },
897
904
  "meetingType": {
898
905
  "type": ["string", "null"],
899
906
  "description": "Type of Meeting",
package/src/schemas.d.ts CHANGED
@@ -2914,7 +2914,7 @@ export interface Meeting {
2914
2914
  /**
2915
2915
  * Unique identifier for the meeting
2916
2916
  */
2917
- meetingId?: number | null;
2917
+ meetingId: number;
2918
2918
  /**
2919
2919
  * Meeting agenda
2920
2920
  */
@@ -2927,6 +2927,10 @@ export interface Meeting {
2927
2927
  * Meeting date
2928
2928
  */
2929
2929
  meetingDate?: string | null;
2930
+ /**
2931
+ * Estimated Preliminary Meeting date
2932
+ */
2933
+ estimatedPrelimMeetingDate?: string | null;
2930
2934
  /**
2931
2935
  * Type of Meeting
2932
2936
  */
@@ -3993,7 +3997,11 @@ export interface AppellantSubmissionCommand {
3993
3997
  } & AppellantCommonSubmissionProperties &
3994
3998
  AppellantCommonPlanningProperties &
3995
3999
  AppellantProcedurePreferenceProperties &
3996
- LDCSpecificProperties);
4000
+ LDCSpecificProperties)
4001
+ | ({
4002
+ caseType?: 'F';
4003
+ } & AppellantEnforcementSubmissionProperties &
4004
+ AppellantProcedurePreferenceProperties);
3997
4005
  documents: {
3998
4006
  /**
3999
4007
  * The unique identifier for the document
@@ -4597,7 +4605,7 @@ export interface LPAQuestionnaireCommand {
4597
4605
  LPAProcedurePreferenceProperties &
4598
4606
  ChangedListedBuildingNumbersProperties)
4599
4607
  | ({
4600
- caseType?: 'C';
4608
+ caseType?: 'C' | 'F';
4601
4609
  } & LPAQCommonSubmissionProperties &
4602
4610
  LPAQHASSubmissionProperties &
4603
4611
  LPAProcedurePreferenceProperties &
@@ -0,0 +1,109 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import Ajv from 'ajv';
4
+ import addFormats from 'ajv-formats';
5
+ import { loadAllSchemasSync } from '../../../src/index.js';
6
+
7
+ const schema = 'lpa-questionnaire.schema.json';
8
+
9
+ const document = {
10
+ documentId: 'deserunt sint aliqua adipisicing dolore',
11
+ filename: 'ut dolore',
12
+ originalFilename: 'Lorem amet fugiat adipisicing Excepteur',
13
+ size: -90476934,
14
+ mime: 'magna labore exercitation ut',
15
+ documentURI: 'ut reprehenderit',
16
+ dateCreated: '1933-04-03T03:24:38.0Z',
17
+ documentType: 'plansDrawings'
18
+ };
19
+
20
+ const exampleEnforcementListedQuestionnaireSchema = {
21
+ casedata: {
22
+ caseType: 'F',
23
+ caseReference: 'est ea elit in nulla',
24
+ lpaQuestionnaireSubmittedDate: null,
25
+ siteAccessDetails: ['velit adipisicing fugiat dolor ullamco'],
26
+ siteSafetyDetails: ['ut', 'dolore ut sint Duis', 'magna consequat quis laboris officia'],
27
+ nearbyCaseReferences: ['nulla', 'incididunt eu nostrud eiusmod', 'exercitation', 'Ut nostrud', 'eiusmod cillum eu'],
28
+ neighbouringSiteAddresses: null,
29
+ isCorrectAppealType: true,
30
+ affectedListedBuildingNumbers: null,
31
+ isGreenBelt: null,
32
+ inConservationArea: null,
33
+ newConditionDetails: null,
34
+ notificationMethod: ['irure', 'cillum tempor incididunt labore in'],
35
+ lpaCostsAppliedFor: true,
36
+ lpaStatement: 'ex laborum cupidatat',
37
+ changedListedBuildingNumbers: null,
38
+ affectsScheduledMonument: true,
39
+ hasProtectedSpecies: false,
40
+ isAonbNationalLandscape: true,
41
+ designatedSitesNames: ['quis nulla eu officia exercitation'],
42
+ hasTreePreservationOrder: null,
43
+ isGypsyOrTravellerSite: true,
44
+ isPublicRightOfWay: null,
45
+ eiaEnvironmentalImpactSchedule: 'schedule-2',
46
+ eiaDevelopmentDescription: 'production-processing-of-metals',
47
+ eiaSensitiveAreaDetails: null,
48
+ eiaColumnTwoThreshold: false,
49
+ eiaScreeningOpinion: false,
50
+ eiaRequiresEnvironmentalStatement: null,
51
+ eiaCompletedEnvironmentalStatement: true,
52
+ hasStatutoryConsultees: true,
53
+ consultedBodiesDetails: 'in in labore irure nostrud',
54
+ hasConsultationResponses: null,
55
+ hasEmergingPlan: null,
56
+ hasSupplementaryPlanningDocs: null,
57
+ hasInfrastructureLevy: true,
58
+ isInfrastructureLevyFormallyAdopted: false,
59
+ infrastructureLevyAdoptedDate: '1913-06-14T10:40:33.0Z',
60
+ infrastructureLevyExpectedDate: '1912-06-14T10:40:33.0Z',
61
+ lpaProcedurePreference: null,
62
+ lpaProcedurePreferenceDetails: 'in reprehenderit',
63
+ lpaProcedurePreferenceDuration: -34480053.16630782,
64
+ noticeRelatesToBuildingEngineeringMiningOther: null,
65
+ siteAreaSquareMetres: null,
66
+ hasAllegedBreachArea: null,
67
+ doesAllegedBreachCreateFloorSpace: null,
68
+ changeOfUseRefuseOrWaste: null,
69
+ changeOfUseMineralExtraction: null,
70
+ changeOfUseMineralStorage: null,
71
+ relatesToErectionOfBuildingOrBuildings: null,
72
+ relatesToBuildingWithAgriculturalPurpose: null,
73
+ relatesToBuildingSingleDwellingHouse: null,
74
+ affectedTrunkRoadName: null,
75
+ isSiteOnCrownLand: null,
76
+ article4AffectedDevelopmentRights: null
77
+ },
78
+ documents: [document]
79
+ };
80
+
81
+ describe('Enforcement listed building questionnaire command schema', () => {
82
+ const schemas = loadAllSchemasSync();
83
+ const flatSchemas = Object.values(schemas).reduce((a, c) => ({ ...a, ...c }), {});
84
+ const ajv = new Ajv({ schemas: flatSchemas, allErrors: true });
85
+ addFormats(ajv);
86
+
87
+ it('should allow valid schema for Enforcement listed building', () => {
88
+ const validationResult = ajv.validate(schema, exampleEnforcementListedQuestionnaireSchema);
89
+ assert.strictEqual(validationResult, true);
90
+ });
91
+
92
+ it('should reject missing caseReference', () => {
93
+ const test = structuredClone(exampleEnforcementListedQuestionnaireSchema);
94
+ delete test.casedata.caseReference;
95
+ const validationResult = ajv.validate(schema, test);
96
+ assert.strictEqual(validationResult, false);
97
+ assert.strictEqual(
98
+ ajv.errors.some((x) => x.message === "must have required property 'caseReference'"),
99
+ true
100
+ );
101
+ });
102
+
103
+ it('should allow additional props', () => {
104
+ const test = structuredClone(exampleEnforcementListedQuestionnaireSchema);
105
+ test.test = 1;
106
+ const validationResult = ajv.validate(schema, test);
107
+ assert.strictEqual(validationResult, true);
108
+ });
109
+ });
@@ -0,0 +1,187 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import Ajv from 'ajv';
4
+ import addFormats from 'ajv-formats';
5
+ import { loadAllSchemasSync } from '../../../src/index.js';
6
+
7
+ const schema = 'appellant-submission.schema.json';
8
+
9
+ const user = {
10
+ salutation: 'nisi aute tempor Ut',
11
+ firstName: null,
12
+ lastName: null,
13
+ emailAddress: null,
14
+ telephoneNumber: 'irure',
15
+ organisation: null,
16
+ serviceUserType: 'Appellant'
17
+ };
18
+
19
+ const document = {
20
+ documentId: 'Lorem',
21
+ filename: 'sunt',
22
+ originalFilename: 'dolore fugiat',
23
+ size: 663667,
24
+ mime: 'consequat veniam ipsum ullamco sint',
25
+ documentURI: 'reprehenderit',
26
+ dateCreated: '1904-04-10T14:53:32.0Z',
27
+ documentType: 'priorCorrespondenceWithPINS'
28
+ };
29
+
30
+ const exampleEnforcementListedSubmissionSchema = {
31
+ casedata: {
32
+ caseType: 'F',
33
+ submissionId: '4b78fc58-fcb0-70d6-5dea-b9b774f802d6',
34
+ caseProcedure: 'written',
35
+ lpaCode: 'cupidatat',
36
+ caseSubmittedDate: '1890-12-28T22:49:47.0Z',
37
+ enforcementNotice: true,
38
+ enforcementReference: '12345',
39
+ enforcementIssueDate: '1890-12-28T22:49:47.0Z',
40
+ enforcementEffectiveDate: '1890-12-28T22:49:47.0Z',
41
+ contactPlanningInspectorateDate: null,
42
+ interestInLand: 'owner',
43
+ writtenOrVerbalPermission: null,
44
+ descriptionOfAllegedBreach: 'a new chimney',
45
+ applicationMadeAndFeePaid: true,
46
+ applicationDevelopmentAllOrPart: 'all-of-the-development',
47
+ originalDevelopmentDescription: 'in amet',
48
+ changedDevelopmentDescription: true,
49
+ applicationReference: '43010/APP/1/290572',
50
+ applicationDate: '1890-12-28T22:49:47.0Z',
51
+ applicationDecision: 'granted',
52
+ applicationDecisionAppealed: false,
53
+ applicationDecisionDate: '1890-12-28T22:49:47.0Z',
54
+ appealDecisionDate: null,
55
+ caseSubmissionDueDate: null,
56
+ siteAddressLine1: 'occaecat aliquip non pariatur consequat',
57
+ siteAddressLine2: null,
58
+ siteAddressTown: 'et',
59
+ siteAddressCounty: 'velit',
60
+ siteAddressPostcode: 'nisi minim laboris sed',
61
+ siteGridReferenceEasting: '357144',
62
+ siteGridReferenceNorthing: '400534',
63
+ contactAddressLine1: null,
64
+ contactAddressLine2: null,
65
+ contactAddressTown: null,
66
+ contactAddressCounty: null,
67
+ contactAddressPostcode: null,
68
+ contactGridReferenceEasting: null,
69
+ contactGridReferenceNorthing: null,
70
+ siteAccessDetails: ['laborum', 'aute velit quis', 'dolor'],
71
+ siteSafetyDetails: ['velit aliqua', 'qui', 'tempor Duis ut dolore', 'anim Ut in ea', 'eiusmod laborum'],
72
+ appellantCostsAppliedFor: false,
73
+ appellantProcedurePreference: null,
74
+ appellantProcedurePreferenceDetails: 'eiusmod ex exercitation',
75
+ appellantProcedurePreferenceDuration: 10816414.941069126,
76
+ appellantProcedurePreferenceWitnessCount: -91300569.36444478,
77
+ statusPlanningObligation: 'proident aute',
78
+ nearbyCaseReferences: ['incididunt'],
79
+ namedIndividuals: [
80
+ {
81
+ firstName: 'Bob',
82
+ lastName: 'Bobberson',
83
+ interestInLand: 'owner',
84
+ writtenOrVerbalPermission: 'yes'
85
+ }
86
+ ],
87
+ appealGrounds: [
88
+ {
89
+ groundRef: 'a',
90
+ factsForGround: 'I like Christmas'
91
+ }
92
+ ]
93
+ },
94
+ documents: [document],
95
+ users: [user]
96
+ };
97
+
98
+ describe(' listed building submission command schema', () => {
99
+ const schemas = loadAllSchemasSync();
100
+ const flatSchemas = Object.values(schemas).reduce((a, c) => ({ ...a, ...c }), {});
101
+ const ajv = new Ajv({ schemas: flatSchemas, allErrors: true });
102
+ addFormats(ajv);
103
+
104
+ it('should allow valid schema for enforcement listed building', () => {
105
+ const validationResult = ajv.validate(schema, exampleEnforcementListedSubmissionSchema);
106
+ assert.strictEqual(validationResult, true);
107
+ });
108
+
109
+ it('should enforce eastings-northings pattern', () => {
110
+ const invalidPatterns = [
111
+ { easting: 'abc123', northing: '400534', description: 'easting with letters' },
112
+ { easting: '1234567*', northing: '400534', description: 'easting too long' },
113
+ { easting: '12345', northing: '400534', description: 'easting too short' },
114
+ { easting: '357144', northing: 'xyz123', description: 'northing with letters' },
115
+ { easting: '357144', northing: '12345678', description: 'northing too long' },
116
+ { easting: '357144', northing: '12345', description: 'northing too short' },
117
+ { easting: '', northing: '400534', description: 'empty easting' },
118
+ { easting: '357144', northing: '', description: 'empty northing' }
119
+ ];
120
+
121
+ for (const pattern of invalidPatterns) {
122
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
123
+ test.casedata.siteGridReferenceEasting = pattern.easting;
124
+ test.casedata.siteGridReferenceNorthing = pattern.northing;
125
+
126
+ const validationResult = ajv.validate(schema, test);
127
+ assert.strictEqual(validationResult, false, `Expected validation to fail for ${pattern.description}`);
128
+ }
129
+ });
130
+
131
+ it('should allow only eastings-northings', () => {
132
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
133
+ test.casedata.siteAddressPostcode = undefined;
134
+ test.casedata.siteAddressLine1 = null;
135
+ test.casedata.siteAddressTown = null;
136
+ const validationResult = ajv.validate(schema, test);
137
+ assert.strictEqual(validationResult, true);
138
+ });
139
+
140
+ it('should allow only site address', () => {
141
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
142
+ test.casedata.siteGridReferenceEasting = undefined;
143
+ test.casedata.siteGridReferenceNorthing = null;
144
+ const validationResult = ajv.validate(schema, test);
145
+ assert.strictEqual(validationResult, true);
146
+ });
147
+
148
+ it('should enforce either site address or easting-northing', () => {
149
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
150
+ test.casedata.siteAddressPostcode = undefined;
151
+ test.casedata.siteAddressLine1 = null;
152
+ test.casedata.siteAddressTown = null;
153
+ test.casedata.siteGridReferenceEasting = undefined;
154
+ test.casedata.siteGridReferenceNorthing = null;
155
+ const validationResult = ajv.validate(schema, test);
156
+ assert.strictEqual(validationResult, false);
157
+ });
158
+
159
+ it('should reject missing root property', () => {
160
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
161
+ delete test.casedata.caseType;
162
+ const validationResult = ajv.validate(schema, test);
163
+ assert.strictEqual(validationResult, false);
164
+ assert.strictEqual(
165
+ ajv.errors.some((x) => x.message === "must have required property 'caseType'"),
166
+ true
167
+ );
168
+ });
169
+
170
+ it('should reject missing nested property', () => {
171
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
172
+ delete test.casedata.caseProcedure;
173
+ const validationResult = ajv.validate(schema, test);
174
+ assert.strictEqual(validationResult, false);
175
+ assert.strictEqual(
176
+ ajv.errors.some((x) => x.message === "must have required property 'caseProcedure'"),
177
+ true
178
+ );
179
+ });
180
+
181
+ it('should allow additional props', () => {
182
+ const test = structuredClone(exampleEnforcementListedSubmissionSchema);
183
+ test.test = 1;
184
+ const validationResult = ajv.validate(schema, test);
185
+ assert.strictEqual(validationResult, true);
186
+ });
187
+ });