Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

17573/17467: Support for Manufacturer and HomeDealer QS Applicant Reviews #2687

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions auth-web/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 auth-web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "auth-web",
"version": "2.4.57",
"version": "2.4.58",
"appName": "Auth Web",
"sbcName": "SBC Common Components",
"private": true,
Expand Down
165 changes: 119 additions & 46 deletions auth-web/src/components/auth/staff/review-task/QsApplication.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,46 +24,76 @@
</v-row>

<!-- QS Applicant Info -->
<v-row>
<v-col class="cols-12 mt-5 py-2">
<h3>Qualified Supplier ({{ qsApplicationTypeDisplay }}) Information</h3>
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 col-sm-3 py-2 pr-2">
Qualified Supplier Name
</v-col>
<v-col
class="py-2"
data-test="qs-org-name"
>
{{ qsApplicantData && qsApplicantData.businessName }}
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 col-sm-3 py-2">
Phone Number
</v-col>
<v-col
class="py-2"
data-test="qs-phone"
<template v-if="qsApplicantData">
<v-row>
<v-col class="cols-12 mt-5 py-2">
<h3>Qualified Supplier ({{ qsApplicationTypeDisplay }}) Information</h3>
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 col-sm-3 py-2 pr-2">
Qualified Supplier Name
</v-col>
<v-col
class="py-2"
data-test="qs-org-name"
>
{{ qsApplicantData.businessName }}
</v-col>
</v-row>
<v-row v-if="!isLawyerNotaryApplication">
<v-col class="cols-12 col-sm-3 py-2 pr-2">
DBA / Operating Name
</v-col>
<v-col
class="py-2"
data-test="qs-dba-name"
>
{{ qsApplicantData.dbaName || '(Not Entered)' }}
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 col-sm-3 py-2">
Phone Number
</v-col>
<v-col
class="py-2"
data-test="qs-phone"
>
{{ qsApplicantPhone }}
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 col-sm-3 py-2">
Mailing Address
</v-col>
<v-col class="py-2">
<BaseAddressForm
v-if="qsApplicantData"
:schema="null"
:editing="false"
:address="formatAddress(qsApplicantData.address)"
/>
</v-col>
</v-row>
<v-row
v-if="isManufacturerApplication"
data-test="qs-mf-location-row"
>
{{ qsApplicantData && qsApplicantPhone }}
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 col-sm-3 py-2">
Mailing Address
</v-col>
<v-col class="py-2">
<BaseAddressForm
v-if="qsApplicantData"
:schema="null"
:editing="false"
:address="formatAddress(qsApplicantData.address)"
/>
</v-col>
</v-row>
<v-col class="cols-12 col-sm-3 py-2">
Location of the Manufactured Home(s)
</v-col>
<v-col class="py-2">
<BaseAddressForm
v-if="qsApplicantData.mfLocation"
:schema="null"
:editing="false"
:address="formatAddress(qsApplicantData.mfLocation)"
data-test="qs-mf-location"
/>
</v-col>
</v-row>
</template>

<!-- Submitting Party Info -->
<v-row>
Expand Down Expand Up @@ -147,7 +177,7 @@
</v-col>
</v-row>
<v-row>
<v-col class="cols-12 py-2 icon-text">
<v-col class="cols-12 py-0 icon-text">
<v-icon
class="pr-2"
color="success"
Expand All @@ -166,8 +196,10 @@
</v-row>
<v-row>
<v-col class="py-2">
Legal name of the person authorized to complete and submit this application. <b>Note:</b> The authorized person
must be an active B.C. lawyer or notary in good standing.
Legal name of the person authorized to complete and submit this application.
<span v-if="isLawyerNotaryApplication">
<b>Note:</b> The authorized person must be an active B.C. lawyer or notary in good standing.
</span>
</v-col>
</v-row>
<v-row>
Expand Down Expand Up @@ -199,7 +231,11 @@
</template>

<script lang="ts">
import { QualifiedSupplierApplicant, QualifiedSupplierRequirementsConfig } from '@/models/external'
import {
MhrManufacturerInfoIF,
QualifiedSupplierApplicant,
QualifiedSupplierRequirementsConfig
} from '@/models/external'
import { computed, defineComponent, onMounted, reactive, toRefs } from '@vue/composition-api'
import { userAccessDisplayNames, userAccessRequirements } from '@/resources/QualifiedSupplierAccessResource'
import { Address } from '@/models/address'
Expand All @@ -209,6 +245,7 @@ import { Contact } from '@/models/contact'
import { Organization } from '@/models/Organization'
import { Task } from '@/models/Task'
import TaskService from '@/services/task.services'
import { TaskType } from '@/util/constants'
import { User } from '@/models/user'
import moment from 'moment/moment'

Expand Down Expand Up @@ -236,22 +273,58 @@ export default defineComponent({
}),
qsRequirements: computed((): QualifiedSupplierRequirementsConfig[] => {
return userAccessRequirements[props.taskDetails?.type]
})
}),
isLawyerNotaryApplication: computed((): boolean => props.taskDetails?.type === TaskType.MHR_LAWYER_NOTARY),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, I wonder what's the difference between this and
computed<boolean>(()=> props.taskDetails?.type === TaskType.MHR_LAWYER_NOTARY)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure!
It may be a case of either or. Both seem to do the trick.

Do you have a preference? I wonder if one is preferred in a more strict typing scenario 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either works I think, any feature flags or timing this needs to be released at? or can we just merge and push to prod anytime?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No feature flags required for this one!

Support to create these Qualified Supplier applications lives on our end and is flagged/unreleased.
This code can go anytime that works for Relationships release schedule 👍

isManufacturerApplication: computed((): boolean => props.taskDetails?.type === TaskType.MHR_MANUFACTURERS)
})

/**
* Converts manufacturer data to a qualified supplier applicant.
* @param {MhrManufacturerInfoIF} mfData - The manufacturer data to convert.
* @returns {QualifiedSupplierApplicant} The converted qualified supplier applicant.
*/
const formatManufacturer = (mfData: MhrManufacturerInfoIF): QualifiedSupplierApplicant => {
// Always 1 group with 1 owner in Manufacturer Owner record
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this

const mfOwner = mfData.ownerGroups[0].owners[0]
return {
address: mfOwner.address,
authorizationName: mfData.authorizationName,
businessName: mfOwner.organizationName,
dbaName: mfData.dbaName,
phoneNumber: mfOwner.phoneNumber,
termsAccepted: mfData.termsAccepted,
mfLocation: mfData.location.address
}
}

/** On Mount: Fetch and parse Qualified Supplier applicant into local model. */
onMounted(async () => {
await TaskService.getQsApplicantForTaskReview(props.accountUnderReview.id).then(response => {
// Fetch Qualified Suppler application data
await TaskService.getQsApplicantForTaskReview(props.accountUnderReview.id, props.taskDetails?.type).then(response => {
if (!response?.data) {
throw new Error('Invalid API response')
}
localState.qsApplicantData = response.data
// Format response to fit QS model when Manufacturer
localState.qsApplicantData = localState.isManufacturerApplication
? formatManufacturer(response.data)
: response.data
}).catch(error => { console.error(error) })
})

/**
* Formats the given date into a string representation.
* @param {Date} date - The date object to format.
* @returns {string} The formatted date string.
*/
const formatDate = (date: Date): string => {
return moment(date).format('MMM DD, YYYY')
}

/**
* Formats the address by converting the city and street values to lowercase.
* @param {Address} address - The address object to be formatted.
* @returns {Address} - The formatted address object.
*/
const formatAddress = (address: Address): Address => {
address && Object.keys(address).forEach(key => {
if (['city', 'street'].includes(key)) {
Expand Down
42 changes: 39 additions & 3 deletions auth-web/src/models/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,45 @@ export interface QualifiedSupplierApplicant {
address: Address
authorizationName: string
businessName: string
partyType: string
phoneExtension: string
phoneNumber: string
dbaName?: string
partyType?: string
phoneExtension?: string
phoneNumber?: string
termsAccepted: boolean
mfLocation?: Address
}

// Interface describing response from MHR api for Qualified Supplier applicant info
export interface MhrManufacturerInfoIF {
authorizationName?: string
dbaName?: string
description: {
manufacturer: string
}
location: {
address: Address
dealerName: string
leaveProvince: boolean
locationType: string
}
ownerGroups: [
{
groupId: number
owners: [
{
address: Address
organizationName: string
partyType: string
phoneNumber: string
}
]
type: string
}
],
submittingParty: {
address: Address
businessName: string
}
termsAccepted: boolean
}

Expand Down
25 changes: 22 additions & 3 deletions auth-web/src/resources/QualifiedSupplierAccessResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,31 @@ export const userAccessRequirements: Partial<Record<TaskType, QualifiedSupplierR
forms), will be provided within 7 business days, at the fee level set by the Registrar.`
}
],
[TaskType.MHR_MANUFACTURERS]: [],
[TaskType.MHR_DEALERS]: []
[TaskType.MHR_MANUFACTURERS]: [
{
boldText: `Have comprehensive general liability insurance `,
regularText: `equal to or greater than $2,000,000.00.`
},
{
boldText: `Manufactured homes built are CSA approved `,
regularText: `(Z240 or A277).`
},
{
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. `
}
],
[TaskType.MHR_DEALERS]: [
{
boldText: `Have comprehensive general liability insurance `,
regularText: `equal to or greater than $2,000,000.00.`
}
]
}

export const userAccessDisplayNames: Partial<Record<TaskType, string>> = {
[TaskType.MHR_LAWYER_NOTARY]: 'Lawyers and Notaries',
[TaskType.MHR_MANUFACTURERS]: 'Manufacturers',
[TaskType.MHR_MANUFACTURERS]: 'Home Manufacturers',
[TaskType.MHR_DEALERS]: 'Home Dealers'
}
10 changes: 7 additions & 3 deletions auth-web/src/services/task.services.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Task, TaskFilterParams, TaskList } from '@/models/Task'
import { TaskRelationshipStatus, TaskType } from '@/util/constants'

import { AxiosResponse } from 'axios'
import ConfigHelper from '@/util/config-helper'
import { TaskRelationshipStatus } from '@/util/constants'
import { axios } from '@/util/http-util'

export default class TaskService {
Expand Down Expand Up @@ -60,12 +60,16 @@ export default class TaskService {
{ status: TaskRelationshipStatus.HOLD, remarks, relationshipStatus: TaskRelationshipStatus.PENDING_STAFF_REVIEW })
}

public static async getQsApplicantForTaskReview (accountId: number | string): Promise<AxiosResponse> {
public static async getQsApplicantForTaskReview (accountId: number | string, type: TaskType): Promise<AxiosResponse> {
const apiKey = ConfigHelper.getMhrAPIKey()
const headers = {
'x-apikey': apiKey,
'Account-Id': accountId
}
return axios.get(`${ConfigHelper.getMhrAPIUrl()}/qualified-suppliers`, { headers })
const url = type === TaskType.MHR_MANUFACTURERS
? `${ConfigHelper.getMhrAPIUrl()}/manufacturers`
: `${ConfigHelper.getMhrAPIUrl()}/qualified-suppliers`

return axios.get(url, { headers })
}
}
Loading
Loading