diff --git a/ppr-ui/src/components/tables/common/TableRow.vue b/ppr-ui/src/components/tables/common/TableRow.vue index b2616702b..4efdc8e34 100644 --- a/ppr-ui/src/components/tables/common/TableRow.vue +++ b/ppr-ui/src/components/tables/common/TableRow.vue @@ -387,9 +387,19 @@ + + exemption-icon + Rescind Exemption Order + + + exemption-icon @@ -400,13 +410,17 @@ v-if="isRoleStaffReg && isExemptionEnabled && ![HomeLocationTypes.HOME_PARK, HomeLocationTypes.LOT].includes(item.locationType)" @click="openExemption(UnitNoteDocTypes.NON_RESIDENTIAL_EXEMPTION, item)" + data-test-id="non-res-exemption-btn" > exemption-icon Non-Residential Exemption - + mdi-delete Remove From Table @@ -530,7 +544,7 @@ export default defineComponent({ securedParties } = useRegistration(null) const { isTransAffi } = useTransferOwners() - const { isExemptionEnabled } = useExemptions() + const { isExemptionEnabled, hasChildResExemption } = useExemptions() const localState = reactive({ loadingPDF: '', @@ -651,7 +665,8 @@ export default defineComponent({ } const isEnabledMhr = (item: MhRegistrationSummaryIF) => { - return [MhApiStatusTypes.ACTIVE, MhApiStatusTypes.FROZEN].includes(item.statusType as MhApiStatusTypes) && + return [MhApiStatusTypes.ACTIVE, MhApiStatusTypes.FROZEN, MhApiStatusTypes.EXEMPT] + .includes(item.statusType as MhApiStatusTypes) && localState.enableOpenEdit && (item.registrationDescription === APIMhrDescriptionTypes.REGISTER_NEW_UNIT || item.registrationDescription === APIMhrDescriptionTypes.CONVERTED) } @@ -887,6 +902,7 @@ export default defineComponent({ isRepairersLienAmendDisabled, isRoleStaffReg, isExemptionEnabled, + hasChildResExemption, hasRenewal, downloadPDF, inSelectedHeaders, diff --git a/ppr-ui/src/composables/exemption/useExemptions.ts b/ppr-ui/src/composables/exemption/useExemptions.ts index 9dcaf442a..8698ba0e1 100644 --- a/ppr-ui/src/composables/exemption/useExemptions.ts +++ b/ppr-ui/src/composables/exemption/useExemptions.ts @@ -2,7 +2,6 @@ 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 { cleanEmpty, fromDisplayPhone, @@ -11,7 +10,8 @@ import { hasTruthyValue, parseAccountToSubmittingParty } from '@/utils' -import { ExemptionIF } from '@/interfaces' +import { ExemptionIF, MhRegistrationSummaryIF } from '@/interfaces' +import { APIMhrDescriptionTypes, MhApiStatusTypes, RouteNames, UnitNoteDocTypes } from '@/enums' export const useExemptions = () => { const { goToRoute } = useNavigation() @@ -95,10 +95,20 @@ export const useExemptions = () => { } } + /** Check is MHR Registration has filed Residential Exemption **/ + const hasChildResExemption = (mhrRegSummary: MhRegistrationSummaryIF): boolean => { + return mhrRegSummary.changes?.filter( + reg => + reg.registrationDescription === APIMhrDescriptionTypes.RESIDENTIAL_EXEMPTION && + reg.statusType === MhApiStatusTypes.EXEMPT + ).length > 0 + } + return { isExemptionEnabled, goToExemptions, updateValidation, - buildExemptionPayload + buildExemptionPayload, + hasChildResExemption } } diff --git a/ppr-ui/src/composables/useRegistration.ts b/ppr-ui/src/composables/useRegistration.ts index 707b71dac..ad1f6e35e 100644 --- a/ppr-ui/src/composables/useRegistration.ts +++ b/ppr-ui/src/composables/useRegistration.ts @@ -46,6 +46,7 @@ export const useRegistration = (setSort: RegistrationSortIF) => { isChild: boolean, isPpr: boolean): string => { if (!status) return UIStatusTypes.DRAFT if (status === MhApiStatusTypes.FROZEN) return MhUIStatusTypes.ACTIVE + if (!isChild && status === MhApiStatusTypes.EXEMPT) return MhUIStatusTypes.EXEMPT if (isChild && (status === MhApiStatusTypes.CANCELLED || status === MhApiStatusTypes.EXEMPT)) return '' return isPpr ? PprAPIToUIStatusTypesMap[status] : MhrAPIToUIStatusTypesMap[status] } diff --git a/ppr-ui/src/enums/registrationTypes.ts b/ppr-ui/src/enums/registrationTypes.ts index e24122464..3e89a9c6d 100644 --- a/ppr-ui/src/enums/registrationTypes.ts +++ b/ppr-ui/src/enums/registrationTypes.ts @@ -174,6 +174,7 @@ export enum APIMhrDescriptionTypes { TRANSFER_EXECUTOR_PROBATE_WILL = 'TRANSFER TO EXECUTOR \u2013 GRANT OF PROBATE WITH WILL', TRANSFER_EXECUTOR_UNDER_25_WILL = 'TRANSFER TO EXECUTOR \u2013 ESTATE UNDER $25,000 WITH WILL', TRANSFER_ADMINISTRATOR = 'TRANSFER TO ADMINISTRATOR \u2013 GRANT OF ADMINISTRATION', + RESIDENTIAL_EXEMPTION = 'RESIDENTIAL EXEMPTION' } export enum UIMhrDescriptionTypes { diff --git a/ppr-ui/src/store/store.ts b/ppr-ui/src/store/store.ts index f63a3fd32..7ca13a721 100644 --- a/ppr-ui/src/store/store.ts +++ b/ppr-ui/src/store/store.ts @@ -126,13 +126,13 @@ export const useStore = defineStore('assetsStore', () => { return state.value.accountInformation?.id }) const isRoleStaffBcol = computed((): boolean => { - return state.value.authorization?.authRoles.includes('helpdesk') + return state.value.authorization?.authRoles.includes(AuthRoles.HELPDESK) }) const isPremiumAccount = computed((): boolean => { return (state.value.accountInformation?.accountType === AccountTypes.PREMIUM) }) const isRoleStaffReg = computed((): boolean => { - return state.value.authorization?.authRoles.includes('ppr_staff') + return state.value.authorization?.authRoles.includes(AuthRoles.PPR_STAFF) }) /** Whether the user has one of the approved 'qualified supplier' product subscriptions. */ const isRoleQualifiedSupplier = computed((): boolean => { diff --git a/ppr-ui/tests/unit/TableRow.spec.ts b/ppr-ui/tests/unit/TableRow.spec.ts index 9184300f7..f6f5fd81f 100644 --- a/ppr-ui/tests/unit/TableRow.spec.ts +++ b/ppr-ui/tests/unit/TableRow.spec.ts @@ -26,8 +26,11 @@ import { mockedMhRegistration, mockedMhDraft, mockedLockedMhRegistration, - mockedMhRegistrationWithCancelNote + mockedMhRegistrationWithCancelNote, + mockedResidentialExemptionMhRegistration, + mockedManufacturerAuthRoles } from './test-data' +import { defaultFlagSet } from '@/utils/feature-flags' Vue.use(Vuetify) @@ -411,7 +414,7 @@ describe('Mhr TableRow tests', () => { expect(wrapper.vm.applyAddedRegEffect).toBe(false) expect(wrapper.findAll(applyAddedRegEffect).length).toBe(0) - // check things specific to state / heirarchy of the item + // check things specific to state / hierarchy of the item if (!draftReg.type) { // not a draft let rowData: WrapperArray @@ -616,7 +619,52 @@ describe('Mhr TableRow tests', () => { } }) - it('correctly displays a cancelnote', async () => { + it('should displays correct dropdown options for Exempt MHR (Staff and Qualified Supplier)', async () => { + await store.setAuthRoles([AuthRoles.PPR_STAFF]) + defaultFlagSet['mhr-exemption-enabled'] = true + + const registration: MhRegistrationSummaryIF = mockedResidentialExemptionMhRegistration + + await wrapper.setProps({ + setItem: registration, + setChild: false + }) + + expect(wrapper.vm.item).toEqual(registration) + + const rowData = wrapper.findAll(tableRow + ' td') + + expect(rowData.at(3).text()).toContain(MhUIStatusTypes.EXEMPT) // Status column data + expect(rowData.at(rowData.length - 1).text()).toContain('Open') + + wrapper.find('.actions__more-actions__btn').trigger('click') + await nextTick() + + const staffMenuItems = wrapper.find('.registration-actions') + + expect(staffMenuItems.findAll('.v-list-item').length).toBe(3) + expect(staffMenuItems.find(getTestId('rescind-exemption-btn')).exists()).toBeTruthy() + expect(staffMenuItems.find(getTestId('res-exemption-btn')).exists()).toBeFalsy() // res exemption already filed + expect(staffMenuItems.find(getTestId('non-res-exemption-btn')).exists()).toBeTruthy() + expect(staffMenuItems.find(getTestId('remove-mhr-row-btn')).exists()).toBeTruthy() + + // Change role to Qualified Supplier + await store.setAuthRoles(mockedManufacturerAuthRoles) + await store.setUserProductSubscriptionsCodes([ProductCode.MHR, ProductCode.MANUFACTURER]) + await nextTick() + + wrapper.find('.actions__more-actions__btn').trigger('click') + await nextTick() + + const qsMenuItems = wrapper.find('.registration-actions') + expect(qsMenuItems.findAll('.v-list-item').length).toBe(1) + expect(qsMenuItems.find(getTestId('rescind-exemption-btn')).exists()).toBeFalsy() // staff only + expect(qsMenuItems.find(getTestId('res-exemption-btn')).exists()).toBeFalsy() // res exemption already filed + expect(qsMenuItems.find(getTestId('non-res-exemption-btn')).exists()).toBeFalsy() // staff only + expect(qsMenuItems.find(getTestId('remove-mhr-row-btn')).exists()).toBeTruthy() + }) + + it('correctly displays a cancel note', async () => { const cancelNote = mockedMhRegistrationWithCancelNote.changes .find(change => change.registrationDescription === 'CANCEL NOTE') diff --git a/ppr-ui/tests/unit/test-data/mock-registration-responses.ts b/ppr-ui/tests/unit/test-data/mock-registration-responses.ts index c87fb9b0c..f19033ca3 100644 --- a/ppr-ui/tests/unit/test-data/mock-registration-responses.ts +++ b/ppr-ui/tests/unit/test-data/mock-registration-responses.ts @@ -185,6 +185,37 @@ export const mockedLockedMhRegistration: MhRegistrationSummaryIF = { expand: true } +export const mockedResidentialExemptionMhRegistration: MhRegistrationSummaryIF = { + changes: [ + { + clientReferenceId: 'UT-NCAN-002', + createDateTime: '2023-07-12T14:11:59-07:00', + documentId: '63285826', + documentRegistrationNumber: '00501476', + mhrNumber: '107714', + ownerNames: 'INTERNATIONAL STARTECK INDUSTRIES LTD.', + path: '/path/to/doc', + registrationDescription: APIMhrDescriptionTypes.RESIDENTIAL_EXEMPTION, + registrationType: APIMhrTypes.RESIDENTIAL_EXEMPTION, + statusType: MhApiStatusTypes.EXEMPT, + submittingParty: 'ABC SEARCHING COMPANY', + username: 'Staff account' + } as MhRegistrationSummaryIF + ], + mhrNumber: '123456', + ownerNames: 'John Smith', + clientReferenceId: 'ABC123', + createDateTime: '2023-07-20T17:21:17+00:00', + path: '/path/to/doc', + username: 'John Smith', + submittingParty: 'EATON CREDIT OFFICE', + registrationDescription: APIMhrDescriptionTypes.REGISTER_NEW_UNIT, + documentRegistrationNumber: 'GOV2343', + registrationType: APIMhrTypes.MANUFACTURED_HOME_REGISTRATION, + statusType: MhApiStatusTypes.EXEMPT, + expand: true +} + export const mockedMhDraft: MhrDraftIF = { lastUpdateDateTime: '2021-08-03T17:21:17+00:00', type: APIMhrTypes.MANUFACTURED_HOME_REGISTRATION,