-
- mdi-account {{ legalName }}
+
+ mdi-account {{ legalName }}
{{ item.businessName }}
@@ -107,6 +107,7 @@ import { authorizedTableHeaders } from '@/resources'
export default defineComponent({
name: 'CertifyInformation',
+ emits: ['certifyValid'],
components: {
BaseAddress
},
diff --git a/ppr-ui/src/components/common/ContactInformation.vue b/ppr-ui/src/components/common/ContactInformation.vue
index 313ad5bfe..2d7ffe042 100644
--- a/ppr-ui/src/components/common/ContactInformation.vue
+++ b/ppr-ui/src/components/common/ContactInformation.vue
@@ -24,8 +24,8 @@
class="pa-8 pr-6"
:class="{ 'border-error-left': showBorderError }"
>
-
-
+
+
-
+
-
+
-
+
-
+
{{ label }}
-
+
diff --git a/ppr-ui/src/components/common/PartyForm.vue b/ppr-ui/src/components/common/PartyForm.vue
index 146d8e69b..892352f7f 100644
--- a/ppr-ui/src/components/common/PartyForm.vue
+++ b/ppr-ui/src/components/common/PartyForm.vue
@@ -1,10 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
-
- Person's Name
-
+
+ Person's Legal Name
+
+
+
+
+
+
+
+
+
+
+
+
@@ -17,9 +80,9 @@
filled
id="business-name"
class="pt-4 pr-2"
- label="Business Name"
+ :label="`Business Name ${schema.businessName.optional ? '(Optional)' : ''}`"
v-model="partyModel.businessName"
- :rules="schema.businessName"
+ :rules="schema.businessName.rules"
/>
@@ -38,7 +101,7 @@
:fieldHint="orgLookupConfig.fieldHint"
:nilSearchText="orgLookupConfig.nilSearchText"
:baseValue="partyModel.businessName"
- :orgNameRules="schema.businessName"
+ :orgNameRules="schema.businessName.rules"
@updateOrgName="partyModel.businessName = $event"
/>
@@ -50,9 +113,9 @@
filled
id="contact-info-email"
class="pt-4 pr-2"
- label="Email Address (Optional)"
+ :label="`Email Address ${schema.email.optional ? '(Optional)' : ''}`"
v-model="partyModel.emailAddress"
- :rules="schema.email"
+ :rules="schema.email.rules"
/>
@@ -67,9 +130,9 @@
filled
id="party-form-phone"
class="pr-3"
- label="Phone Number"
+ :label="`Phone Number ${schema.phone.optional ? '(Optional)' : ''}`"
v-model="partyModel.phoneNumber"
- :rules="schema.phone"
+ :rules="schema.phone.rules"
/>
@@ -77,9 +140,9 @@
filled
id="party-form-phone-ext"
class="px-2"
- label="Extension (Optional)"
+ :label="`Extension ${schema.phoneExt.optional ? '(Optional)' : ''}`"
v-model="partyModel.phoneExtension"
- :rules="schema.phoneExt"
+ :rules="schema.phoneExt.rules"
/>
@@ -88,6 +151,7 @@
Mailing Address
+ Registry documents, if any, will be mailed to this address.
@@ -109,6 +173,7 @@ import { FormIF, OrgLookupConfigIF, PartyIF, PartySchemaIF } from '@/interfaces'
import { BaseAddress } from '@/composables/address'
import { VueMaskDirective } from 'v-mask'
import OrgNameLookup from '@/components/common/OrgNameLookup.vue'
+import { ContactTypes } from '@/enums'
export default defineComponent({
name: 'PartyForm',
@@ -129,6 +194,10 @@ export default defineComponent({
orgLookupConfig: {
type: Object as () => OrgLookupConfigIF,
default: null
+ },
+ showErrors: {
+ type: Boolean,
+ default: false
}
},
directives: {
@@ -142,6 +211,10 @@ export default defineComponent({
isFormValid: false,
isAddressValid: false,
partyModel: props.baseParty as PartyIF,
+ contactInfoType: ContactTypes.PERSON as ContactTypes,
+ requiresPartyTypeSelect: computed(() => {
+ return hasPropData('personName') && hasPropData('businessName')
+ }),
isValid: computed(() => localState.isFormValid && localState.isAddressValid)
})
@@ -155,11 +228,30 @@ export default defineComponent({
await baseAddressRef.value?.validate()
}
+ watch(() => props.baseParty, (party: PartyIF) => {
+ localState.contactInfoType = party.businessName ? ContactTypes.BUSINESS : ContactTypes.PERSON
+ localState.partyModel = party
+ })
watch(() => localState.isValid, (isValid: boolean) => {
emit('isValid', isValid)
})
+ watch(() => props.showErrors, async () => {
+ await validatePartyForm()
+ })
+ /** Clear the name values on contact type changes **/
+ watch(() => localState.contactInfoType, (type: ContactTypes) => {
+ partyFormRef.value?.resetValidation()
+ if (type === ContactTypes.PERSON) {
+ localState.partyModel.businessName = ''
+ } else {
+ localState.partyModel.personName.first = ''
+ localState.partyModel.personName.middle = ''
+ localState.partyModel.personName.last = ''
+ }
+ })
return {
+ ContactTypes,
hasPropData,
partyFormRef,
baseAddressRef,
diff --git a/ppr-ui/src/components/common/RegistrationsWrapper.vue b/ppr-ui/src/components/common/RegistrationsWrapper.vue
index 2d923844c..83dd50a15 100644
--- a/ppr-ui/src/components/common/RegistrationsWrapper.vue
+++ b/ppr-ui/src/components/common/RegistrationsWrapper.vue
@@ -620,8 +620,8 @@ export default defineComponent({
case TableActions.OPEN_MHR:
openMhr(mhrInfo)
break
- case TableActions.OPEN_RES_EXEMPTION:
- case TableActions.OPEN_NON_RES_EXEMPTION:
+ case UnitNoteDocTypes.RESIDENTIAL_EXEMPTION_ORDER:
+ case UnitNoteDocTypes.NON_RESIDENTIAL_EXEMPTION:
openMhrExemption(mhrInfo, action)
break
default:
diff --git a/ppr-ui/src/components/common/Remarks.vue b/ppr-ui/src/components/common/Remarks.vue
index 68264da35..7cf165db7 100644
--- a/ppr-ui/src/components/common/Remarks.vue
+++ b/ppr-ui/src/components/common/Remarks.vue
@@ -11,17 +11,17 @@
:class="{ 'border-error-left': showBorderError }"
flat
>
-
-
-
- {{ content.sideLabel }}
-
-
-
+
+
+
+ {{ content.sideLabel }}
+
+
+
+ />
+
+
+
+
+
+
+
+
+
+
+ mdi-information-outline
+ This step is unfinished.
+ Return to this step to complete it.
+
+
+
+
+
+
+
+
+ {{item.property || '(Not Entered)'}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ppr-ui/src/components/common/index.ts b/ppr-ui/src/components/common/index.ts
index 2edb73198..309ebb72a 100644
--- a/ppr-ui/src/components/common/index.ts
+++ b/ppr-ui/src/components/common/index.ts
@@ -34,3 +34,4 @@ export { default as PartyForm } from './PartyForm.vue'
export { default as PartyReview } from './PartyReview.vue'
export { default as FormCard } from './FormCard.vue'
export { default as OrgNameLookup } from './OrgNameLookup.vue'
+export { default as ReviewCard } from './ReviewCard.vue'
diff --git a/ppr-ui/src/components/mhrRegistration/HomeOwners/HomeOwnersTable.vue b/ppr-ui/src/components/mhrRegistration/HomeOwners/HomeOwnersTable.vue
index b6708d437..087dc4021 100644
--- a/ppr-ui/src/components/mhrRegistration/HomeOwners/HomeOwnersTable.vue
+++ b/ppr-ui/src/components/mhrRegistration/HomeOwners/HomeOwnersTable.vue
@@ -1063,7 +1063,7 @@ export default defineComponent({
}
.owner-info {
- min-width: 60rem;
+ min-width: 50rem;
display: flex;
}
}
diff --git a/ppr-ui/src/components/mhrRegistration/ReviewConfirm/YourHomeReview.vue b/ppr-ui/src/components/mhrRegistration/ReviewConfirm/YourHomeReview.vue
index 857621ea9..9653a92cf 100644
--- a/ppr-ui/src/components/mhrRegistration/ReviewConfirm/YourHomeReview.vue
+++ b/ppr-ui/src/components/mhrRegistration/ReviewConfirm/YourHomeReview.vue
@@ -216,7 +216,7 @@ export default defineComponent({
showStepError: computed(() => !getStepValidation(MhrSectVal.YOUR_HOME_VALID)),
hasData: computed(() : boolean => {
return hasTruthyValue(getMhrRegistrationHomeDescription.value) ||
- (!isMhrManufacturerRegistration.value && !!getMhrRegistrationOtherInfo.value)
+ (!isMhrManufacturerRegistration.value && !!getMhrRegistrationOtherInfo.value)
})
})
diff --git a/ppr-ui/src/components/mhrTransfers/ConfirmCompletion.vue b/ppr-ui/src/components/mhrTransfers/ConfirmCompletion.vue
index d288a4cec..5946ef77b 100644
--- a/ppr-ui/src/components/mhrTransfers/ConfirmCompletion.vue
+++ b/ppr-ui/src/components/mhrTransfers/ConfirmCompletion.vue
@@ -1,7 +1,7 @@
-
{{ sectionNumber }} . Confirm
-
+
{{ `${sectionNumber ? sectionNumber + '.' : ''} Confirm`}}
+
The following information must be completed and confirmed before submitting this registration.
-
-
- Bill of sale has been signed by either all owners or by someone with the authority
- to act on behalf of the registered owners and witnessed by an independent third party. If this is a
- transfer to a beneficiary, you must have written consent from all beneficiaries that are not being
- added as an owner.
-
- Note: If the bill of sale has been signed by someone acting on behalf of the registered
- owners, the person submitting this transfer is a lawyer or notary, and the power by which the
- signatory was authorized was power of attorney, representation agreement, committee, receiver, or writ
- of seizure and sale.
-
-
-
- Original or
-
-
- certified copy
-
- Vital Statistics and associated Funeral Homes issue original death certificates on secure, banknote
- paper. Certified copies are obtained by presenting those original certificate(s) to a lawyer,
- notary or other commissioner for taking affidavits and having them confirm that it is a true copy
- of the original. A statement of death or a cremation certificate from a funeral director is not
- acceptable.
-
- of Death Certificate that has been issued by Vital Statistics and has been received for each
- joint tenant owner being removed due to death. I confirm that it was
-
-
- issued from Canada or the United States
-
- If the death certificate was issued outside of Canada or the US, the transfer will have to be sent
- to the Manufactured Home Registry.
- , and the name on the death certificate matches the name displayed above exactly.
+
+
+
+ Bill of sale has been signed by either all owners or by someone with the authority
+ to act on behalf of the registered owners and witnessed by an independent third party. If this is a
+ transfer to a beneficiary, you must have written consent from all beneficiaries that are not being
+ added as an owner.
+
+ Note: If the bill of sale has been signed by someone acting on behalf of the
+ registered owners, the person submitting this transfer is a lawyer or notary, and the power by which
+ the signatory was authorized was power of attorney, representation agreement, committee, receiver,
+ or writ of seizure and sale.
-
-
- Transfer or Change Ownership form has been received and retained.
-
-
- Court certified true copy of the Grant of Probate with the will attached.
-
-
- Certified true copy of Grant of Administration issued by the court.
-
-
- Affidavit of Administration with List of Assets and Liabilities.
-
-
- Certified true copy of the will.
-
-
- Original signed Affidavit of Executor form has been received and retained.
-
-
- Search of the Corporate Register has been completed if one or more of the current or
- future owners is an incorporated company, society or cooperative association.
-
- Note: For current registered owners the incorporated business must have been active on
- the Corporate Register at the time the bill of sale was signed. Future owners must be in active status
- at the time of registration.
-
-
-
- Personal Property Registry lien search has been completed and there are no liens
- on the home that stop the transfer.
-
- Note: Liens that stop the transfer include Family Maintenance Enforcement Act, Family
- Relations Act, BC Second Mortgage, Land Tax Deferment Act.
-
-
-
+
+
+ Original or
+
+
+ certified copy
+
+ Vital Statistics and associated Funeral Homes issue original death certificates on secure,
+ banknote paper. Certified copies are obtained by presenting those original certificate(s) to a
+ lawyer, notary or other commissioner for taking affidavits and having them confirm that it is a
+ true copy of the original. A statement of death or a cremation certificate from a funeral director
+ is not acceptable.
+
+ of Death Certificate that has been issued by Vital Statistics and has been received for
+ each joint tenant owner being removed due to death. I confirm that it was
+
+
+ issued from Canada or the United States
+
+ If the death certificate was issued outside of Canada or the US, the transfer will have to be sent
+ to the Manufactured Home Registry.
+ , and the name on the death certificate matches the name displayed above exactly.
+
+
+
+ Transfer or Change Ownership form has been received and retained.
+
+
+ Court certified true copy of the Grant of Probate with the will attached.
+
+
+ Certified true copy of Grant of Administration issued by the court.
+
+
+ Affidavit of Administration with List of Assets and Liabilities.
+
+
+ Certified true copy of the will.
+
+
+ Original signed Affidavit of Executor form has been received and retained.
+
+
+ Search of the Corporate Register has been completed if one or more of the current
+ or future owners is an incorporated company, society or cooperative association.
+
+ Note: For current registered owners the incorporated business must have been active on
+ the Corporate Register at the time the bill of sale was signed. Future owners must be in active
+ status at the time of registration.
+
+
+
+ Personal Property Registry lien search has been completed and there are no liens
+ on the home that stop the transfer.
+
+ Note: Liens that stop the transfer include Family Maintenance Enforcement Act, Family
+ Relations Act, BC Second Mortgage, Land Tax Deferment Act.
+
+
+
+
-
-
+
+
-
+
-
-
- I, {{ legalName }} , confirm that all of the requirements listed above have been completed.
-
-
-
+ class="py-7 px-4 my-0 confirm-checkbox"
+ :hide-details="true"
+ id="checkbox-certified"
+ v-model="confirmCompletion"
+ data-test-id="confirm-completion-checkbox"
+ >
+
+
+ I, {{ legalName }} , confirm that all of the requirements listed above have been
+ completed.
+
+
+
@@ -147,11 +149,10 @@ import { storeToRefs } from 'pinia'
export default defineComponent({
name: 'ConfirmCompletion',
-
props: {
sectionNumber: {
type: Number,
- default: 2
+ default: null
},
legalName: {
type: String,
diff --git a/ppr-ui/src/components/tables/common/TableRow.vue b/ppr-ui/src/components/tables/common/TableRow.vue
index 0dfb50a9c..b2616702b 100644
--- a/ppr-ui/src/components/tables/common/TableRow.vue
+++ b/ppr-ui/src/components/tables/common/TableRow.vue
@@ -387,20 +387,22 @@
-
+
Residential Exemption
-
+
Non-Residential Exemption
@@ -482,7 +484,8 @@ import {
UITransferTypes,
MhApiStatusTypes,
MhApiFrozenDocumentTypes,
- UnitNoteDocTypes
+ UnitNoteDocTypes,
+ HomeLocationTypes
} from '@/enums'
import { useRegistration } from '@/composables/useRegistration'
import { useExemptions, useTransferOwners } from '@/composables'
@@ -577,13 +580,13 @@ export default defineComponent({
'registration you must conduct a search.'
} else if (!item.registeringName) {
return 'Verification Statements are only available ' +
- 'to Secured Parties or the Registering Party of this filing. To ' +
- 'view the details of this registration you must conduct a search.'
+ 'to Secured Parties or the Registering Party of this filing. To ' +
+ 'view the details of this registration you must conduct a search.'
} else {
return 'This document PDF is still being generated. Click the ' +
- ' ' +
- ' icon to see if your PDF is ready to download. ' +
- 'Note: Large documents may take up to 20 minutes to generate.'
+ ' ' +
+ ' icon to see if your PDF is ready to download. ' +
+ 'Note: Large documents may take up to 20 minutes to generate.'
}
}
@@ -662,9 +665,9 @@ export default defineComponent({
})
}
- const openExemption = (action: TableActions, item: MhRegistrationSummaryIF): void => {
+ const openExemption = (doctType: UnitNoteDocTypes, item: MhRegistrationSummaryIF): void => {
emit('action', {
- action: action,
+ action: doctType,
mhrInfo: item
})
}
@@ -902,6 +905,7 @@ export default defineComponent({
hasLockedState,
MhApiFrozenDocumentTypes,
UnitNoteDocTypes,
+ HomeLocationTypes,
...toRefs(localState)
}
}
diff --git a/ppr-ui/src/components/tombstone/Tombstone.vue b/ppr-ui/src/components/tombstone/Tombstone.vue
index 9418e64f0..7112c619b 100644
--- a/ppr-ui/src/components/tombstone/Tombstone.vue
+++ b/ppr-ui/src/components/tombstone/Tombstone.vue
@@ -38,7 +38,7 @@ export default defineComponent({
return localState.currentPath.includes('amend')
}),
displayMhrInformation: computed((): boolean => {
- return localState.currentPath.includes('mhr-information')
+ return localState.currentPath.includes('mhr-information') || localState.currentPath.includes('exemption')
})
})
diff --git a/ppr-ui/src/components/tombstone/TombstoneDischarge.vue b/ppr-ui/src/components/tombstone/TombstoneDischarge.vue
index 40d77ae65..f28211cff 100644
--- a/ppr-ui/src/components/tombstone/TombstoneDischarge.vue
+++ b/ppr-ui/src/components/tombstone/TombstoneDischarge.vue
@@ -13,11 +13,12 @@
{{ creationDate }}
-
-
+
+
+
Registration Status:
-
+
{{ statusType }}
@@ -126,5 +127,6 @@ export default defineComponent({
.info-label {
color: $gray9 !important;
font-weight: bold;
+ white-space: nowrap;
}
diff --git a/ppr-ui/src/components/userAccess/ReviewConfirm/Authorization.vue b/ppr-ui/src/components/userAccess/ReviewConfirm/Authorization.vue
index cc9a689bb..17f6213d5 100644
--- a/ppr-ui/src/components/userAccess/ReviewConfirm/Authorization.vue
+++ b/ppr-ui/src/components/userAccess/ReviewConfirm/Authorization.vue
@@ -5,7 +5,7 @@
:class="{'border-error-left': showErrors}"
>
-
+
label {
height: fit-content;
}
-
}
-
diff --git a/ppr-ui/src/components/userAccess/ReviewConfirm/ListRequirements.vue b/ppr-ui/src/components/userAccess/ReviewConfirm/ListRequirements.vue
index bd2f07585..dd24f3584 100644
--- a/ppr-ui/src/components/userAccess/ReviewConfirm/ListRequirements.vue
+++ b/ppr-ui/src/components/userAccess/ReviewConfirm/ListRequirements.vue
@@ -4,10 +4,10 @@
v-for="(requirement, index) in requirements"
:key="index"
>
-
+
-
+
{{ requirement.boldTextPreTooltip }}
@@ -20,7 +20,7 @@
{{ requirement.boldTextPostTooltip }}
- {{ requirement.regularText }}
+ {{ requirement.regularText }}
@@ -28,6 +28,19 @@
{{ requirement.boldText }}
{{ requirement.regularText }}
+
+
+
+
+
+
+ Note:
+ {{ requirement.note }}
+
@@ -47,7 +60,4 @@ export default defineComponent({
diff --git a/ppr-ui/src/composables/common/index.ts b/ppr-ui/src/composables/common/index.ts
index d703c8e50..fc62f3faa 100644
--- a/ppr-ui/src/composables/common/index.ts
+++ b/ppr-ui/src/composables/common/index.ts
@@ -1,2 +1,3 @@
export * from './useAuth'
export * from './useNavigation'
+export * from './usePayment'
diff --git a/ppr-ui/src/composables/common/usePayment.ts b/ppr-ui/src/composables/common/usePayment.ts
new file mode 100644
index 000000000..07b2c1369
--- /dev/null
+++ b/ppr-ui/src/composables/common/usePayment.ts
@@ -0,0 +1,76 @@
+import { reactive } from 'vue-demi'
+import { StaffPaymentOptions } from '@bcrs-shared-components/enums'
+import { StaffPaymentIF } from '@bcrs-shared-components/interfaces'
+import { useStore } from '@/store/store'
+
+/**
+ * Common Payment functionality that can be used to handle instances of the staff payment component.
+ * **/
+export const usePayment = () => {
+ const { setStaffPayment } = useStore()
+ const localState = reactive({
+ staffPaymentValid: false,
+ staffPayment: {
+ option: StaffPaymentOptions.NONE,
+ routingSlipNumber: '',
+ bcolAccountNumber: '',
+ datNumber: '',
+ folioNumber: '',
+ isPriority: false
+ }
+ })
+
+ /** Called when component's staff payment data has been updated. */
+ const onStaffPaymentDataUpdate = async (val: StaffPaymentIF): Promise => {
+ let staffPaymentData: StaffPaymentIF = {
+ ...val
+ }
+
+ switch (staffPaymentData.option) {
+ case StaffPaymentOptions.FAS:
+ staffPaymentData = {
+ option: StaffPaymentOptions.FAS,
+ routingSlipNumber: staffPaymentData.routingSlipNumber,
+ isPriority: staffPaymentData.isPriority,
+ bcolAccountNumber: '',
+ datNumber: '',
+ folioNumber: ''
+ }
+ localState.staffPaymentValid = false
+ break
+
+ case StaffPaymentOptions.BCOL:
+ staffPaymentData = {
+ option: StaffPaymentOptions.BCOL,
+ bcolAccountNumber: staffPaymentData.bcolAccountNumber,
+ datNumber: staffPaymentData.datNumber,
+ folioNumber: staffPaymentData.folioNumber,
+ isPriority: staffPaymentData.isPriority,
+ routingSlipNumber: ''
+ }
+ localState.staffPaymentValid = false
+ break
+
+ case StaffPaymentOptions.NO_FEE:
+ staffPaymentData = {
+ option: StaffPaymentOptions.NO_FEE,
+ routingSlipNumber: '',
+ isPriority: false,
+ bcolAccountNumber: '',
+ datNumber: '',
+ folioNumber: ''
+ }
+ localState.staffPaymentValid = true
+ break
+ case StaffPaymentOptions.NONE: // should never happen
+ break
+ }
+
+ setStaffPayment(staffPaymentData)
+ }
+
+ return {
+ onStaffPaymentDataUpdate,
+ ...localState
+ }
+}
diff --git a/ppr-ui/src/composables/exemption/useExemptions.ts b/ppr-ui/src/composables/exemption/useExemptions.ts
index 551637381..9dcaf442a 100644
--- a/ppr-ui/src/composables/exemption/useExemptions.ts
+++ b/ppr-ui/src/composables/exemption/useExemptions.ts
@@ -1,14 +1,22 @@
-import { computed, ComputedRef, nextTick } from 'vue-demi'
+import { computed, ComputedRef } from 'vue-demi'
import { storeToRefs } from 'pinia'
import { useStore } from '@/store/store'
import { useNavigation } from '@/composables'
import { RouteNames, UnitNoteDocTypes } from '@/enums'
-import { getFeatureFlag } from '@/utils'
+import {
+ cleanEmpty,
+ fromDisplayPhone,
+ getAccountInfoFromAuth,
+ getFeatureFlag,
+ hasTruthyValue,
+ parseAccountToSubmittingParty
+} from '@/utils'
+import { ExemptionIF } from '@/interfaces'
export const useExemptions = () => {
const { goToRoute } = useNavigation()
- const { setMhrExemptionNote } = useStore()
- const { isRoleStaffReg, isRoleQualifiedSupplier } = storeToRefs(useStore())
+ const { setMhrExemption, setMhrExemptionNote, setMhrExemptionValidation, setMhrExemptionValue } = useStore()
+ const { getMhrExemption, isRoleStaffReg, isRoleQualifiedSupplier } = storeToRefs(useStore())
/** Returns true when staff or qualified supplier and the feature flag is enabled **/
const isExemptionEnabled: ComputedRef = computed((): boolean => {
@@ -22,13 +30,75 @@ export const useExemptions = () => {
await goToRoute(RouteNames.EXEMPTION_DETAILS)
}
+ /** Set exemption validation flag values **/
+ const updateValidation = (validationFlag: string, value: boolean): void => {
+ setMhrExemptionValidation({ key: validationFlag, value: value })
+ }
+
+ /** Construct the payload for Exemptions submission **/
+ const buildExemptionPayload = (): ExemptionIF => {
+ const party = getMhrExemption.value.submittingParty
+ const submittingParty = {
+ ...party,
+ personName: (party.personName && hasTruthyValue(party.personName))
+ ? { ...party.personName }
+ : '',
+ phoneNumber: fromDisplayPhone(party.phoneNumber)
+ }
+ return {
+ ...cleanEmpty(getMhrExemption.value),
+ submittingParty: cleanEmpty(submittingParty)
+ }
+ }
+
+ /** Initialize Exemption **/
const initExemption = async (exemptionType: UnitNoteDocTypes): Promise => {
+ setMhrExemption({
+ documentId: '',
+ clientReferenceId: '',
+ attentionReference: '',
+ submittingParty: {
+ personName: {
+ first: '',
+ last: '',
+ middle: ''
+ },
+ businessName: '',
+ address: {
+ street: '',
+ streetAdditional: '',
+ city: '',
+ region: '',
+ country: '',
+ postalCode: ''
+ },
+ emailAddress: '',
+ phoneNumber: '',
+ phoneExtension: ''
+ },
+ nonResidential: null,
+ note: {
+ documentType: null,
+ remarks: ''
+ }
+ })
setMhrExemptionNote({ key: 'documentType', value: exemptionType })
- // Reset filing here
+
+ if (isRoleQualifiedSupplier.value) {
+ const account = await getAccountInfoFromAuth()
+ setMhrExemptionValue({ key: 'submittingParty', value: parseAccountToSubmittingParty(account) })
+
+ // Reset Validations here for qs specific requirements
+ updateValidation('documentId', true)
+ updateValidation('submittingParty', true)
+ updateValidation('staffPayment', true)
+ }
}
return {
isExemptionEnabled,
- goToExemptions
+ goToExemptions,
+ updateValidation,
+ buildExemptionPayload
}
}
diff --git a/ppr-ui/src/composables/mhrInformation/useTransferOwners.ts b/ppr-ui/src/composables/mhrInformation/useTransferOwners.ts
index 3d9d02625..2661ed0e2 100644
--- a/ppr-ui/src/composables/mhrInformation/useTransferOwners.ts
+++ b/ppr-ui/src/composables/mhrInformation/useTransferOwners.ts
@@ -344,12 +344,15 @@ export const useTransferOwners = (enableAllActions: boolean = false) => {
return hasOneDeleted && hasSomeNotDeleted
},
hasAllCurrentOwnersRemoved: (groupId): boolean => {
- const regOwners = getMhrTransferHomeOwnerGroups.value
- .find(group => group.groupId === groupId).owners
+ const group: MhrHomeOwnerGroupIF = getMhrTransferHomeOwnerGroups.value
+ .find(group => group.groupId === groupId)
- if (regOwners?.length === 0) return true
+ // for newly Added or Deleted groups do not check for current owners
+ if ([ActionTypes.ADDED, ActionTypes.REMOVED].includes(group.action)) return false
- return regOwners
+ if (group.owners?.length === 0) return true
+
+ return group.owners
.every(owner => isCurrentOwner(owner)
? owner.action === ActionTypes.REMOVED
: owner.action === ActionTypes.ADDED)
diff --git a/ppr-ui/src/composables/userAccess/useUserAccess.ts b/ppr-ui/src/composables/userAccess/useUserAccess.ts
index 70b12869d..786f35e9a 100644
--- a/ppr-ui/src/composables/userAccess/useUserAccess.ts
+++ b/ppr-ui/src/composables/userAccess/useUserAccess.ts
@@ -114,21 +114,21 @@ export const useUserAccess = () => {
status: ProductStatus.ACTIVE,
icon: 'mdi-check-circle',
color: 'success',
- msg: `Your application for Qualified Supplier – ${productName} access to the Manufactured Home
+ msg: `Your application for Qualified Supplier – ${productName} access to the Manufactured Home
Registry has been approved.`
},
{
status: ProductStatus.PENDING,
icon: 'mdi-clock-outline',
color: '',
- msg: `Your application for Qualified Supplier – ${productName} access is under review. You will
+ msg: `Your application for Qualified Supplier – ${productName} access is under review. You will
receive email notification once your request has been reviewed.`
},
{
status: ProductStatus.REJECTED,
icon: 'mdi-alert',
color: 'error',
- msg: `Your application for Qualified Supplier – ${productName} access has been rejected.
+ msg: `Your application for Qualified Supplier – ${productName} access has been rejected.
Refer to your notification email or contact ${helpEmail} for details.
You can submit a new Qualified Supplier access request once you have all of the required information.`
}
diff --git a/ppr-ui/src/enums/errorCategories.ts b/ppr-ui/src/enums/errorCategories.ts
index faf9d66c3..befb64e18 100644
--- a/ppr-ui/src/enums/errorCategories.ts
+++ b/ppr-ui/src/enums/errorCategories.ts
@@ -22,5 +22,6 @@ export enum ErrorCategories {
SEARCH_COMPLETE = 'search-complete',
SEARCH_UPDATE = 'search-update',
LTSA_REQUEST = 'ltsa-request',
- MHR_UNIT_NOTE_FILING = 'mhr-unit-note-filing'
+ MHR_UNIT_NOTE_FILING = 'mhr-unit-note-filing',
+ EXEMPTION_SAVE = 'exemption-save',
}
diff --git a/ppr-ui/src/enums/routeNames.ts b/ppr-ui/src/enums/routeNames.ts
index 8e58bd76a..1869cdac0 100644
--- a/ppr-ui/src/enums/routeNames.ts
+++ b/ppr-ui/src/enums/routeNames.ts
@@ -28,6 +28,8 @@ export enum RouteNames {
YOUR_HOME = 'your-home',
MHR_INFORMATION = 'mhr-information',
MHR_INFORMATION_NOTE = 'mhr-information-note',
+ RESIDENTIAL_EXEMPTION = 'residential-exemption',
+ NON_RESIDENTIAL_EXEMPTION = 'non-residential-exemption',
EXEMPTION_DETAILS = 'exemption-details',
EXEMPTION_REVIEW = 'exemption-review',
QS_USER_ACCESS = 'user-access',
diff --git a/ppr-ui/src/enums/tableActions.ts b/ppr-ui/src/enums/tableActions.ts
index a53db9eef..42eb69ec5 100644
--- a/ppr-ui/src/enums/tableActions.ts
+++ b/ppr-ui/src/enums/tableActions.ts
@@ -9,6 +9,4 @@ export enum TableActions {
REMOVE_TRANSFER_DRAFT = 'removeTransferDraft',
OPEN_MHR = 'openMhr',
EDIT_NEW_MHR = 'editMhr',
- OPEN_RES_EXEMPTION = 'openResExemption',
- OPEN_NON_RES_EXEMPTION = 'openNonResExemption'
}
diff --git a/ppr-ui/src/interfaces/error-interface.ts b/ppr-ui/src/interfaces/error-interface.ts
index 709c7314d..c49eecf1d 100644
--- a/ppr-ui/src/interfaces/error-interface.ts
+++ b/ppr-ui/src/interfaces/error-interface.ts
@@ -7,3 +7,7 @@ export interface ErrorIF {
statusCode: number,
type?: ErrorCodes
}
+
+export interface ErrorDetailIF {
+ error: ErrorIF;
+}
diff --git a/ppr-ui/src/interfaces/exemption-interfaces/ExemptionIF.ts b/ppr-ui/src/interfaces/exemption-interfaces/ExemptionIF.ts
index 2b835c938..1dcab5a4a 100644
--- a/ppr-ui/src/interfaces/exemption-interfaces/ExemptionIF.ts
+++ b/ppr-ui/src/interfaces/exemption-interfaces/ExemptionIF.ts
@@ -2,12 +2,24 @@ import { PartyIF } from '@/interfaces'
import { UnitNoteDocTypes } from '@/enums'
export interface ExemptionIF {
+ documentId: string
clientReferenceId: string
attentionReference: string
- submittingParty: PartyIF,
+ submittingParty: PartyIF
nonResidential: boolean
note: {
documentType: UnitNoteDocTypes
remarks: string
}
}
+
+export interface ExemptionValidationIF {
+ documentId: boolean
+ remarks: boolean
+ submittingParty: boolean
+ attention: boolean
+ folio: boolean
+ confirmCompletion: boolean
+ authorization: boolean
+ staffPayment: boolean
+}
diff --git a/ppr-ui/src/interfaces/index.ts b/ppr-ui/src/interfaces/index.ts
index 3ce6b0eb4..7ceeb05de 100644
--- a/ppr-ui/src/interfaces/index.ts
+++ b/ppr-ui/src/interfaces/index.ts
@@ -22,3 +22,4 @@ export * from './content-interface'
export * from './unit-note-interfaces'
export * from './mhr-user-access-interfaces'
export * from './user-access-interfaces'
+export * from './exemption-interfaces'
diff --git a/ppr-ui/src/interfaces/party-interfaces/party-schema-interface.ts b/ppr-ui/src/interfaces/party-interfaces/party-schema-interface.ts
index 3e6c61c0d..b43c238f8 100644
--- a/ppr-ui/src/interfaces/party-interfaces/party-schema-interface.ts
+++ b/ppr-ui/src/interfaces/party-interfaces/party-schema-interface.ts
@@ -1,12 +1,12 @@
import { SchemaIF } from '@/composables/address/interfaces'
export interface PartySchemaIF {
- firstName: Array<(v:string) => true | string>,
- middleName: Array<(v:string) => true | string>,
- lastName: Array<(v:string) => true | string>,
- businessName: Array<(v:string) => true | string>,
- phone: Array<(v:string) => true | string>,
- phoneExt: Array<(v:string) => true | string>,
- email: Array<(v:string) => true | string>,
- address: SchemaIF
+ firstName: { rules: Array<(v:string) => true | string>, optional: boolean }
+ middleName: { rules: Array<(v:string) => true | string>, optional: boolean }
+ lastName: { rules: Array<(v:string) => true | string>, optional: boolean }
+ businessName: { rules: Array<(v:string) => true | string>, optional: boolean }
+ phone: { rules: Array<(v:string) => true | string>, optional: boolean }
+ phoneExt: { rules: Array<(v:string) => true | string>, optional: boolean }
+ email: { rules: Array<(v:string) => true | string>, optional: boolean }
+ address: { rules: SchemaIF, optional: boolean }
}
diff --git a/ppr-ui/src/interfaces/store-interfaces/state-model-interface.ts b/ppr-ui/src/interfaces/store-interfaces/state-model-interface.ts
index a1132c195..0840b1c47 100644
--- a/ppr-ui/src/interfaces/store-interfaces/state-model-interface.ts
+++ b/ppr-ui/src/interfaces/store-interfaces/state-model-interface.ts
@@ -28,11 +28,12 @@ import {
UnitNoteRegistrationIF,
MhrUnitNoteValidationStateIF,
UserAccessIF,
- UserAccessValidationIF
+ UserAccessValidationIF,
+ ExemptionIF,
+ ExemptionValidationIF
} from '@/interfaces'
import { StaffPaymentIF } from '@bcrs-shared-components/interfaces'
import { UnitNoteIF } from '@/interfaces/unit-note-interfaces/unit-note-interface'
-import { ExemptionIF } from '@/interfaces/exemption-interfaces'
// State model example
export interface StateModelIF {
@@ -90,6 +91,7 @@ export interface StateModelIF {
mhrUnitNoteValidationState: MhrUnitNoteValidationStateIF
mhrUserAccess: UserAccessIF
mhrExemption: ExemptionIF
+ mhrExemptionValidation: ExemptionValidationIF
mhrUserAccessValidation: UserAccessValidationIF
mhrSearchResultSelectAllLien: boolean
mhrValidationState?: MhrValidationStateIF
diff --git a/ppr-ui/src/interfaces/user-access-interfaces/user-access-requirements-interface.ts b/ppr-ui/src/interfaces/user-access-interfaces/user-access-requirements-interface.ts
index 4735c723e..6e3de1497 100644
--- a/ppr-ui/src/interfaces/user-access-interfaces/user-access-requirements-interface.ts
+++ b/ppr-ui/src/interfaces/user-access-interfaces/user-access-requirements-interface.ts
@@ -5,4 +5,6 @@ export interface RequirementsConfigIF {
underlinedText?: string
tooltipText?: string
regularText?: string
+ bullets?: Array
+ note?: string
}
diff --git a/ppr-ui/src/resources/attnRefConfigs.ts b/ppr-ui/src/resources/attnRefConfigs.ts
index 4d7d95f35..92ab839f5 100644
--- a/ppr-ui/src/resources/attnRefConfigs.ts
+++ b/ppr-ui/src/resources/attnRefConfigs.ts
@@ -22,3 +22,11 @@ export const attentionConfigManufacturer: AttnRefConfigIF = {
' different from the Submitting Party name, add an optional name.' +
' If entered, it will appear on the cover letter from BC Registries.'
}
+
+export const attentionExemptionConfig: AttnRefConfigIF = {
+ title: 'Attention',
+ description: 'If the intended recipient of the registration verification statement and decal is different from the' +
+ ' Submitting Party name, add an optional name. If entered, it will appear on the cover letter from BC Registries.',
+ inputTitle: 'Attention',
+ inputLabel: 'Attention (Optional)'
+}
diff --git a/ppr-ui/src/resources/dialogOptions/errorDialogs.ts b/ppr-ui/src/resources/dialogOptions/errorDialogs.ts
index 9223e336b..f08de1314 100644
--- a/ppr-ui/src/resources/dialogOptions/errorDialogs.ts
+++ b/ppr-ui/src/resources/dialogOptions/errorDialogs.ts
@@ -189,3 +189,12 @@ export const unitNoteFilingError: DialogOptionsIF = {
text: 'We are unable to file Unit Note at this time. Please try again later. ' +
'If this issue persists, please contact us.'
}
+
+export const exemptionSaveError: DialogOptionsIF = {
+ acceptText: 'OK',
+ cancelText: '',
+ hasContactInfo: true,
+ title: 'Unable to save Exemption',
+ text: 'We are unable to save your Exemption at this time. ' +
+ 'Please try this again later. If this issue persists, please contact us.'
+}
diff --git a/ppr-ui/src/resources/exemptions/componentContent.ts b/ppr-ui/src/resources/exemptions/componentContent.ts
index 66286d982..e4f724e38 100644
--- a/ppr-ui/src/resources/exemptions/componentContent.ts
+++ b/ppr-ui/src/resources/exemptions/componentContent.ts
@@ -1,4 +1,4 @@
-import { ContentIF } from '@/interfaces'
+import { ContactInformationContentIF, ContentIF, RequirementsConfigIF } from '@/interfaces'
export const exDocIdContent: ContentIF = {
title: 'Document ID',
@@ -11,3 +11,127 @@ export const exRemarksContent: ContentIF = {
sideLabel: 'Add Remarks',
description: 'Remarks will be shown when a search result is produced for this manufactured home.'
}
+
+export const exConfirmRequirements: Array = [
+ {
+ boldText: 'Residential Exemption form ',
+ regularText: 'meets the following requirements:',
+ bullets: [
+ 'It has been signed by either a) the registered owner(s) (individually or by a duly authorized representative' +
+ ' of an organization), or b) person(s) with the authority to act on behalf of the registered owner(s).',
+ 'All signatures have been witnessed by an independent third party, and the name and occupation of each witness' +
+ ' has been recorded.'
+ ],
+ note: ' If the Residential Exemption form has been signed by a person acting on behalf of a registered owner, the' +
+ ' qualified supplier submitting this application must provide evidence of the authority by which the signatory' +
+ ' was authorized. Such authorization must be granted by one of the following: power of attorney, ' +
+ 'representation agreement, or committee.'
+ },
+ {
+ boldText: 'Home location and homeowner(s) named in the Manufactured Home Registry match ',
+ regularText: 'the home location and current ownership of the home on the Residential Exemption form.'
+ },
+ {
+ boldText: 'Must have one of the following ',
+ regularText: 'that shows the name of the homeowner(s) and home location and at least one of the homeowners as ' +
+ 'also being an owner of the land where the home is located:',
+ bullets: [
+ 'Land Title Search, dated within 30 days of today, or',
+ 'Pending freehold transfer'
+ ]
+ },
+ {
+ boldText: 'Legal Land Description on the Land Title Search or pending freehold transfer matches ',
+ regularText: 'the registered manufactured home location information. One or more of the following must correspond' +
+ ' and there should be no material differences in the location descriptions:',
+ bullets: [
+ 'PID,',
+ 'Lot / land district / plan number, or',
+ 'District lot / land district'
+ ]
+ },
+ {
+ boldText: 'Personal Property Registry search ',
+ regularText: 'has been completed and there are no liens that block the exemption. PPR registrations that block' +
+ ' the exemption include the following:',
+ bullets: [
+ 'Marriage/Separation Agreement Affecting Manufactured Home',
+ 'Land Tax Deferment Lien on a Manufactured Home',
+ 'Maintenance Lien',
+ 'Manufactured Home Notice',
+ 'Possession under s.30 of the Sale of Goods Act'
+ ],
+ note: 'If there is a Personal Property Security Act (PPSA) security interest registered against this manufactured' +
+ ' home, such registration has been discharged or consent to the exemption application of each secured party' +
+ ' under the security agreement has been obtained.'
+ }
+]
+
+export const exConfirmRequirementsQs: Array = [
+ {
+ boldText: 'Residential Exemption form ',
+ regularText: 'meets the following requirements:',
+ bullets: [
+ 'It has been signed by either a) the registered owner(s) (individually or by a duly authorized representative' +
+ ' of an organization), or b) person(s) with the authority to act on behalf of the registered owner(s).',
+ 'All signatures have been witnessed by an independent third party, and the name and occupation of each witness' +
+ ' has been recorded.'
+ ],
+ note: ' If the Residential Exemption form has been signed by a person acting on behalf of a registered owner, the' +
+ ' qualified supplier submitting this application must be a lawyer or notary. Unless you are a lawyer or notary,' +
+ ' you are not authorized to continue. The lawyer or notary must confirm the authority by which the signatory' +
+ ' was authorized. Such authorization must be granted by one of the following: power of attorney, representation' +
+ ' agreement, or committee.'
+ },
+ {
+ boldText: 'Home location and homeowner(s) named in the Manufactured Home Registry match ',
+ regularText: 'the home location and current ownership of the home on the Residential Exemption form.'
+ },
+ {
+ boldText: 'Must have one of the following ',
+ regularText: 'that shows the name of the homeowner(s) and home location and at least one of the homeowners as ' +
+ 'also being an owner of the land where the home is located:',
+ bullets: [
+ 'Land Title Search, dated within 30 days of today, or',
+ 'Pending freehold transfer'
+ ]
+ },
+ {
+ boldText: 'Legal Land Description on the Land Title Search or pending freehold transfer matches ',
+ regularText: 'the registered manufactured home location information. One or more of the following must correspond' +
+ ' and there should be no material differences in the location descriptions:',
+ bullets: [
+ 'PID,',
+ 'Lot / land district / plan number, or',
+ 'District lot / land district'
+ ]
+ },
+ {
+ boldText: 'Personal Property Registry search ',
+ regularText: 'has been completed and there are no liens that block the exemption. PPR registrations that block' +
+ ' the exemption include the following:',
+ bullets: [
+ 'Marriage/Separation Agreement Affecting Manufactured Home',
+ 'Land Tax Deferment Lien on a Manufactured Home',
+ 'Maintenance Lien',
+ 'Manufactured Home Notice',
+ 'Possession under s.30 of the Sale of Goods Act'
+ ],
+ note: 'If there is a Personal Property Security Act (PPSA) security interest registered against this manufactured' +
+ ' home, such registration has been discharged or consent to the exemption application of each secured party' +
+ ' under the security agreement has been obtained.'
+ },
+ {
+ boldText: 'All filed documents will be stored for 7 years. ',
+ regularText: 'If requested, a copy or certified copy of filed documents (such as the Bill of Sale, or other' +
+ ' signed forms), will be provided within 7 business days, at the fee level set by the Registrar.'
+ }
+]
+
+export const exCertifyInfoContent: ContentIF = {
+ title: 'Authorization',
+ description: `The following account information will be recorded by BC Registries upon registration and payment. This
+ information is used to confirm you have the authority to submit this registration.`,
+ sideLabel: 'Confirm Authorization',
+ mailAddressInfo: 'Test Address'
+}
diff --git a/ppr-ui/src/resources/index.ts b/ppr-ui/src/resources/index.ts
index 7663f0a20..2afd590a8 100644
--- a/ppr-ui/src/resources/index.ts
+++ b/ppr-ui/src/resources/index.ts
@@ -1,4 +1,5 @@
export * from './authorizedTableHeaders'
+export * from './attnRefConfigs'
export * from './breadcrumbs'
export * from './registrationTypes'
export * from './searchTypes'
diff --git a/ppr-ui/src/resources/transferTypes.ts b/ppr-ui/src/resources/transferTypes.ts
index 2ee249475..66279f68c 100644
--- a/ppr-ui/src/resources/transferTypes.ts
+++ b/ppr-ui/src/resources/transferTypes.ts
@@ -20,7 +20,7 @@ export const StaffTransferTypes: Array = [
group: 1,
tooltip: {
title: 'Supporting Documents Required',
- bullets: ['Transfer form', 'Bill of sale', 'Transfer fee']
+ bullets: ['Ownership Transfer or Change form', 'Bill of Sale']
}
},
{
@@ -134,7 +134,7 @@ export const QualifiedSupplierTransferTypes: Array = [
group: 1,
tooltip: {
title: 'Supporting Documents Required',
- bullets: ['Transfer form', 'Bill of sale', 'Transfer fee']
+ bullets: ['Ownership Transfer or Change form', 'Bill of Sale']
}
},
{
diff --git a/ppr-ui/src/schemas/party-form.ts b/ppr-ui/src/schemas/party-form.ts
index 207e5c5be..4eb484168 100644
--- a/ppr-ui/src/schemas/party-form.ts
+++ b/ppr-ui/src/schemas/party-form.ts
@@ -13,12 +13,23 @@ const {
} = useInputRules()
export const PartyFormSchema: PartySchemaIF = {
- firstName: firstNameRules(),
- middleName: middleNameRules,
- lastName: lastNameRules(),
- businessName: businessNameRules(),
- phone: phoneRules(),
- phoneExt: phoneExtensionRules,
- email: emailRules,
- address: PartyAddressSchema
+ firstName: { rules: firstNameRules(), optional: false },
+ middleName: { rules: middleNameRules, optional: true },
+ lastName: { rules: lastNameRules(), optional: false },
+ businessName: { rules: businessNameRules(), optional: false },
+ phone: { rules: phoneRules(), optional: false },
+ phoneExt: { rules: phoneExtensionRules, optional: true },
+ email: { rules: emailRules, optional: true },
+ address: { rules: PartyAddressSchema, optional: false }
+}
+
+export const ExemptionPartyFormSchema: PartySchemaIF = {
+ firstName: { rules: firstNameRules(), optional: false },
+ middleName: { rules: middleNameRules, optional: true },
+ lastName: { rules: lastNameRules(), optional: false },
+ businessName: { rules: businessNameRules(), optional: false },
+ phone: { rules: phoneRules(true), optional: true },
+ phoneExt: { rules: phoneExtensionRules, optional: true },
+ email: { rules: emailRules, optional: true },
+ address: { rules: PartyAddressSchema, optional: false }
}
diff --git a/ppr-ui/src/store/state/state-model.ts b/ppr-ui/src/store/state/state-model.ts
index 2777d4e6c..9f2b95424 100644
--- a/ppr-ui/src/store/state/state-model.ts
+++ b/ppr-ui/src/store/state/state-model.ts
@@ -393,6 +393,7 @@ export const stateModel: StateModelIF = {
qsSubmittingParty: null
},
mhrExemption: {
+ documentId: '',
clientReferenceId: '',
attentionReference: '',
submittingParty: {
@@ -420,6 +421,16 @@ export const stateModel: StateModelIF = {
remarks: ''
}
},
+ mhrExemptionValidation: {
+ documentId: false,
+ remarks: true,
+ submittingParty: false,
+ attention: true,
+ folio: true,
+ confirmCompletion: false,
+ authorization: false,
+ staffPayment: false
+ },
mhrUserAccessValidation: {
qsInformationValid: false,
qsSaConfirmValid: false,
diff --git a/ppr-ui/src/store/store.ts b/ppr-ui/src/store/store.ts
index b0fe093f9..f63a3fd32 100644
--- a/ppr-ui/src/store/store.ts
+++ b/ppr-ui/src/store/store.ts
@@ -46,7 +46,9 @@ import {
PartyIF,
UserAccessValidationIF,
AccountInfoIF,
- UserAccessAuthorizationIF
+ UserAccessAuthorizationIF,
+ ExemptionIF,
+ ExemptionValidationIF
} from '@/interfaces'
import {
AccountTypes,
@@ -743,7 +745,7 @@ export const useStore = defineStore('assetsStore', () => {
text: 'Verify Home Details',
to: RouteNames.EXEMPTION_DETAILS,
disabled: false,
- valid: true,
+ valid: getMhrExemptionValidation.value.documentId && getMhrExemptionValidation.value.remarks,
component: ExemptionDetails
},
{
@@ -753,14 +755,20 @@ export const useStore = defineStore('assetsStore', () => {
text: 'Review and Confirm',
to: RouteNames.EXEMPTION_REVIEW,
disabled: false,
- valid: true,
+ valid: isMhrExemptionValid.value,
component: ExemptionReview
}
]
})
- const getMhrExemption = computed(() => {
+ const getMhrExemption = computed((): ExemptionIF => {
return state.value.mhrExemption
})
+ const getMhrExemptionValidation = computed((): ExemptionValidationIF => {
+ return state.value.mhrExemptionValidation
+ })
+ const isMhrExemptionValid = computed(() => {
+ return Object.values(getMhrExemptionValidation.value).every(value => value)
+ })
/** Actions **/
function resetNewRegistration () {
@@ -1193,12 +1201,18 @@ export const useStore = defineStore('assetsStore', () => {
}
// Exemptions
- function setMhrExemption ({ key, value }) {
+ function setMhrExemption (value: ExemptionIF) {
+ state.value.mhrExemption = value
+ }
+ function setMhrExemptionValue ({ key, value }) {
state.value.mhrExemption[key] = value
}
function setMhrExemptionNote ({ key, value }) {
state.value.mhrExemption.note[key] = value
}
+ function setMhrExemptionValidation ({ key, value }) {
+ state.value.mhrExemptionValidation[key] = value
+ }
return {
// Temp feature flag getters
@@ -1380,6 +1394,8 @@ export const useStore = defineStore('assetsStore', () => {
// Exemptions
getMhrExemptionSteps,
getMhrExemption,
+ getMhrExemptionValidation,
+ isMhrExemptionValid,
// ACTIONS
@@ -1497,6 +1513,8 @@ export const useStore = defineStore('assetsStore', () => {
// Exemption
setMhrExemption,
- setMhrExemptionNote
+ setMhrExemptionValue,
+ setMhrExemptionNote,
+ setMhrExemptionValidation
}
})
diff --git a/ppr-ui/src/utils/form-helper.ts b/ppr-ui/src/utils/form-helper.ts
index a1f80aa3a..34d0cabe4 100644
--- a/ppr-ui/src/utils/form-helper.ts
+++ b/ppr-ui/src/utils/form-helper.ts
@@ -12,11 +12,31 @@ export function focusOnFirstError (formName: string): void {
}
// Scroll to first designated error on Information or Review page
-export async function scrollToFirstErrorComponent (): Promise {
+export async function scrollToFirstErrorComponent (defaultIndex: number = 0): Promise {
setTimeout(() => {
document.getElementsByClassName('border-error-left').length > 0 &&
document
- .getElementsByClassName('border-error-left')[0]
+ .getElementsByClassName('border-error-left')[defaultIndex]
.scrollIntoView({ behavior: 'smooth' })
}, 500)
}
+
+/**
+ * Scroll to first visible instance of designated error class.
+ * Useful for multiple instances of error class across different views.
+ **/
+export async function scrollToFirstVisibleErrorComponent (): Promise {
+ const errorElements = document.getElementsByClassName('border-error-left')
+ for (const [index, element] of Array.from(errorElements).entries()) {
+ if (isElementInViewport(element)) {
+ await scrollToFirstErrorComponent(index)
+ return
+ }
+ }
+}
+
+/** Returns true when the element is within the current viewport **/
+function isElementInViewport (el: any): boolean {
+ const rect = el.getBoundingClientRect()
+ return (rect.top !== 0 && rect.left !== 0 && rect.bottom !== 0 && rect.right !== 0)
+}
diff --git a/ppr-ui/src/utils/mhr-api-helper.ts b/ppr-ui/src/utils/mhr-api-helper.ts
index 4f40f96ca..fb71b0d60 100644
--- a/ppr-ui/src/utils/mhr-api-helper.ts
+++ b/ppr-ui/src/utils/mhr-api-helper.ts
@@ -13,7 +13,7 @@ import {
RegistrationSortIF,
MhrDraftIF,
MhrManufacturerInfoIF,
- MhrQsPayloadIF
+ MhrQsPayloadIF, ExemptionIF, ErrorDetailIF
} from '@/interfaces'
import { APIMhrTypes, ErrorCategories, ErrorCodes } from '@/enums'
import { useSearch } from '@/composables/useSearch'
@@ -788,7 +788,7 @@ export async function updateQualifiedSupplier (payload: MhrQsPayloadIF): Promise
})
}
-// Get pdf for a Qualified Supplier Service Agreement
+/** Get pdf for a Qualified Supplier Service Agreement **/
export async function getQsServiceAgreements (): Promise {
const url = sessionStorage.getItem('MHR_API_URL')
const config = {
@@ -814,3 +814,42 @@ export async function getQsServiceAgreements (): Promise {
}
})
}
+
+/**
+ * Submit Exemption filing request
+ * @param payload The request payload containing the exemption information
+ * @param mhrNumber The specified Mhr number
+ * @param staffPayment The staff payment data
+ */
+// Function Definition
+export async function createExemption (
+ payload: ExemptionIF,
+ mhrNumber: string,
+ staffPayment: StaffPaymentIF
+): Promise {
+ try {
+ const paymentParams = `?${mhrStaffPaymentParameters(staffPayment)}`
+
+ const response = await axios.post(
+ `exemptions/${mhrNumber}${paymentParams}`,
+ payload,
+ getDefaultConfig()
+ )
+
+ // Ensure response data exists
+ if (!response.data) {
+ throw new Error('Invalid API response')
+ }
+
+ // Return exemption data
+ return response.data
+ } catch (error: AxiosError | any) {
+ // If an error occurs, return an ErrorIF object
+ return {
+ error: {
+ category: ErrorCategories.EXEMPTION_SAVE,
+ statusCode: error?.response?.status || StatusCodes.NOT_FOUND
+ }
+ }
+ }
+}
diff --git a/ppr-ui/src/utils/submitting-party-helper.ts b/ppr-ui/src/utils/submitting-party-helper.ts
index 485e0e9ad..1a1975fa1 100644
--- a/ppr-ui/src/utils/submitting-party-helper.ts
+++ b/ppr-ui/src/utils/submitting-party-helper.ts
@@ -1,4 +1,4 @@
-import { AccountInfoIF, SubmittingPartyIF } from '@/interfaces'
+import { AccountInfoIF, PartyIF, SubmittingPartyIF } from '@/interfaces'
export const parseAccountToSubmittingParty = (accountInfo: AccountInfoIF): SubmittingPartyIF => {
return {
@@ -9,3 +9,18 @@ export const parseAccountToSubmittingParty = (accountInfo: AccountInfoIF): Submi
phoneExtension: accountInfo.accountAdmin.phoneExtension
}
}
+export const parseSubmittingPartyToAccountInfo = (party: PartyIF): AccountInfoIF => {
+ return {
+ name: party.businessName,
+ mailingAddress: party.address,
+ id: null,
+ isBusinessAccount: !!party.businessName,
+ accountAdmin: {
+ firstName: party.personName?.first,
+ lastName: party.personName?.last,
+ email: party.emailAddress,
+ phone: party.phoneNumber,
+ phoneExtension: party.phoneExtension
+ }
+ }
+}
diff --git a/ppr-ui/src/views/exemption/ExemptionDetails.vue b/ppr-ui/src/views/exemption/ExemptionDetails.vue
index 4641473d1..3be480493 100644
--- a/ppr-ui/src/views/exemption/ExemptionDetails.vue
+++ b/ppr-ui/src/views/exemption/ExemptionDetails.vue
@@ -10,8 +10,8 @@
@@ -64,7 +64,10 @@
@@ -72,13 +75,15 @@