@planning-inspectorate/data-model 2.14.0 → 2.15.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.
- package/package.json +1 -1
- package/pins_data_model/models/model_appeal_document.py +1 -1
- package/pins_data_model/models/model_appeal_event.py +1 -1
- package/pins_data_model/models/model_appeal_event_estimate.py +1 -1
- package/pins_data_model/models/model_appeal_has.py +1 -1
- package/pins_data_model/models/model_appeal_representation.py +1 -1
- package/pins_data_model/models/model_appeal_s78.py +1 -1
- package/pins_data_model/models/model_dart_response.py +1 -1
- package/pins_data_model/models/model_entraid.py +1 -1
- package/pins_data_model/models/model_folder.py +1 -1
- package/pins_data_model/models/model_gettimesheets_response.py +1 -1
- package/pins_data_model/models/model_listed_building.py +1 -1
- package/pins_data_model/models/model_listed_buildings.py +1 -1
- package/pins_data_model/models/model_nsip_document.py +1 -1
- package/pins_data_model/models/model_nsip_exam_timetable.py +1 -1
- package/pins_data_model/models/model_nsip_invoice.py +1 -1
- package/pins_data_model/models/model_nsip_meeting.py +1 -1
- package/pins_data_model/models/model_nsip_project.py +1 -1
- package/pins_data_model/models/model_nsip_project_update.py +1 -1
- package/pins_data_model/models/model_nsip_representation.py +1 -1
- package/pins_data_model/models/model_nsip_subscription.py +1 -1
- package/pins_data_model/models/model_pins_inspector.py +1 -1
- package/pins_data_model/models/model_pins_lpa.py +1 -1
- package/pins_data_model/models/model_s51_advice.py +1 -1
- package/pins_data_model/models/model_service_user.py +1 -1
- package/schemas/commands/appellant-submission.schema.json +8 -0
- package/schemas/commands/lpa-questionnaire.schema.json +2 -2
- package/src/schemas.d.ts +6 -2
- package/tests/appeals/commands/enforcement-listed-questionnaire.test.js +109 -0
- package/tests/appeals/commands/enforcement-listed-submission.test.js +187 -0
package/package.json
CHANGED
|
@@ -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" },
|
package/src/schemas.d.ts
CHANGED
|
@@ -3993,7 +3993,11 @@ export interface AppellantSubmissionCommand {
|
|
|
3993
3993
|
} & AppellantCommonSubmissionProperties &
|
|
3994
3994
|
AppellantCommonPlanningProperties &
|
|
3995
3995
|
AppellantProcedurePreferenceProperties &
|
|
3996
|
-
LDCSpecificProperties)
|
|
3996
|
+
LDCSpecificProperties)
|
|
3997
|
+
| ({
|
|
3998
|
+
caseType?: 'F';
|
|
3999
|
+
} & AppellantEnforcementSubmissionProperties &
|
|
4000
|
+
AppellantProcedurePreferenceProperties);
|
|
3997
4001
|
documents: {
|
|
3998
4002
|
/**
|
|
3999
4003
|
* The unique identifier for the document
|
|
@@ -4597,7 +4601,7 @@ export interface LPAQuestionnaireCommand {
|
|
|
4597
4601
|
LPAProcedurePreferenceProperties &
|
|
4598
4602
|
ChangedListedBuildingNumbersProperties)
|
|
4599
4603
|
| ({
|
|
4600
|
-
caseType?: 'C';
|
|
4604
|
+
caseType?: 'C' | 'F';
|
|
4601
4605
|
} & LPAQCommonSubmissionProperties &
|
|
4602
4606
|
LPAQHASSubmissionProperties &
|
|
4603
4607
|
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
|
+
});
|