From 2906d6922a76ace7e372d3aef223b7e2f6aaab20 Mon Sep 17 00:00:00 2001 From: Kyle Morel Date: Wed, 24 Jan 2024 12:55:13 -0800 Subject: [PATCH] Various updates Permit type fixes. Bug fixes. Schema updates. --- app/src/db/migrations/20231212000000_init.ts | 215 ++++++++++++++++-- app/src/db/models/permit.ts | 44 ++-- app/src/db/models/permit_type.ts | 20 +- app/src/db/prisma/schema.prisma | 37 +-- app/src/services/permit.ts | 19 +- app/src/types/Permit.ts | 5 +- app/src/types/PermitType.ts | 6 +- frontend/src/components/permit/PermitCard.vue | 19 +- .../src/components/permit/PermitModal.vue | 17 +- frontend/src/types/Permit.ts | 1 + 10 files changed, 279 insertions(+), 104 deletions(-) diff --git a/app/src/db/migrations/20231212000000_init.ts b/app/src/db/migrations/20231212000000_init.ts index fb2914d48..fc0f3fc86 100644 --- a/app/src/db/migrations/20231212000000_init.ts +++ b/app/src/db/migrations/20231212000000_init.ts @@ -93,17 +93,17 @@ export async function up(knex: Knex): Promise { knex.schema.createTable('permit_type', (table) => { table.specificType('permitTypeId', 'integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY'); table.text('agency').notNullable(); - table.text('division').notNullable(); - table.text('branch').notNullable(); + table.text('division'); + table.text('branch'); table.text('businessDomain').notNullable(); table.text('type').notNullable(); table.text('family'); table.text('name').notNullable(); - table.text('name_subtype'); + table.text('nameSubtype'); table.text('acronym'); - table.boolean('tracked_in_ats'); - table.text('source_system').notNullable(); - table.text('source_system_acronym').notNullable(); + table.boolean('trackedInATS'); + table.text('sourceSystem'); + table.text('sourceSystemAcronym').notNullable(); stamps(knex, table); }) ) @@ -125,6 +125,7 @@ export async function up(knex: Knex): Promise { .inTable('submission') .onUpdate('CASCADE') .onDelete('CASCADE'); + table.text('issuedPermitId'); table.text('trackingId'); table.text('authStatus'); table.text('needed'); @@ -253,9 +254,9 @@ export async function up(knex: Knex): Promise { type: 'Alteration', name: 'Site Alteration Permit', acronym: 'SAP', - tracked_in_ats: false, - source_system: 'Archaeology Permit Tracking System', - source_system_acronym: 'APTS' + trackedInATS: false, + sourceSystem: 'Archaeology Permit Tracking System', + sourceSystemAcronym: 'APTS' }, { agency: 'Water, Land and Resource Stewardship', @@ -265,9 +266,9 @@ export async function up(knex: Knex): Promise { type: 'Inspection', name: 'Heritage Inspection Permit', acronym: 'HIP', - tracked_in_ats: false, - source_system: 'Archaeology Permit Tracking System', - source_system_acronym: 'APTS' + trackedInATS: false, + sourceSystem: 'Archaeology Permit Tracking System', + sourceSystemAcronym: 'APTS' }, { agency: 'Water, Land and Resource Stewardship', @@ -276,9 +277,9 @@ export async function up(knex: Knex): Promise { businessDomain: 'Archaeology', type: 'Investigation', name: 'Investigation Permit', - tracked_in_ats: false, - source_system: 'Archaeology Permit Tracking System', - source_system_acronym: 'APTS' + trackedInATS: false, + sourceSystem: 'Archaeology Permit Tracking System', + sourceSystemAcronym: 'APTS' }, { agency: 'Environment and Climate Change Strategy', @@ -287,9 +288,9 @@ export async function up(knex: Knex): Promise { businessDomain: 'Contaminated Sites', type: 'Contaminated Sites Remediation', name: 'Contaminated Sites Remediation Permit', - tracked_in_ats: false, - source_system: 'Contaminated Sites Application Tracking System', - source_system_acronym: 'CATS' + trackedInATS: false, + sourceSystem: 'Contaminated Sites Application Tracking System', + sourceSystemAcronym: 'CATS' }, { agency: 'Forests', @@ -299,8 +300,8 @@ export async function up(knex: Knex): Promise { type: 'Occupant Licence To Cut', name: 'Occupant Licence to Cut', acronym: 'OLTC', - source_system: 'Forest Tenure Administration', - source_system_acronym: 'FTA' + sourceSystem: 'Forest Tenure Administration', + sourceSystemAcronym: 'FTA' }, { agency: 'Forests', @@ -310,10 +311,180 @@ export async function up(knex: Knex): Promise { type: 'Private Timber Mark', name: 'Private Timber Mark', acronym: 'PTM', - source_system: 'Forest Tenure Administration', - source_system_acronym: 'FTA' + sourceSystem: 'Forest Tenure Administration', + sourceSystemAcronym: 'FTA' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Integrated Resource Operations', + branch: 'Lands Program', + businessDomain: 'Lands', + type: 'Commercial General', + family: 'Crown Land Tenure', + name: 'Commercial General', + sourceSystem: 'Tantalis', + sourceSystemAcronym: 'TANTALIS' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Integrated Resource Operations', + branch: 'Lands Program', + businessDomain: 'Lands', + type: 'Nominal Rent Tenure', + family: 'Crown Land Tenure', + name: 'Nominal Rent Tenure', + acronym: 'NRT', + sourceSystem: 'Tantalis', + sourceSystemAcronym: 'TANTALIS' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Integrated Resource Operations', + branch: 'Lands Program', + businessDomain: 'Lands', + type: 'Residential', + family: 'Crown Land Tenure', + name: 'Residential', + sourceSystem: 'Tantalis', + sourceSystemAcronym: 'TANTALIS' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Integrated Resource Operations', + branch: 'Lands Program', + businessDomain: 'Lands', + type: 'Roadways - Public', + family: 'Crown Land Tenure', + name: 'Roadways - Public', + sourceSystem: 'Tantalis', + sourceSystemAcronym: 'TANTALIS' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Integrated Resource Operations', + branch: 'Lands Program', + businessDomain: 'Lands', + type: 'Sponsored Crown Grant', + family: 'Crown Land Tenure', + name: 'Sponsored Crown Grant', + sourceSystem: 'Tantalis', + sourceSystemAcronym: 'TANTALIS' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Integrated Resource Operations', + branch: 'Lands Program', + businessDomain: 'Lands', + type: 'Utilities', + family: 'Crown Land Tenure', + name: 'Utilities', + sourceSystem: 'Tantalis', + sourceSystemAcronym: 'TANTALIS' + }, + { + agency: 'Transportation and Infrastructure', + businessDomain: 'Transportation', + type: 'Rural Subdivision', + name: 'Rural subdivision', + sourceSystemAcronym: 'MOTI' + }, + { + agency: 'Transportation and Infrastructure', + businessDomain: 'Transportation', + type: 'Rezoning', + name: 'Rezoning', + sourceSystemAcronym: 'MOTI' + }, + { + agency: 'Transportation and Infrastructure', + businessDomain: 'Transportation', + type: 'Municipal Subdivision', + name: 'Municipal subdivision', + sourceSystemAcronym: 'MOTI' + }, + { + agency: 'Transportation and Infrastructure', + businessDomain: 'Transportation', + type: 'Highway Use Permit', + name: 'Highway Use Permit', + sourceSystemAcronym: 'MOTI' + }, + { + agency: 'Transportation and Infrastructure', + businessDomain: 'Transportation', + type: 'Other', + name: 'Other', + sourceSystemAcronym: 'MOTI' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Water, Fisheries and Coast', + branch: 'Fisheries, Aquaculture and Wild Salmon', + businessDomain: 'RAPR', + type: 'New', + name: 'Riparian Area Development Permit', + sourceSystem: 'Riparian Areas Regulation Notification System', + sourceSystemAcronym: 'RARN' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Water, Fisheries and Coast', + branch: 'Water Management', + businessDomain: 'Water', + type: 'Change Approval for Work in and About a Stream', + name: 'Change approval for work in and about a stream', + acronym: 'A-CIAS', + sourceSystem: 'Water Management Application', + sourceSystemAcronym: 'WMA' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Water, Fisheries and Coast', + branch: 'Water Management', + businessDomain: 'Water', + type: 'Notification', + name: 'Notification of authorized changes in and about a stream', + acronym: 'N-CIAS', + sourceSystem: 'Water Management Application', + sourceSystemAcronym: 'WMA' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Water, Fisheries and Coast', + branch: 'Water Management', + businessDomain: 'Water', + type: 'Use Approval', + name: 'Short-term use approval', + acronym: 'STU', + sourceSystem: 'Water Management Application', + sourceSystemAcronym: 'WMA' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Water, Fisheries and Coast', + branch: 'Water Management', + businessDomain: 'Water', + type: 'New Groundwater Licence', + family: 'Water Licence', + name: 'Groundwater Licence - Wells', + acronym: 'PWD', + sourceSystem: 'Water Management Application', + sourceSystemAcronym: 'WMA' + }, + { + agency: 'Water, Land and Resource Stewardship', + division: 'Water, Fisheries and Coast', + branch: 'Water Management', + businessDomain: 'Water', + type: 'Water Licence', + family: 'Water Licence', + name: 'Surface Water Licence', + acronym: 'PD', + sourceSystem: 'Water Management Application', + sourceSystemAcronym: 'WMA' } ]; + return knex('permit_type').insert(items); }) ); diff --git a/app/src/db/models/permit.ts b/app/src/db/models/permit.ts index 7bdb99578..eddb13908 100644 --- a/app/src/db/models/permit.ts +++ b/app/src/db/models/permit.ts @@ -1,38 +1,30 @@ import { Prisma } from '@prisma/client'; import { default as permit_type } from './permit_type'; -import disconnectRelation from '../utils/disconnectRelation'; +import { default as submission } from './submission'; import type { IStamps } from '../../interfaces/IStamps'; -import type { Permit } from '../../types'; +import type { ChefsSubmissionForm, Permit } from '../../types'; // Define types const _permit = Prisma.validator()({}); const _permitWithGraph = Prisma.validator()({ - include: { permit_type: true } + include: { permit_type: true, submission: { include: { user: true } } } }); type PermitTypeRelation = { - permit_type: - | { - connect: { - permitTypeId: number; - }; - } - | { - disconnect: boolean; - }; + permit_type: { + connect: { + permitTypeId: number; + }; + }; }; type SubmissionRelation = { - submission: - | { - connect: { - submissionId: string; - }; - } - | { - disconnect: boolean; - }; + submission: { + connect: { + submissionId: string; + }; + }; }; type PrismaRelationPermit = Omit< @@ -48,16 +40,15 @@ export default { toPrismaModel(input: Permit): PrismaRelationPermit { return { permitId: input.permitId, + issuedPermitId: input.issuedPermitId, trackingId: input.trackingId, authStatus: input.authStatus, needed: input.needed, status: input.status, submittedDate: input.submittedDate ? new Date(input.submittedDate) : null, adjudicationDate: input.adjudicationDate ? new Date(input.adjudicationDate) : null, - permit_type: input.permitType?.permitTypeId - ? { connect: { permitTypeId: input.permitType?.permitTypeId } } - : disconnectRelation, - submission: input.submissionId ? { connect: { submissionId: input.submissionId } } : disconnectRelation + permit_type: { connect: { permitTypeId: input.permitType.permitTypeId } }, + submission: { connect: { submissionId: input.submissionId } } }; }, @@ -68,6 +59,7 @@ export default { permitId: input.permitId, permitTypeId: input.permitTypeId, submissionId: input.submissionId, + issuedPermitId: input.issuedPermitId, trackingId: input.trackingId, authStatus: input.authStatus, needed: input.needed, @@ -75,7 +67,7 @@ export default { submittedDate: input.submittedDate?.toISOString() ?? null, adjudicationDate: input.adjudicationDate?.toISOString() ?? null, permitType: permit_type.fromPrismaModel(input.permit_type), - submission: null, + submission: submission.fromPrismaModel(input.submission) as ChefsSubmissionForm, updatedAt: input.updatedAt?.toISOString() ?? null, updatedBy: input.updatedBy }; diff --git a/app/src/db/models/permit_type.ts b/app/src/db/models/permit_type.ts index d0acdc8ce..2c74c9635 100644 --- a/app/src/db/models/permit_type.ts +++ b/app/src/db/models/permit_type.ts @@ -19,17 +19,15 @@ export default { type: input.type, family: input.family, name: input.name, - name_subtype: input.nameSubtype, + nameSubtype: input.nameSubtype, acronym: input.acronym, - tracked_in_ats: input.trackedInATS, - source_system: input.sourceSystem, - source_system_acronym: input.sourceSystemAcronym + trackedInATS: input.trackedInATS, + sourceSystem: input.sourceSystem, + sourceSystemAcronym: input.sourceSystemAcronym }; }, - fromPrismaModel(input: PrismaRelationPermitType | null): PermitType | null { - if (!input) return null; - + fromPrismaModel(input: PrismaRelationPermitType): PermitType { return { permitTypeId: input.permitTypeId, agency: input.agency, @@ -39,11 +37,11 @@ export default { type: input.type, family: input.family, name: input.name, - nameSubtype: input.name_subtype, + nameSubtype: input.nameSubtype, acronym: input.acronym, - trackedInATS: input.tracked_in_ats, - sourceSystem: input.source_system, - sourceSystemAcronym: input.source_system_acronym + trackedInATS: input.trackedInATS, + sourceSystem: input.sourceSystem, + sourceSystemAcronym: input.sourceSystemAcronym }; } }; diff --git a/app/src/db/prisma/schema.prisma b/app/src/db/prisma/schema.prisma index c68eff0d2..badbca6e9 100644 --- a/app/src/db/prisma/schema.prisma +++ b/app/src/db/prisma/schema.prisma @@ -48,6 +48,7 @@ model permit { permitId String @id @db.Uuid permitTypeId Int submissionId String @db.Uuid + issuedPermitId String? trackingId String? authStatus String? needed String? @@ -65,24 +66,24 @@ model permit { } model permit_type { - permitTypeId Int @id @default(autoincrement()) - agency String - division String - branch String - businessDomain String - type String - family String? - name String - name_subtype String? - acronym String? - tracked_in_ats Boolean? - source_system String - source_system_acronym String - createdBy String? @default("00000000-0000-0000-0000-000000000000") - createdAt DateTime? @default(now()) @db.Timestamptz(6) - updatedBy String? - updatedAt DateTime? @db.Timestamptz(6) - permit permit[] + permitTypeId Int @id @default(autoincrement()) + agency String + division String? + branch String? + businessDomain String + type String + family String? + name String + nameSubtype String? + acronym String? + trackedInATS Boolean? + sourceSystem String? + sourceSystemAcronym String + createdBy String? @default("00000000-0000-0000-0000-000000000000") + createdAt DateTime? @default(now()) @db.Timestamptz(6) + updatedBy String? + updatedAt DateTime? @db.Timestamptz(6) + permit permit[] } model submission { diff --git a/app/src/services/permit.ts b/app/src/services/permit.ts index b443873ec..e10768be6 100644 --- a/app/src/services/permit.ts +++ b/app/src/services/permit.ts @@ -17,13 +17,15 @@ const service = { const newPermit = { ...data, permitId: uuidv4() }; const create = await prisma.permit.create({ - // @ts-expect-error TS2322 - I cant figure out the type error but it works fine data: permit.toPrismaModel(newPermit) }); const result = await prisma.permit.findUnique({ include: { - permit_type: true + permit_type: true, + submission: { + include: { user: true } + } }, where: { permitId: create.permitId @@ -44,7 +46,10 @@ const service = { deletePermit: async (permitId: string) => { const response = await prisma.permit.delete({ include: { - permit_type: true + permit_type: true, + submission: { + include: { user: true } + } }, where: { permitId: permitId @@ -77,7 +82,10 @@ const service = { listPermits: async (submissionId: string) => { const response = await prisma.permit.findMany({ include: { - permit_type: true + permit_type: true, + submission: { + include: { user: true } + } }, where: { submissionId: submissionId @@ -92,13 +100,12 @@ const service = { /** * @function updatePermit - * Creates a Permit + * Updates a Permit * @returns {Promise} The result of running the findMany operation */ updatePermit: async (data: Permit) => { try { await prisma.permit.update({ - // @ts-expect-error TS2322 - I cant figure out the type error but it works fine data: permit.toPrismaModel(data), where: { permitId: data.permitId diff --git a/app/src/types/Permit.ts b/app/src/types/Permit.ts index 0959cc87b..31664acf3 100644 --- a/app/src/types/Permit.ts +++ b/app/src/types/Permit.ts @@ -6,12 +6,13 @@ export type Permit = { permitId: string; // Primary Key permitTypeId: number; submissionId: string; + issuedPermitId: string | null; trackingId: string | null; authStatus: string | null; needed: string | null; status: string | null; submittedDate: string | null; adjudicationDate: string | null; - permitType: PermitType | null; - submission: ChefsSubmissionForm | null; + permitType: PermitType; + submission: ChefsSubmissionForm; } & Partial; diff --git a/app/src/types/PermitType.ts b/app/src/types/PermitType.ts index 510ea7623..90cda823d 100644 --- a/app/src/types/PermitType.ts +++ b/app/src/types/PermitType.ts @@ -3,8 +3,8 @@ import { IStamps } from '../interfaces/IStamps'; export type PermitType = { permitTypeId: number; // Primary Key agency: string; - division: string; - branch: string; + division: string | null; + branch: string | null; businessDomain: string; type: string; family: string | null; @@ -12,6 +12,6 @@ export type PermitType = { nameSubtype: string | null; acronym: string | null; trackedInATS: boolean | null; - sourceSystem: string; + sourceSystem: string | null; sourceSystemAcronym: string; } & Partial; diff --git a/frontend/src/components/permit/PermitCard.vue b/frontend/src/components/permit/PermitCard.vue index 1fd0214c9..a6ff83657 100644 --- a/frontend/src/components/permit/PermitCard.vue +++ b/frontend/src/components/permit/PermitCard.vue @@ -4,7 +4,7 @@ import { ref } from 'vue'; import PermitModal from '@/components/permit/PermitModal.vue'; import { Button, Card, useConfirm, useToast } from '@/lib/primevue'; import { permitService } from '@/services'; -import { formatDateLong } from '@/utils/formatters'; +import { formatDate } from '@/utils/formatters'; import type { Ref } from 'vue'; import type { Permit } from '@/types'; @@ -31,9 +31,10 @@ const toast = useToast(); const confirmDelete = (data: Permit) => { if (data.permitId) { confirm.require({ - message: `Please confirm that you want to delete the ${data.permitType?.name}.`, - header: 'Delete permit?', + message: 'Please confirm that you want to delete the selected permit. This cannot be undone.', + header: 'Confirm delete', acceptLabel: 'Confirm', + acceptClass: 'p-button-danger', rejectLabel: 'Cancel', accept: () => { permitService @@ -54,8 +55,8 @@ async function onPermitSubmit(data: Permit) { cardData.value = { ...data, - submittedDate: data.submittedDate, - adjudicationDate: data.adjudicationDate + submittedDate: data.submittedDate ? new Date(data.submittedDate).toISOString() : undefined, + adjudicationDate: data.adjudicationDate ? new Date(data.adjudicationDate).toISOString() : undefined }; permitModalVisible.value = false; @@ -90,7 +91,7 @@ async function onPermitSubmit(data: Permit) {

Last updated: - {{ formatDateLong(cardData.updatedAt as string) }} + {{ cardData.updatedAt ? formatDate(cardData.updatedAt) : undefined }}

Updated by: @@ -123,7 +124,7 @@ async function onPermitSubmit(data: Permit) {

Permit ID: - {{ cardData.permitId }} + {{ cardData.issuedPermitId }}

@@ -140,11 +141,11 @@ async function onPermitSubmit(data: Permit) {

Submitted date: - {{ formatDateLong(cardData.submittedDate as string) }} + {{ cardData.submittedDate ? formatDate(cardData.submittedDate) : undefined }}

Adjudication date: - {{ formatDateLong(cardData.adjudicationDate as string) }} + {{ cardData.adjudicationDate ? formatDate(cardData.adjudicationDate) : undefined }}

diff --git a/frontend/src/components/permit/PermitModal.vue b/frontend/src/components/permit/PermitModal.vue index 9b1cbe9bd..00be6a9f4 100644 --- a/frontend/src/components/permit/PermitModal.vue +++ b/frontend/src/components/permit/PermitModal.vue @@ -38,7 +38,7 @@ let initialFormValues: any = { trackingId: props.permit?.trackingId, businessDomain: props.permit?.permitType?.businessDomain, authStatus: props.permit?.authStatus, - sourceSystem: props.permit?.permitType?.sourceSystem, + sourceSystem: props.permit?.permitType?.sourceSystem ?? props.permit?.permitType?.sourceSystemAcronym, submittedDate: props.permit?.submittedDate ? new Date(props.permit.submittedDate) : undefined, permitId: props.permit?.permitId, adjudicationDate: props.permit?.adjudicationDate ? new Date(props.permit.adjudicationDate) : undefined @@ -51,7 +51,6 @@ const formSchema = object({ status: string().required().label('Permit state'), agency: string().required().label('Agency'), businessDomain: string().required().label('Business domain'), - authStatus: string().required().label('Authorization status'), sourceSystem: string().required().label('Source system'), submittedDate: string().required().label('Submitted date') }); @@ -66,12 +65,14 @@ function onPermitTypeChanged(e: DropdownChangeEvent, setValues: Function) { setValues({ agency: type.agency, businessDomain: type.businessDomain, - sourceSystem: type.sourceSystem + sourceSystem: type.sourceSystem ?? type.sourceSystemAcronym }); } -function onSubmit(data: any) { - initialFormValues = data; +// @ts-expect-error TS7031 resetForm is an automatic binding https://vee-validate.logaretm.com/v4/guide/components/handling-forms/ +function onSubmit(data: any, { resetForm }) { + if (props.permit) initialFormValues = data; + else resetForm(); emit('permit:submit', data); } @@ -138,6 +139,7 @@ onMounted(async () => { class="col-12 lg:col-6" name="agency" label="Agency" + :disabled="true" /> { class="col-12 lg:col-6" name="businessDomain" label="Business domain" + :disabled="true" /> { class="col-12 lg:col-6" name="sourceSystem" label="Source system" + :disabled="true" /> { />