diff --git a/src/export/digitalPlanning/model.ts b/src/export/digitalPlanning/model.ts index eb5761dd..40a78fad 100644 --- a/src/export/digitalPlanning/model.ts +++ b/src/export/digitalPlanning/model.ts @@ -7,8 +7,10 @@ import { Passport } from "../../models"; import { getResultData } from "../../models/result"; import { Breadcrumbs, + ComponentType, EnhancedGISResponse, FlowGraph, + Node, Passport as IPassport, SessionMetadata, Value, @@ -16,11 +18,13 @@ import { import { extractFileDescriptionForPassportKey, formatProposalDetails, + parsePolicyRefs, } from "../bops"; import jsonSchema from "./schema/schema.json"; import { ApplicationType, DigitalPlanningApplication as Payload, + FeeExplanation, File, FileType, GeoJSON, @@ -814,6 +818,46 @@ export class DigitalPlanning { return requestedFiles; } + private getFeeExplanations(): FeeExplanation { + const explanations: FeeExplanation = { + calculated: [], + payable: [], + }; + + const fns = ["application.fee.calculated", "application.fee.payable"]; + const calculateNodes = Object.entries(this.flow) + .filter( + ([nodeId, node]: [string, Node]) => + node?.type === ComponentType.Calculate && + fns.includes(node.data?.output as string) && + Object.keys(this.breadcrumbs).includes(nodeId), + ) + .map(([_nodeId, node]: [string, Node]) => node); + + if (!calculateNodes) { + return explanations; + } + + calculateNodes.forEach((node: Node) => { + const suffix = (node.data?.output as string).split(".").pop() as string; + explanations[suffix].push({ + ...(node.data?.info && { description: node.data.info }), + ...(node.data?.policyRef && { + policyRefs: parsePolicyRefs(node.data.policyRef as string), + }), + }); + }); + + if ( + explanations.calculated.length > 0 && + explanations.payable.length === 0 + ) { + explanations["payable"] = explanations["calculated"]; + } + + return explanations; + } + private getMetadata(): Payload["metadata"] { return { id: this.sessionId, @@ -824,6 +868,7 @@ export class DigitalPlanning { flowId: this.metadata.flow.id, url: `https://www.editor.planx.uk/${this.metadata.flow.team.slug}/${this.metadata.flow.slug}/preview`, files: this.getRequestedFiles(), + fee: this.getFeeExplanations(), }, schema: `https://theopensystemslab.github.io/digital-planning-data-schemas/${jsonSchema["$id"]}/schema.json`, } as PlanXMetadata; diff --git a/src/export/digitalPlanning/schema/schema.json b/src/export/digitalPlanning/schema/schema.json index c7285f2f..b0025726 100644 --- a/src/export/digitalPlanning/schema/schema.json +++ b/src/export/digitalPlanning/schema/schema.json @@ -1,5 +1,5 @@ { - "$id": "v0.4.0", + "$id": "v0.4.1", "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": false, "definitions": { @@ -203,6 +203,9 @@ "additionalProperties": false, "description": "Information about this planning application", "properties": { + "CIL": { + "$ref": "#/definitions/CommunityInfrastructureLevy" + }, "declaration": { "$ref": "#/definitions/ApplicationDeclaration" }, @@ -1316,6 +1319,9 @@ "required": ["area"], "type": "object" }, + "materials": { + "$ref": "#/definitions/Materials" + }, "new": { "additionalProperties": false, "properties": { @@ -1344,6 +1350,53 @@ }, "type": "object" }, + "CalculateMetadata": { + "$id": "#CalculateMetadata", + "additionalProperties": false, + "description": "Metadata associated with PlanX Calculate components used to determine fees throughout a service", + "properties": { + "description": { + "type": "string" + }, + "policyRefs": { + "items": { + "additionalProperties": false, + "properties": { + "text": { + "type": "string" + }, + "url": { + "$ref": "#/definitions/URL" + } + }, + "required": ["text"], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "CommunityInfrastructureLevy": { + "$id": "#CommunityInfrastructureLevy", + "additionalProperties": false, + "description": "Details about the Community Infrastructure Levy planning charge, if applicable", + "properties": { + "result": { + "enum": [ + "exempt.annexe", + "exempt.extension", + "exempt.selfBuild", + "liable", + "relief.charity", + "relief.socialHousing" + ], + "type": "string" + } + }, + "required": ["result"], + "type": "object" + }, "Date": { "format": "date", "type": "string" @@ -1439,6 +1492,27 @@ "required": ["features", "type"], "type": "object" }, + "FeeExplanation": { + "$id": "#FeeExplanation", + "additionalProperties": false, + "description": "An explanation, including policy references, of the calculated and payable fees associated with this application", + "properties": { + "calculated": { + "items": { + "$ref": "#/definitions/CalculateMetadata" + }, + "type": "array" + }, + "payable": { + "items": { + "$ref": "#/definitions/CalculateMetadata" + }, + "type": "array" + } + }, + "required": ["calculated", "payable"], + "type": "object" + }, "File": { "$id": "#File", "additionalProperties": false, @@ -1463,6 +1537,21 @@ "FileType": { "$id": "#FileType", "anyOf": [ + { + "additionalProperties": false, + "properties": { + "description": { + "const": "Details of impact on access, roads, and rights of way", + "type": "string" + }, + "value": { + "const": "accessRoadsRightsOfWayDetails", + "type": "string" + } + }, + "required": ["value", "description"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -1778,6 +1867,21 @@ "required": ["value", "description"], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "description": { + "const": "External materials details", + "type": "string" + }, + "value": { + "const": "externalMaterialsDetails", + "type": "string" + } + }, + "required": ["value", "description"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -2543,6 +2647,36 @@ "required": ["value", "description"], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "description": { + "const": "Location of trees and hedges", + "type": "string" + }, + "value": { + "const": "treeAndHedgeLocation", + "type": "string" + } + }, + "required": ["value", "description"], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "description": { + "const": "Removed or pruned trees and hedges", + "type": "string" + }, + "value": { + "const": "treeAndHedgeRemovedOrPruned", + "type": "string" + } + }, + "required": ["value", "description"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -2693,6 +2827,21 @@ "required": ["value", "description"], "type": "object" }, + { + "additionalProperties": false, + "properties": { + "description": { + "const": "Viability Appraisal", + "type": "string" + }, + "value": { + "const": "viabilityAppraisal", + "type": "string" + } + }, + "required": ["value", "description"], + "type": "object" + }, { "additionalProperties": false, "properties": { @@ -2852,6 +3001,9 @@ "required": ["area"], "type": "object" }, + "materials": { + "$ref": "#/definitions/Materials" + }, "new": { "additionalProperties": false, "properties": { @@ -3403,6 +3555,9 @@ "required": ["site", "area"], "type": "object" }, + "details": { + "$ref": "#/definitions/PropertyDetails" + }, "localAuthorityDistrict": { "description": "Current and historic UK Local Authority Districts that contain this address sourced from planning.data.gov.uk/dataset/local-authority-district", "items": { @@ -3494,6 +3649,36 @@ ], "type": "object" }, + "Materials": { + "additionalProperties": false, + "properties": { + "boundary": { + "type": "string" + }, + "door": { + "type": "string" + }, + "lighting": { + "type": "string" + }, + "other": { + "type": "string" + }, + "roof": { + "type": "string" + }, + "surface": { + "type": "string" + }, + "wall": { + "type": "string" + }, + "window": { + "type": "string" + } + }, + "type": "object" + }, "Metadata": { "$id": "#DigitalPlanningMetadata", "anyOf": [ @@ -3723,6 +3908,9 @@ "service": { "additionalProperties": false, "properties": { + "fee": { + "$ref": "#/definitions/FeeExplanation" + }, "files": { "$ref": "#/definitions/RequestedFiles" }, @@ -3733,7 +3921,7 @@ "$ref": "#/definitions/URL" } }, - "required": ["flowId", "url", "files"], + "required": ["flowId", "url", "files", "fee"], "type": "object" }, "source": { @@ -10562,6 +10750,17 @@ ], "description": "Information about the site where the works will happen" }, + "PropertyDetails": { + "$id": "#PropertyDetails", + "additionalProperties": false, + "description": "Details about the property as it currently exists", + "properties": { + "materials": { + "$ref": "#/definitions/Materials" + } + }, + "type": "object" + }, "PropertyType": { "$id": "#PropertyType", "anyOf": [ @@ -17681,7 +17880,7 @@ "RequestedFiles": { "$id": "#RequestedFiles", "additionalProperties": false, - "description": "File types requested by this service. Schema[\"files\"] will be a subset of this list based on the user's journey through the service.", + "description": "File types requested by this service. Schema[\"files\"] will be a subset of this list based on the user's journey through the service", "properties": { "optional": { "items": { @@ -18281,6 +18480,9 @@ "required": ["site", "area"], "type": "object" }, + "details": { + "$ref": "#/definitions/PropertyDetails" + }, "localAuthorityDistrict": { "description": "Current and historic UK Local Authority Districts that contain this address sourced from planning.data.gov.uk/dataset/local-authority-district", "items": { diff --git a/src/export/digitalPlanning/schema/types.d.ts b/src/export/digitalPlanning/schema/types.d.ts index e10749c3..c90b9a83 100644 --- a/src/export/digitalPlanning/schema/types.d.ts +++ b/src/export/digitalPlanning/schema/types.d.ts @@ -4058,6 +4058,10 @@ export type ProjectType = * Types of planning documents and drawings */ export type FileType = + | { + description: "Details of impact on access, roads, and rights of way"; + value: "accessRoadsRightsOfWayDetails"; + } | { description: "Affordable housing statement"; value: "affordableHousingStatement"; @@ -4142,6 +4146,10 @@ export type FileType = description: "Environmental Impact Assessment (EIA)"; value: "environmentalImpactAssessment"; } + | { + description: "External materials details"; + value: "externalMaterialsDetails"; + } | { description: "Fire safety report"; value: "fireSafetyReport"; @@ -4346,6 +4354,14 @@ export type FileType = description: "Travel plan"; value: "travelPlan"; } + | { + description: "Location of trees and hedges"; + value: "treeAndHedgeLocation"; + } + | { + description: "Removed or pruned trees and hedges"; + value: "treeAndHedgeRemovedOrPruned"; + } | { description: "Tree canopy calculator"; value: "treeCanopyCalculator"; @@ -4386,6 +4402,10 @@ export type FileType = description: "Ventilation or extraction statement"; value: "ventilationStatement"; } + | { + description: "Viability Appraisal"; + value: "viabilityAppraisal"; + } | { description: "Visualisations"; value: "visualisations"; @@ -4664,11 +4684,24 @@ export interface Agent { * Information about this planning application */ export interface Application { + CIL?: CommunityInfrastructureLevy; declaration: ApplicationDeclaration; fee: ApplicationFee; preApp?: PreApplication; type: ApplicationType; } +/** + * Details about the Community Infrastructure Levy planning charge, if applicable + */ +export interface CommunityInfrastructureLevy { + result: + | "exempt.annexe" + | "exempt.extension" + | "exempt.selfBuild" + | "liable" + | "relief.charity" + | "relief.socialHousing"; +} /** * Declarations about the accuracy of this application and any personal connections to the receiving authority */ @@ -4727,6 +4760,7 @@ export interface UKProperty { area: Area; site: GeoJSON; }; + details?: PropertyDetails; /** * Current and historic UK Local Authority Districts that contain this address sourced from planning.data.gov.uk/dataset/local-authority-district */ @@ -5008,6 +5042,22 @@ export interface Feature3CGeometry2CGeoJsonProperties3E { */ type: "Feature"; } +/** + * Details about the property as it currently exists + */ +export interface PropertyDetails { + materials?: Materials; +} +export interface Materials { + boundary?: string; + door?: string; + lighting?: string; + other?: string; + roof?: string; + surface?: string; + wall?: string; + window?: string; +} /** * Property details for sites within the Greater London Authority (GLA) area */ @@ -5021,6 +5071,7 @@ export interface LondonProperty { area: Area; site: GeoJSON; }; + details?: PropertyDetails; /** * Current and historic UK Local Authority Districts that contain this address sourced from planning.data.gov.uk/dataset/local-authority-district */ @@ -5083,6 +5134,7 @@ export interface BaseDetails { extend?: { area: Area; }; + materials?: Materials; new?: { area: Area; count?: { @@ -5099,6 +5151,7 @@ export interface LondonDetails { extend?: { area: Area; }; + materials?: Materials; new?: { area: Area; count?: { @@ -5293,6 +5346,7 @@ export interface PlanXMetadata { organisation: string; schema: URL; service: { + fee: FeeExplanation; files: RequestedFiles; flowId: UUID; url: URL; @@ -5301,7 +5355,24 @@ export interface PlanXMetadata { submittedAt: DateTime; } /** - * File types requested by this service. Schema["files"] will be a subset of this list based on the user's journey through the service. + * An explanation, including policy references, of the calculated and payable fees associated with this application + */ +export interface FeeExplanation { + calculated: CalculateMetadata[]; + payable: CalculateMetadata[]; +} +/** + * Metadata associated with PlanX Calculate components used to determine fees throughout a service + */ +export interface CalculateMetadata { + description?: string; + policyRefs?: { + text: string; + url?: URL; + }[]; +} +/** + * File types requested by this service. Schema["files"] will be a subset of this list based on the user's journey through the service */ export interface RequestedFiles { optional: FileType[];