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

UTH-164: review status and housing type types #187

Merged
merged 14 commits into from
Jan 13, 2025
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
66 changes: 66 additions & 0 deletions migrations/20241216104418_refactor-housing-reference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function (knex) {
return knex.transaction(async (trx) => {
await trx.raw(`
ALTER TABLE application_profile_housing_reference
ALTER COLUMN phone nvarchar(36) NULL;
`)

await trx.raw(`
ALTER TABLE application_profile_housing_reference
ADD
comment nvarchar(max),
reasonRejected nvarchar(36),
lastAdminUpdatedAt datetimeoffset,
lastAdminUpdatedBy nvarchar(36),
lastApplicantUpdatedAt datetimeoffset;
`)

await trx.raw(`
ALTER TABLE application_profile_housing_reference
DROP COLUMN reviewStatusReason, reviewedAt;
`)

await trx.raw(`
ALTER TABLE application_profile
ALTER COLUMN housingType nvarchar(36) NOT NULL;
`)
})
}

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
return knex.transaction(async (trx) => {
await trx.raw(`
ALTER TABLE application_profile_housing_reference
ADD reviewStatusReason nvarchar(max),
reviewedAt datetimeoffset;
`)

await trx.raw(`
ALTER TABLE application_profile_housing_reference
DROP COLUMN
comment,
reasonRejected,
lastAdminUpdatedAt,
lastApplicantUpdatedAt,
lastAdminUpdatedBy;
`)

await trx.raw(`
ALTER TABLE application_profile_housing_reference
ALTER COLUMN phone nvarchar(36) NOT NULL;
`)

await trx.raw(`
ALTER TABLE application_profile
ALTER COLUMN housingType nvarchar(36) NULL;
`)
})
}
8 changes: 4 additions & 4 deletions 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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"koa-pino-logger": "^4.0.0",
"koa2-swagger-ui": "^5.10.0",
"mssql": "^11.0.1",
"onecore-types": "^2.5.0",
"onecore-types": "^3.0.0",
"onecore-utilities": "^1.1.0",
"personnummer": "^3.2.1",
"pino": "^9.1.0",
Expand Down
180 changes: 114 additions & 66 deletions src/services/lease-service/adapters/application-profile-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,89 @@
import { Knex } from 'knex'
import { RequestError } from 'tedious'
import { logger } from 'onecore-utilities'
import { ApplicationProfile } from 'onecore-types'
import { z } from 'zod'

import { AdapterResult } from './types'
import {
ApplicationProfileHousingReferenceSchema,
ApplicationProfileSchema,
} from './db-schemas'

type CreateParams = {
contactCode: string
numAdults: number
numChildren: number
expiresAt: Date | null
housingType?: string
housingTypeDescription?: string
landlord?: string
}
type ApplicationProfile = z.infer<typeof ApplicationProfileSchema>

const _CreateParamsSchema = ApplicationProfileSchema.pick({
numChildren: true,
numAdults: true,
expiresAt: true,
housingType: true,
housingTypeDescription: true,
landlord: true,
}).extend({
housingReference: ApplicationProfileHousingReferenceSchema.pick({
expiresAt: true,
phone: true,
email: true,
reviewStatus: true,
comment: true,
reasonRejected: true,
lastAdminUpdatedAt: true,
lastApplicantUpdatedAt: true,
}),
})

type CreateParams = z.infer<typeof _CreateParamsSchema>

export async function create(
db: Knex,
contactCode: string,
params: CreateParams
): Promise<
AdapterResult<ApplicationProfile, 'conflict-contact-code' | 'unknown'>
> {
try {
const [profile] = await db
.insert({
contactCode: params.contactCode,
numChildren: params.numChildren,
numAdults: params.numAdults,
expiresAt: params.expiresAt,
housingType: params.housingType,
housingTypeDescription: params.housingTypeDescription,
landlord: params.landlord,
const result = await db.transaction(async (trx) => {
const [profile] = await trx
.insert({
contactCode: contactCode,
numChildren: params.numChildren,
numAdults: params.numAdults,
expiresAt: params.expiresAt,
housingType: params.housingType,
housingTypeDescription: params.housingTypeDescription,
landlord: params.landlord,
})
.into('application_profile')
.returning('*')

const [reference] = await trx
.insert({
applicationProfileId: profile.id,
phone: params.housingReference.phone,
email: params.housingReference.email,
reviewStatus: params.housingReference.reviewStatus,
comment: params.housingReference.comment,
reasonRejected: params.housingReference.reasonRejected,
lastAdminUpdatedAt: params.housingReference.lastAdminUpdatedAt,
lastAdminUpdatedBy: 'not-implemented',
lastApplicantUpdatedAt:
params.housingReference.lastApplicantUpdatedAt,
expiresAt: params.housingReference.expiresAt,
})
.into('application_profile_housing_reference')
.returning('*')

return ApplicationProfileSchema.parse({
...profile,
housingReference: reference,
})
.into('application_profile')
.returning('*')
})

return { ok: true, data: profile }
return { ok: true, data: result }
} catch (err) {
if (err instanceof RequestError) {
if (err.message.includes('UQ_contactCode')) {
logger.info(
{ contactCode: params.contactCode },
{ contactCode },
'applicationProfileAdapter.create - can not insert duplicate application profile'
)
return { ok: false, err: 'conflict-contact-code' }
Expand All @@ -62,82 +105,87 @@ export async function getByContactCode(
SELECT
ap.*,
(
SELECT apht.*
FROM application_profile_housing_reference apht
WHERE apht.applicationProfileId = ap.id
SELECT apht2.*
FROM application_profile_housing_reference apht2
WHERE apht2.applicationProfileId = ap.id
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER, INCLUDE_NULL_VALUES
) AS housingReference
FROM application_profile ap
INNER JOIN application_profile_housing_reference apht ON ap.id = apht.applicationProfileId
WHERE ap.contactCode = ?
`,
`,
[contactCode]
)

if (!row) {
return { ok: false, err: 'not-found' }
}

const housingReference = row.housingReference
? JSON.parse(row.housingReference)
: undefined

return {
ok: true,
data: {
data: ApplicationProfileSchema.parse({
...row,
housingReference: housingReference
? {
...housingReference,
expiresAt: new Date(housingReference.expiresAt),
createdAt: new Date(housingReference.createdAt),
reviewedAt: housingReference.reviewedAt
? new Date(housingReference.reviewedAt)
: null,
}
: undefined,
housingType: row.housingType || undefined,
housingTypeDescription: row.housingTypeDescription || undefined,
landlord: row.landlord || undefined,
},
housingReference: JSON.parse(row.housingReference),
}),
}
} catch (err) {
logger.error(err, 'applicationProfileAdapter.getByContactCode')
return { ok: false, err: 'unknown' }
}
}

type UpdateParams = {
numChildren: number
numAdults: number
expiresAt: Date | null
housingType?: string
housingTypeDescription?: string
landlord?: string
}
type UpdateParams = z.infer<typeof _CreateParamsSchema>

export async function update(
db: Knex,
contactCode: string,
params: UpdateParams
): Promise<AdapterResult<ApplicationProfile, 'no-update' | 'unknown'>> {
try {
const [profile] = await db('application_profile')
.update({
numChildren: params.numChildren,
numAdults: params.numAdults,
expiresAt: params.expiresAt,
housingType: params.housingType,
housingTypeDescription: params.housingTypeDescription,
landlord: params.landlord,
const result = await db.transaction(async (trx) => {
const [profile] = await db('application_profile')
.update({
numChildren: params.numChildren,
numAdults: params.numAdults,
expiresAt: params.expiresAt,
housingType: params.housingType,
housingTypeDescription: params.housingTypeDescription,
landlord: params.landlord,
})
.where('contactCode', contactCode)
.returning('*')

if (!profile) {
return 'no-update'
}

const [reference] = await trx('application_profile_housing_reference')
.update({
phone: params.housingReference.phone,
email: params.housingReference.email,
reviewStatus: params.housingReference.reviewStatus,
comment: params.housingReference.comment,
reasonRejected: params.housingReference.reasonRejected,
lastAdminUpdatedAt: params.housingReference.lastAdminUpdatedAt,
lastAdminUpdatedBy: 'not-implemented',
lastApplicantUpdatedAt:
params.housingReference.lastApplicantUpdatedAt,
expiresAt: params.housingReference.expiresAt,
})
.where({ applicationProfileId: profile.id })
.returning('*')

return ApplicationProfileSchema.parse({
...profile,
housingReference: reference,
})
.where('contactCode', contactCode)
.returning('*')
})

if (!profile) {
if (result === 'no-update') {
return { ok: false, err: 'no-update' }
}

return { ok: true, data: profile }
return { ok: true, data: result }
} catch (err) {
logger.error(err, 'applicationProfileAdapter.update')
return { ok: false, err: 'unknown' }
Expand Down
Loading
Loading