Skip to content
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
68 changes: 68 additions & 0 deletions src/adapters/property-base-adapter/generated/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,65 @@ export interface paths {
patch?: never;
trace?: never;
};
"/maintenance-units/by-rental-id/{id}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get all maintenance units for a specific rental property id
* @description Retrieves all maintenance units associated with a given rental property id.
*
*/
get: {
parameters: {
query?: never;
header?: never;
path: {
/** @description The ID of the rental property for which to retrieve maintenance units. */
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successfully retrieved the maintenance units. */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
content?: components["schemas"]["MaintenanceUnit"][];
};
};
};
/** @description Invalid query parameters. */
400: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Internal server error. */
500: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/health": {
parameters: {
query?: never;
Expand Down Expand Up @@ -1398,6 +1457,15 @@ export interface components {
disableQuantitiesBelowCompany: number;
timestamp: string;
};
MaintenanceUnit: {
id: string;
rentalPropertyId: string;
code: string;
caption: string;
type: string | null;
estateCode: string;
estate: string;
};
ResidenceByRentalId: {
id: string;
code: string;
Expand Down
29 changes: 29 additions & 0 deletions src/adapters/property-base-adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,32 @@ export async function getRooms(
return { ok: false, err: 'unknown' }
}
}

type GetMaintenanceUnitsByRentalPropertyIdResponse =
components['schemas']['MaintenanceUnit'][]

export async function getMaintenanceUnitsForRentalProperty(
rentalPropertyId: string
): Promise<
AdapterResult<GetMaintenanceUnitsByRentalPropertyIdResponse, 'unknown'>
> {
try {
const fetchResponse = await client().GET(
'/maintenance-units/by-rental-id/{id}',
{
params: { path: { id: rentalPropertyId } },
}
)
if (!fetchResponse.data?.content) {
throw { ok: false, err: 'unknown' }
}

return { ok: true, data: fetchResponse.data.content }
} catch (err) {
logger.error(
{ err },
'property-base-adapter.getMaintenanceUnitsForRentalProperty'
)
return { ok: false, err: 'unknown' }
}
}
42 changes: 42 additions & 0 deletions src/adapters/tests/property-base-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@

describe('getResidenceByRentalId', () => {
it('returns err if request fails', async () => {
const residenceDetailsMock = factory.residenceByRentalIdDetails.build()

Check warning on line 194 in src/adapters/tests/property-base-adapter.test.ts

View workflow job for this annotation

GitHub Actions / test

'residenceDetailsMock' is assigned a value but never used. Allowed unused vars must match /^_/u

mockServer.use(
http.get(
Expand Down Expand Up @@ -379,4 +379,46 @@
})
})
})

describe('getMaintenanceUnitsByRentalId', () => {
it('returns maintenance units for a rental property', async () => {
const maintenanceUnitsMock = factory.maintenanceUnitInfo.buildList(3)

mockServer.use(
http.get(
`${config.propertyBaseService.url}/maintenance-units/by-rental-id/1234`,
() =>
HttpResponse.json(
{
content: maintenanceUnitsMock,
},
{ status: 200 }
)
)
)

const result =
await propertyBaseAdapter.getMaintenanceUnitsForRentalProperty('1234')

expect(result).toMatchObject({
ok: true,
data: maintenanceUnitsMock,
})
})

it('returns err if request fails', async () => {
mockServer.use(
http.get(
`${config.propertyBaseService.url}/maintenance-units/by-rental-id/1234`,
() => new HttpResponse(null, { status: 500 })
)
)

const result =
await propertyBaseAdapter.getMaintenanceUnitsForRentalProperty('1234')

expect(result.ok).toBe(false)
if (!result.ok) expect(result.err).toBe('unknown')
})
})
})
157 changes: 157 additions & 0 deletions src/services/property-base-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const routes = (router: KoaRouter) => {
registerSchema('ResidenceDetails', schemas.ResidenceDetailsSchema)
registerSchema('Staircase', schemas.StaircaseSchema)
registerSchema('Room', schemas.RoomSchema)
registerSchema('MaintenanceUnit', schemas.MaintenanceUnitSchema)
registerSchema(
'ResidenceByRentalIdDetails',
schemas.ResidenceByRentalIdSchema
Expand Down Expand Up @@ -676,4 +677,160 @@ export const routes = (router: KoaRouter) => {
ctx.body = { error: 'Internal server error', ...metadata }
}
})

/**
* @swagger
* /propertyBase/maintenance-units/by-rental-id/{rentalId}:
* get:
* summary: Get maintenance units by rental id.
* description: Returns all maintenance units belonging to a rental property.
* tags:
* - Property base Service
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: rentalId
* required: true
* schema:
* type: string
* description: The ID of the rental property for which to retrieve maintenance units.
* responses:
* 200:
* description: Successfully retrieved the maintenance units.
* content:
* application/json:
* schema:
* type: object
* properties:
* content:
* type: array
* items:
* $ref: '#/components/schemas/MaintenanceUnit'
* 400:
* description: Invalid query parameters.
* 500:
* description: Internal server error.
*/
router.get('(.*)/maintenance-units/by-rental-id/:rentalId', async (ctx) => {
const metadata = generateRouteMetadata(ctx)
const { rentalId } = ctx.params

logger.info(`GET /maintenance-units/by-rental-id/${rentalId}`, metadata)

try {
const result =
await propertyBaseAdapter.getMaintenanceUnitsForRentalProperty(rentalId)
if (!result.ok) {
logger.error(
result.err,
'Error getting maintenance units from property-base',
metadata
)
ctx.status = 500
ctx.body = { error: 'Internal server error', ...metadata }
return
}

ctx.body = {
content: result.data satisfies Array<schemas.MaintenanceUnit>,
...metadata,
}
} catch (error) {
logger.error(error, 'Internal server error', metadata)
ctx.status = 500
ctx.body = { error: 'Internal server error', ...metadata }
}
})

/**
* @swagger
* /propertyBase/maintenance-units/by-contact-code/{contactCode}:
* get:
* summary: Get maintenance units by contact code.
* description: Returns all maintenance units belonging to a contact code.
* tags:
* - Property base Service
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: contactCode
* required: true
* schema:
* type: string
* description: The contact code for which to retrieve maintenance units.
* responses:
* 200:
* description: Successfully retrieved the maintenance units.
* content:
* application/json:
* schema:
* type: object
* properties:
* content:
* type: array
* items:
* type: object
* properties:
* ok:
* type: boolean
* data:
* type: array
* items:
* $ref: '#/components/schemas/MaintenanceUnit'
* 400:
* description: Invalid query parameters.
* 500:
* description: Internal server error.
*/
router.get(
'(.*)/maintenance-units/by-contact-code/:contactCode',
async (ctx) => {
const metadata = generateRouteMetadata(ctx)
try {
const leases = await leasingAdapter.getLeasesForContactCode(
ctx.params.contactCode,
{
includeUpcomingLeases: true,
includeTerminatedLeases: false,
includeContacts: false,
}
)
const promises = leases
.filter(
(lease) =>
lease.type.toLocaleLowerCase().trimEnd() === 'bostadskontrakt'
)
.map((lease) =>
propertyBaseAdapter.getMaintenanceUnitsForRentalProperty(
lease.rentalPropertyId
)
)

const maintenanceUnits = await Promise.all(promises).then((units) =>
units.filter((unit) => unit !== undefined).flat()
)

if (maintenanceUnits && maintenanceUnits.length > 0) {
ctx.status = 200
ctx.body = { content: maintenanceUnits, ...metadata }
} else {
ctx.status = 200
ctx.body = {
content: [],
reason: 'No maintenance units found',
...metadata,
}
logger.info('No maintenance units found')
return
}
} catch (error) {
console.error('Error:', error)
ctx.status = 500
ctx.body = { error: 'Internal server error', ...metadata }
return
}
}
)
}
11 changes: 11 additions & 0 deletions src/services/property-base-service/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,16 @@ export const RoomSchema = z.object({
roomType: RoomTypeSchema.nullable(),
})

export const MaintenanceUnitSchema = z.object({
id: z.string(),
rentalPropertyId: z.string(),
code: z.string(),
caption: z.string(),
type: z.string().nullable(),
estateCode: z.string(),
estate: z.string(),
})

export const GetRoomsQueryParamsSchema = z.object({
residenceId: z.string().min(1, { message: 'residenceId is required.' }),
})
Expand Down Expand Up @@ -323,3 +333,4 @@ export type ResidenceByRentalIdDetails = z.infer<
export type Staircase = z.infer<typeof StaircaseSchema>
export type RoomType = z.infer<typeof RoomTypeSchema>
export type Room = z.infer<typeof RoomSchema>
export type MaintenanceUnit = z.infer<typeof MaintenanceUnitSchema>
Loading
Loading