Skip to content

Commit 3859f2a

Browse files
authored
Merge pull request #303 from Bostads-AB-Mimer/feature/mim-536-skapa-endpoint-for-att-hamta-underhallsenheter
MIM-536: Create endpoint for fetching maintenance units - core
2 parents 9a01041 + 7e0e3f3 commit 3859f2a

File tree

6 files changed

+344
-0
lines changed

6 files changed

+344
-0
lines changed

src/adapters/property-base-adapter/generated/api-types.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,65 @@ export interface paths {
971971
patch?: never;
972972
trace?: never;
973973
};
974+
"/maintenance-units/by-rental-id/{id}": {
975+
parameters: {
976+
query?: never;
977+
header?: never;
978+
path?: never;
979+
cookie?: never;
980+
};
981+
/**
982+
* Get all maintenance units for a specific rental property id
983+
* @description Retrieves all maintenance units associated with a given rental property id.
984+
*
985+
*/
986+
get: {
987+
parameters: {
988+
query?: never;
989+
header?: never;
990+
path: {
991+
/** @description The ID of the rental property for which to retrieve maintenance units. */
992+
id: string;
993+
};
994+
cookie?: never;
995+
};
996+
requestBody?: never;
997+
responses: {
998+
/** @description Successfully retrieved the maintenance units. */
999+
200: {
1000+
headers: {
1001+
[name: string]: unknown;
1002+
};
1003+
content: {
1004+
"application/json": {
1005+
content?: components["schemas"]["MaintenanceUnit"][];
1006+
};
1007+
};
1008+
};
1009+
/** @description Invalid query parameters. */
1010+
400: {
1011+
headers: {
1012+
[name: string]: unknown;
1013+
};
1014+
content?: never;
1015+
};
1016+
/** @description Internal server error. */
1017+
500: {
1018+
headers: {
1019+
[name: string]: unknown;
1020+
};
1021+
content?: never;
1022+
};
1023+
};
1024+
};
1025+
put?: never;
1026+
post?: never;
1027+
delete?: never;
1028+
options?: never;
1029+
head?: never;
1030+
patch?: never;
1031+
trace?: never;
1032+
};
9741033
"/health": {
9751034
parameters: {
9761035
query?: never;
@@ -1398,6 +1457,15 @@ export interface components {
13981457
disableQuantitiesBelowCompany: number;
13991458
timestamp: string;
14001459
};
1460+
MaintenanceUnit: {
1461+
id: string;
1462+
rentalPropertyId: string;
1463+
code: string;
1464+
caption: string;
1465+
type: string | null;
1466+
estateCode: string;
1467+
estate: string;
1468+
};
14011469
ResidenceByRentalId: {
14021470
id: string;
14031471
code: string;

src/adapters/property-base-adapter/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,32 @@ export async function getRooms(
273273
return { ok: false, err: 'unknown' }
274274
}
275275
}
276+
277+
type GetMaintenanceUnitsByRentalPropertyIdResponse =
278+
components['schemas']['MaintenanceUnit'][]
279+
280+
export async function getMaintenanceUnitsForRentalProperty(
281+
rentalPropertyId: string
282+
): Promise<
283+
AdapterResult<GetMaintenanceUnitsByRentalPropertyIdResponse, 'unknown'>
284+
> {
285+
try {
286+
const fetchResponse = await client().GET(
287+
'/maintenance-units/by-rental-id/{id}',
288+
{
289+
params: { path: { id: rentalPropertyId } },
290+
}
291+
)
292+
if (!fetchResponse.data?.content) {
293+
throw { ok: false, err: 'unknown' }
294+
}
295+
296+
return { ok: true, data: fetchResponse.data.content }
297+
} catch (err) {
298+
logger.error(
299+
{ err },
300+
'property-base-adapter.getMaintenanceUnitsForRentalProperty'
301+
)
302+
return { ok: false, err: 'unknown' }
303+
}
304+
}

src/adapters/tests/property-base-adapter.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,46 @@ describe('property-base-adapter', () => {
379379
})
380380
})
381381
})
382+
383+
describe('getMaintenanceUnitsByRentalId', () => {
384+
it('returns maintenance units for a rental property', async () => {
385+
const maintenanceUnitsMock = factory.maintenanceUnitInfo.buildList(3)
386+
387+
mockServer.use(
388+
http.get(
389+
`${config.propertyBaseService.url}/maintenance-units/by-rental-id/1234`,
390+
() =>
391+
HttpResponse.json(
392+
{
393+
content: maintenanceUnitsMock,
394+
},
395+
{ status: 200 }
396+
)
397+
)
398+
)
399+
400+
const result =
401+
await propertyBaseAdapter.getMaintenanceUnitsForRentalProperty('1234')
402+
403+
expect(result).toMatchObject({
404+
ok: true,
405+
data: maintenanceUnitsMock,
406+
})
407+
})
408+
409+
it('returns err if request fails', async () => {
410+
mockServer.use(
411+
http.get(
412+
`${config.propertyBaseService.url}/maintenance-units/by-rental-id/1234`,
413+
() => new HttpResponse(null, { status: 500 })
414+
)
415+
)
416+
417+
const result =
418+
await propertyBaseAdapter.getMaintenanceUnitsForRentalProperty('1234')
419+
420+
expect(result.ok).toBe(false)
421+
if (!result.ok) expect(result.err).toBe('unknown')
422+
})
423+
})
382424
})

src/services/property-base-service/index.ts

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const routes = (router: KoaRouter) => {
3131
registerSchema('ResidenceDetails', schemas.ResidenceDetailsSchema)
3232
registerSchema('Staircase', schemas.StaircaseSchema)
3333
registerSchema('Room', schemas.RoomSchema)
34+
registerSchema('MaintenanceUnit', schemas.MaintenanceUnitSchema)
3435
registerSchema(
3536
'ResidenceByRentalIdDetails',
3637
schemas.ResidenceByRentalIdSchema
@@ -676,4 +677,160 @@ export const routes = (router: KoaRouter) => {
676677
ctx.body = { error: 'Internal server error', ...metadata }
677678
}
678679
})
680+
681+
/**
682+
* @swagger
683+
* /propertyBase/maintenance-units/by-rental-id/{rentalId}:
684+
* get:
685+
* summary: Get maintenance units by rental id.
686+
* description: Returns all maintenance units belonging to a rental property.
687+
* tags:
688+
* - Property base Service
689+
* security:
690+
* - bearerAuth: []
691+
* parameters:
692+
* - in: path
693+
* name: rentalId
694+
* required: true
695+
* schema:
696+
* type: string
697+
* description: The ID of the rental property for which to retrieve maintenance units.
698+
* responses:
699+
* 200:
700+
* description: Successfully retrieved the maintenance units.
701+
* content:
702+
* application/json:
703+
* schema:
704+
* type: object
705+
* properties:
706+
* content:
707+
* type: array
708+
* items:
709+
* $ref: '#/components/schemas/MaintenanceUnit'
710+
* 400:
711+
* description: Invalid query parameters.
712+
* 500:
713+
* description: Internal server error.
714+
*/
715+
router.get('(.*)/maintenance-units/by-rental-id/:rentalId', async (ctx) => {
716+
const metadata = generateRouteMetadata(ctx)
717+
const { rentalId } = ctx.params
718+
719+
logger.info(`GET /maintenance-units/by-rental-id/${rentalId}`, metadata)
720+
721+
try {
722+
const result =
723+
await propertyBaseAdapter.getMaintenanceUnitsForRentalProperty(rentalId)
724+
if (!result.ok) {
725+
logger.error(
726+
result.err,
727+
'Error getting maintenance units from property-base',
728+
metadata
729+
)
730+
ctx.status = 500
731+
ctx.body = { error: 'Internal server error', ...metadata }
732+
return
733+
}
734+
735+
ctx.body = {
736+
content: result.data satisfies Array<schemas.MaintenanceUnit>,
737+
...metadata,
738+
}
739+
} catch (error) {
740+
logger.error(error, 'Internal server error', metadata)
741+
ctx.status = 500
742+
ctx.body = { error: 'Internal server error', ...metadata }
743+
}
744+
})
745+
746+
/**
747+
* @swagger
748+
* /propertyBase/maintenance-units/by-contact-code/{contactCode}:
749+
* get:
750+
* summary: Get maintenance units by contact code.
751+
* description: Returns all maintenance units belonging to a contact code.
752+
* tags:
753+
* - Property base Service
754+
* security:
755+
* - bearerAuth: []
756+
* parameters:
757+
* - in: path
758+
* name: contactCode
759+
* required: true
760+
* schema:
761+
* type: string
762+
* description: The contact code for which to retrieve maintenance units.
763+
* responses:
764+
* 200:
765+
* description: Successfully retrieved the maintenance units.
766+
* content:
767+
* application/json:
768+
* schema:
769+
* type: object
770+
* properties:
771+
* content:
772+
* type: array
773+
* items:
774+
* type: object
775+
* properties:
776+
* ok:
777+
* type: boolean
778+
* data:
779+
* type: array
780+
* items:
781+
* $ref: '#/components/schemas/MaintenanceUnit'
782+
* 400:
783+
* description: Invalid query parameters.
784+
* 500:
785+
* description: Internal server error.
786+
*/
787+
router.get(
788+
'(.*)/maintenance-units/by-contact-code/:contactCode',
789+
async (ctx) => {
790+
const metadata = generateRouteMetadata(ctx)
791+
try {
792+
const leases = await leasingAdapter.getLeasesForContactCode(
793+
ctx.params.contactCode,
794+
{
795+
includeUpcomingLeases: true,
796+
includeTerminatedLeases: false,
797+
includeContacts: false,
798+
}
799+
)
800+
const promises = leases
801+
.filter(
802+
(lease) =>
803+
lease.type.toLocaleLowerCase().trimEnd() === 'bostadskontrakt'
804+
)
805+
.map((lease) =>
806+
propertyBaseAdapter.getMaintenanceUnitsForRentalProperty(
807+
lease.rentalPropertyId
808+
)
809+
)
810+
811+
const maintenanceUnits = await Promise.all(promises).then((units) =>
812+
units.filter((unit) => unit !== undefined).flat()
813+
)
814+
815+
if (maintenanceUnits && maintenanceUnits.length > 0) {
816+
ctx.status = 200
817+
ctx.body = { content: maintenanceUnits, ...metadata }
818+
} else {
819+
ctx.status = 200
820+
ctx.body = {
821+
content: [],
822+
reason: 'No maintenance units found',
823+
...metadata,
824+
}
825+
logger.info('No maintenance units found')
826+
return
827+
}
828+
} catch (error) {
829+
console.error('Error:', error)
830+
ctx.status = 500
831+
ctx.body = { error: 'Internal server error', ...metadata }
832+
return
833+
}
834+
}
835+
)
679836
}

src/services/property-base-service/schemas.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,16 @@ export const RoomSchema = z.object({
292292
roomType: RoomTypeSchema.nullable(),
293293
})
294294

295+
export const MaintenanceUnitSchema = z.object({
296+
id: z.string(),
297+
rentalPropertyId: z.string(),
298+
code: z.string(),
299+
caption: z.string(),
300+
type: z.string().nullable(),
301+
estateCode: z.string(),
302+
estate: z.string(),
303+
})
304+
295305
export const GetRoomsQueryParamsSchema = z.object({
296306
residenceId: z.string().min(1, { message: 'residenceId is required.' }),
297307
})
@@ -323,3 +333,4 @@ export type ResidenceByRentalIdDetails = z.infer<
323333
export type Staircase = z.infer<typeof StaircaseSchema>
324334
export type RoomType = z.infer<typeof RoomTypeSchema>
325335
export type Room = z.infer<typeof RoomSchema>
336+
export type MaintenanceUnit = z.infer<typeof MaintenanceUnitSchema>

0 commit comments

Comments
 (0)