Skip to content

Commit

Permalink
Fix Multiple Issues with Home Owner Groups (#1575)
Browse files Browse the repository at this point in the history
* Update error message in Home Owners table
* Fix error for Individual & Business home owners. Add test.
* Update validation for Home Owner groups. Add tests.
* Update validation as per UXA
  • Loading branch information
dimak1 authored Oct 10, 2023
1 parent 07af978 commit f6b8be5
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 67 deletions.
4 changes: 2 additions & 2 deletions ppr-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ppr-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ppr-ui",
"version": "2.1.14",
"version": "2.1.15",
"private": true,
"appName": "Assets UI",
"sbcName": "SBC Common Components",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,8 @@ export default defineComponent({
isTransferToExecutorUnder25Will.value ||
isTransferDueToSaleOrGift.value ||
isTransferToAdminNoWill.value) {
return props.validateTransfer && props.isMhrTransfer && !hasUnsavedChanges.value
return (props.validateTransfer && props.isMhrTransfer && !hasUnsavedChanges.value) ||
(props.validateTransfer && !localState.isValidAllocation)
}
return ((props.validateTransfer || (!props.isMhrTransfer && localState.reviewedOwners)) &&
Expand Down Expand Up @@ -624,9 +625,13 @@ export default defineComponent({
// check if Owner Group that has deceased Owners is valid
const isInvalidOwnerGroup = (groupId: number): boolean => {
if (!props.isMhrTransfer) return isInvalidRegistrationOwnerGroup(groupId)
if (!props.validateTransfer) return false
// check mixed owners in for all transfer types
if (TransSaleOrGift.hasMixedOwnersInGroup(groupId)) return true
// do not show group error is there is a table error for invalid ownership allocation
if (!props.validateTransfer || !localState.isValidAllocation) return false
// check if group is not valid due to mixed owners or all removed owners
if (TransSaleOrGift.hasMixedOwnersInGroup(groupId) ||
TransSaleOrGift.hasAllCurrentOwnersRemoved(groupId)) return true
if ((isTransferToExecutorProbateWill.value ||
isTransferToExecutorUnder25Will.value ||
Expand Down
15 changes: 14 additions & 1 deletion ppr-ui/src/composables/mhrInformation/useTransferOwners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ export const useTransferOwners = (enableAllActions: boolean = false) => {
const ownerTypes: HomeOwnerPartyTypes[] = getMhrTransferHomeOwnerGroups.value
.find(group => group.groupId === groupId).owners
.filter(owner => owner.action !== ActionTypes.REMOVED)
.map(owner => owner.partyType)
.map(owner =>
// workaround to treat IND and BUS owners the same (not unique roles)
owner.partyType === HomeOwnerPartyTypes.OWNER_BUS ? HomeOwnerPartyTypes.OWNER_IND : owner.partyType)
return ownerTypes.length === 1 ? false : uniq(ownerTypes).length > 1
},
hasPartlyRemovedEATOwners: (groupId: number): boolean => {
Expand All @@ -340,6 +342,17 @@ export const useTransferOwners = (enableAllActions: boolean = false) => {
const hasSomeNotDeleted: boolean = ownerTypes.filter(owner => owner.action !== ActionTypes.REMOVED).length >= 1

return hasOneDeleted && hasSomeNotDeleted
},
hasAllCurrentOwnersRemoved: (groupId): boolean => {
const regOwners = getMhrTransferHomeOwnerGroups.value
.find(group => group.groupId === groupId).owners

if (regOwners?.length === 0) return true

return regOwners
.every(owner => isCurrentOwner(owner)
? owner.action === ActionTypes.REMOVED
: owner.action === ActionTypes.ADDED)
}
}

Expand Down
5 changes: 4 additions & 1 deletion ppr-ui/src/views/newMhrRegistration/HomeOwners.vue
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
<v-col
v-show="showTotalOwnership"
cols="12"
data-test-id="ownership-allocation"
>
<!-- Ownership Allocation Information -->
<span class="generic-label">Total Ownership Allocated:</span> {{ ownershipTotalAllocation }}
Expand All @@ -195,7 +196,9 @@
</span>
</v-col>
<v-col v-if="changesRequired" class="mt-3">
<span class="error-text fs-14">Change of ownership is required</span>
<span class="error-text fs-14" data-test-id="structure-change-required">
Change of the ownership structure is required
</span>
</v-col>
</v-row>

Expand Down
246 changes: 188 additions & 58 deletions ppr-ui/tests/unit/MhrTransferHomeOwners.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
} from '@/enums'
import { DeathCertificate, SupportingDocuments } from '@/components/mhrTransfers'
import { transferSupportingDocuments, transfersErrors, MixedRolesErrors } from '@/resources'
import { useNewMhrRegistration } from '@/composables'

Vue.use(Vuetify)

Expand Down Expand Up @@ -89,6 +90,7 @@ describe('Home Owners', () => {
})
afterEach(() => {
wrapper.destroy()
store.setEmptyMhr(useNewMhrRegistration().initNewMhr())
})

// Helper functions
Expand Down Expand Up @@ -531,6 +533,192 @@ describe('Home Owners', () => {
expect(ownersTable.findAll(getTestId('table-delete-btn'))).toHaveLength(0)
})

it('TRANS SALE: should not show errors for owners types (Individual & Business) in the table', async () => {
const homeOwnerGroup: MhrRegistrationHomeOwnerGroupIF[] = [
{ groupId: 1, owners: [mockedPerson, mockedPerson2, mockedOrganization], type: '' }
]

await store.setMhrTransferCurrentHomeOwnerGroups(homeOwnerGroup)
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)
await selectTransferType(ApiTransferTypes.SALE_OR_GIFT)

const homeOwners: Wrapper<any> = wrapper

// make sure there are no errors
expect(homeOwners.find(getTestId('invalid-group-msg')).exists()).toBeFalsy()
expect(homeOwners.find(getTestId('no-data-msg')).exists()).toBeFalsy()
expect(homeOwners.find(getTestId('structure-change-required')).exists()).toBeFalsy()
expect(homeOwners.find('border-error-left').exists()).toBeFalsy()

// make sure validation is not triggered yet
expect(homeOwners.vm.validateTransfer).toBe(false)
await homeOwners.setProps({ validateTransfer: true })
await Vue.nextTick()

// make sure page validation is triggered
expect(homeOwners.vm.validateTransfer).toBe(true)

// table errors are showing
expect(homeOwners.find(getTestId('structure-change-required')).exists()).toBeTruthy()
expect(homeOwners.find('#home-owner-table-card.border-error-left').exists()).toBeTruthy()

// home owner row errors are not showing
expect(homeOwners.find(getTestId('invalid-group-msg')).exists()).toBeFalsy()
expect(homeOwners.find('.owner-name.border-error-left').exists()).toBeFalsy()
})

it('TRANS SALE: validations for mixed owners roles (Exec, Admin, Trustee) in the table', async () => {
// reset transfer type
await selectTransferType(null)

await selectTransferType(ApiTransferTypes.SALE_OR_GIFT)

const homeOwnerGroup: MhrRegistrationHomeOwnerGroupIF[] = [
{
groupId: 1,
owners: [
{
...mockedExecutor,
id: '1',
partyType: HomeOwnerPartyTypes.EXECUTOR
} as MhrRegistrationHomeOwnerIF,
{
...mockedPerson,
id: '2',
partyType: HomeOwnerPartyTypes.OWNER_IND,
action: ActionTypes.ADDED
} as MhrRegistrationHomeOwnerIF
],
type: ''
}
]
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

const homeOwners = wrapper
const groupError = homeOwners.find(getTestId('invalid-group-msg'))

expect(groupError.text()).toContain(MixedRolesErrors.hasMixedOwnerTypes)

// add one more owner to the second group to trigger a new error message
homeOwnerGroup.push({
groupId: 2,
owners: [mockedPerson],
type: ''
} as MhrRegistrationHomeOwnerGroupIF)

await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

expect(groupError.text()).toContain(MixedRolesErrors.hasMixedOwnerTypesInGroup)

// change transfer type and check for mixed owners again
await selectTransferType(ApiTransferTypes.TO_EXECUTOR_PROBATE_WILL)
homeOwnerGroup.pop()
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

expect(wrapper.vm.getHomeOwners.length).toBe(2)
expect(homeOwners.find(getTestId('invalid-group-msg')).text()).toContain(MixedRolesErrors.hasMixedOwnerTypes)

// change transfer type and check for mixed owners again
await selectTransferType(ApiTransferTypes.TO_EXECUTOR_UNDER_25K_WILL)
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

expect(homeOwners.find(getTestId('invalid-group-msg')).text()).toContain(MixedRolesErrors.hasMixedOwnerTypes)
})

it('TRANS SALE: validations for under allocated group ownership interest', async () => {
// under allocated groups
const homeOwnerGroups: MhrRegistrationHomeOwnerGroupIF[] = [
{
groupId: 1,
interest: 'Undivided',
interestNumerator: 1,
interestDenominator: 4,
owners: [mockedPerson],
type: ''
},
{
groupId: 2,
interest: 'Undivided',
interestNumerator: 2,
interestDenominator: 4,
owners: [mockedPerson2],
type: ''
}
]

await store.setMhrTransferCurrentHomeOwnerGroups(homeOwnerGroups)
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroups)

await selectTransferType(ApiTransferTypes.SALE_OR_GIFT)
wrapper.vm.setShowGroups(true)
await Vue.nextTick()

const homeOwners: Wrapper<any> = wrapper

// check ownership allocation info has error and error is showing
const ownershipAllocation = homeOwners.find(getTestId('ownership-allocation'))
expect(ownershipAllocation.exists()).toBeTruthy()
expect(ownershipAllocation.text()).toContain('3/4')
expect(ownershipAllocation.text()).toContain('Total ownership interest is under allocated')
// table error should not show because page validation is not triggered (Review and Confirm button was not clicked)
expect(homeOwners.find('#home-owner-table-card.border-error-left').exists()).toBe(false)

// trigger page validation
await wrapper.setProps({ validateTransfer: true })
expect(homeOwners.find('#home-owner-table-card.border-error-left').exists()).toBe(true)

// update group to be fully allocated
homeOwnerGroups[0].interestNumerator = 2

await store.setMhrTransferHomeOwnerGroups(homeOwnerGroups)
await Vue.nextTick()

// check ownership allocation info is fully allocated and error not showing
expect(homeOwners.find(getTestId('ownership-allocation')).text()).toContain('Fully Allocated')
expect(homeOwners.find('#home-owner-table-card.border-error-left').exists()).toBe(false)
})

it('TRANS SALE: validations when group has all owners deleted', async () => {
const homeOwnerGroup: MhrRegistrationHomeOwnerGroupIF[] = [
{
groupId: 1,
interest: 'Undivided',
interestNumerator: 4,
interestDenominator: 4,
owners: [mockedRemovedPerson, mockedRemovedOrganization],
type: ''
}
]

await store.setMhrTransferCurrentHomeOwnerGroups(homeOwnerGroup)
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

await selectTransferType(ApiTransferTypes.SALE_OR_GIFT)
wrapper.vm.setShowGroups(true)
await wrapper.setProps({ validateTransfer: true })

await Vue.nextTick()

const homeOwners: Wrapper<any> = wrapper

// check ownership allocation info has no errors
expect(homeOwners.find(getTestId('ownership-allocation')).text()).toContain('Fully Allocated')

// does not have table error
expect(homeOwners.find('#home-owner-table-card.border-error-left').exists()).toBe(false)

expect(homeOwners.find(getTestId('invalid-group-msg')).text())
.toBe('Group must contain at least one owner.')

expect(homeOwners.findAll(getTestId('DELETED-badge'))).toHaveLength(2)

// has border errors for the group (rows: header, error, owner one, owner two)
expect(homeOwners.find('.group-header-slot.border-error-left').exists()).toBeTruthy()
expect(homeOwners.find(getTestId('invalid-group-msg')).classes('border-error-left')).toBeTruthy()
expect(homeOwners.find(getTestId('owner-info-10')).find('.owner-name').classes('border-error-left')).toBeTruthy()
expect(homeOwners.find(getTestId('owner-info-20')).find('.owner-name').classes('border-error-left')).toBeTruthy()
})

it('TRANS WILL: display Supporting Document component for deleted sole Owner and add Executor', async () => {
// reset transfer type
await selectTransferType(null)
Expand Down Expand Up @@ -677,64 +865,6 @@ describe('Home Owners', () => {
).toBe(HomeTenancyTypes.NA)
})

it('TRANS: validations for mixed owners types in the table', async () => {
// reset transfer type
await selectTransferType(null)

await selectTransferType(ApiTransferTypes.SALE_OR_GIFT)

const homeOwnerGroup: MhrRegistrationHomeOwnerGroupIF[] = [
{
groupId: 1,
owners: [
{
...mockedExecutor,
id: '1',
partyType: HomeOwnerPartyTypes.EXECUTOR
} as MhrRegistrationHomeOwnerIF,
{
...mockedPerson,
id: '2',
partyType: HomeOwnerPartyTypes.OWNER_IND,
action: ActionTypes.ADDED
} as MhrRegistrationHomeOwnerIF
],
type: ''
}
]
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

const homeOwners = wrapper
const groupError = homeOwners.find(getTestId('invalid-group-msg'))

expect(groupError.text()).toContain(MixedRolesErrors.hasMixedOwnerTypes)

// add one more owner to the second group to trigger a new error message
homeOwnerGroup.push({
groupId: 2,
owners: [mockedPerson],
type: ''
} as MhrRegistrationHomeOwnerGroupIF)

await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

expect(groupError.text()).toContain(MixedRolesErrors.hasMixedOwnerTypesInGroup)

// change transfer type and check for mixed owners again
await selectTransferType(ApiTransferTypes.TO_EXECUTOR_PROBATE_WILL)
homeOwnerGroup.pop()
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

expect(wrapper.vm.getHomeOwners.length).toBe(2)
expect(homeOwners.find(getTestId('invalid-group-msg')).text()).toContain(MixedRolesErrors.hasMixedOwnerTypes)

// change transfer type and check for mixed owners again
await selectTransferType(ApiTransferTypes.TO_EXECUTOR_UNDER_25K_WILL)
await store.setMhrTransferHomeOwnerGroups(homeOwnerGroup)

expect(homeOwners.find(getTestId('invalid-group-msg')).text()).toContain(MixedRolesErrors.hasMixedOwnerTypes)
})

it('TRANS WILL: validations with sole Owner in one group', async () => {
// reset transfer type
await selectTransferType(null)
Expand Down

0 comments on commit f6b8be5

Please sign in to comment.