Skip to content

Commit 63805cb

Browse files
authored
Feat:UTH-237 Get Published Lisings by RentalObjectCode (#42)
To be able to show the parking space detail page on mimer.nu we need to be able to retrieve published listings by RentalObjectCode. * filter on RentalObjectCode has been added to GET /listings in both core and lesing
1 parent 07c9cec commit 63805cb

File tree

8 files changed

+163
-2
lines changed

8 files changed

+163
-2
lines changed

core/src/adapters/leasing-adapter/listings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ type GetListingsParams = {
208208
listingCategory?: 'PARKING_SPACE' | 'APARTMENT' | 'STORAGE'
209209
published?: boolean
210210
rentalRule?: 'SCORED' | 'NON_SCORED'
211+
rentalObjectCode?: string
211212
}
212213

213214
const getListings = async (
@@ -219,6 +220,8 @@ const getListings = async (
219220
if (params.published !== undefined)
220221
queryParams.append('published', params.published.toString())
221222
if (params.rentalRule) queryParams.append('rentalRule', params.rentalRule)
223+
if (params.rentalObjectCode)
224+
queryParams.append('rentalObjectCode', params.rentalObjectCode)
222225

223226
try {
224227
const response = await axios.get(

core/src/adapters/tests/leasing-adapter/listings.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,23 @@ describe(leasingAdapter.getListings, () => {
217217
]),
218218
})
219219
})
220+
221+
it('returns a list listings filtered on published and rentalObjectCode', async () => {
222+
nock(config.tenantsLeasesService.url)
223+
.get('/listings')
224+
.query({ rentalObjectCode: 'ABC1234', published: true })
225+
.reply(200, { content: factory.listing.buildList(4) })
226+
227+
const result = await leasingAdapter.getListings({
228+
rentalObjectCode: 'ABC1234',
229+
published: true,
230+
})
231+
232+
expect(result).toMatchObject({
233+
ok: true,
234+
data: expect.arrayContaining([
235+
expect.objectContaining({ id: expect.any(Number) }),
236+
]),
237+
})
238+
})
220239
})

core/src/services/lease-service/listings.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ export const routes = (router: KoaRouter) => {
4949
* schema:
5050
* type: string
5151
* description: A contact code to filter out listings that are not valid to rent for the contact.
52+
* - in: query
53+
* name: rentalObjectCode
54+
* required: false
55+
* schema:
56+
* type: string
57+
* description: A Rental Object Code to filter the listings.
5258
* responses:
5359
* '200':
5460
* description: Successful response with the requested list of listings.
@@ -73,6 +79,7 @@ export const routes = (router: KoaRouter) => {
7379
.transform((value) => (value ? value === 'true' : undefined)),
7480
rentalRule: z.enum(['SCORED', 'NON_SCORED']).optional(),
7581
validToRentForContactCode: z.string().optional(),
82+
rentalObjectCode: z.string().optional(),
7683
})
7784
const query = querySchema.safeParse(ctx.query)
7885

@@ -82,6 +89,7 @@ export const routes = (router: KoaRouter) => {
8289
listingCategory: query.data?.listingCategory,
8390
published: query.data?.published,
8491
rentalRule: query.data?.rentalRule,
92+
rentalObjectCode: query.data?.rentalObjectCode,
8593
})
8694

8795
if (!result.ok) {

core/src/services/lease-service/tests/listings.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,34 @@ describe('GET /listings', () => {
6464
})
6565
})
6666

67+
it('responds with 200 on success with filter on published', async () => {
68+
const listing = factory.listing.build({
69+
id: 1337,
70+
publishedFrom: new Date(),
71+
publishedTo: new Date(),
72+
rentalObjectCode: '12345',
73+
})
74+
const parkingSpace = factory.vacantParkingSpace.build({
75+
rentalObjectCode: '12345',
76+
})
77+
78+
const getListingsSpy = jest
79+
.spyOn(tenantLeaseAdapter, 'getListings')
80+
.mockResolvedValueOnce({ ok: true, data: [listing] })
81+
82+
jest
83+
.spyOn(tenantLeaseAdapter, 'getParkingSpaces')
84+
.mockResolvedValueOnce({ ok: true, data: [parkingSpace] })
85+
86+
const res = await request(app.callback()).get('/listings?published=true')
87+
88+
expect(getListingsSpy).toHaveBeenCalledWith({ published: true })
89+
expect(res.status).toBe(200)
90+
expect(res.body).toEqual({
91+
content: [expect.objectContaining({ id: 1337 })],
92+
})
93+
})
94+
6795
it('responds with 200 on success with filter on rentalRule', async () => {
6896
const listing = factory.listing.build({
6997
id: 1337,
@@ -96,6 +124,40 @@ describe('GET /listings', () => {
96124
})
97125
})
98126

127+
it('responds with 200 on success with filter on rentalObjectCode', async () => {
128+
const listing = factory.listing.build({
129+
id: 1337,
130+
rentalRule: 'SCORED',
131+
rentalObjectCode: '12345',
132+
})
133+
const parkingSpace = factory.vacantParkingSpace.build({
134+
rentalObjectCode: '12345',
135+
})
136+
137+
const getListingsSpy = jest
138+
.spyOn(tenantLeaseAdapter, 'getListings')
139+
.mockResolvedValueOnce({ ok: true, data: [listing] })
140+
141+
jest
142+
.spyOn(tenantLeaseAdapter, 'getParkingSpaces')
143+
.mockResolvedValueOnce({ ok: true, data: [parkingSpace] })
144+
145+
const res = await request(app.callback()).get(
146+
'/listings?rentalObjectCode=12345'
147+
)
148+
149+
expect(getListingsSpy).toHaveBeenCalledWith({
150+
rentalObjectCode: '12345',
151+
published: undefined,
152+
listingCategory: undefined,
153+
validToRentForContactCode: undefined,
154+
})
155+
expect(res.status).toBe(200)
156+
expect(res.body).toEqual({
157+
content: [expect.objectContaining({ id: 1337 })],
158+
})
159+
})
160+
99161
it('responds with 200 on success with filter on validToRentForContactCode', async () => {
100162
const listing = factory.listing.build({
101163
id: 1337,

services/leasing/src/services/lease-service/adapters/listing-adapter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ type GetListingsParams = {
342342
listingCategory?: 'PARKING_SPACE' | 'APARTMENT' | 'STORAGE'
343343
published?: boolean
344344
rentalRule?: 'SCORED' | 'NON_SCORED'
345+
rentalObjectCode?: string
345346
}
346347

347348
const getListings = async (
@@ -364,6 +365,9 @@ const getListings = async (
364365
if (params.listingCategory) {
365366
builder.andWhere('ListingCategory', '=', params.listingCategory)
366367
}
368+
if (params.rentalObjectCode) {
369+
builder.andWhere('RentalObjectCode', '=', params.rentalObjectCode)
370+
}
367371
})
368372

369373
return { ok: true, data: listings.map(transformFromDbListing) }

services/leasing/src/services/lease-service/routes/listings.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ export const routes = (router: KoaRouter) => {
5151
* schema:
5252
* type: string
5353
* description: The rental rule for the listings, either SCORED or NON_SCORED.
54+
* - in: query
55+
* name: rentalObjectCode
56+
* required: false
57+
* schema:
58+
* type: string
59+
* description: The rental object code for the listings.
5460
* responses:
5561
* '200':
5662
* description: Successful response with the requested list of listings.
@@ -73,17 +79,17 @@ export const routes = (router: KoaRouter) => {
7379
.optional()
7480
.transform((value) => value === 'true'),
7581
rentalRule: z.enum(['SCORED', 'NON_SCORED']).optional(),
82+
rentalObjectCode: z.string().optional(),
7683
})
7784
const query = querySchema.safeParse(ctx.query)
7885

7986
const result = await listingAdapter.getListings({
8087
listingCategory: query.data?.listingCategory,
8188
published: query.data?.published,
8289
rentalRule: query.data?.rentalRule,
90+
rentalObjectCode: query.data?.rentalObjectCode,
8391
})
8492

85-
//TODO: get correponding rental objects from xpand-adapter and add them to the listings
86-
8793
if (!result.ok) {
8894
ctx.status = 500
8995
ctx.body = {

services/leasing/src/services/lease-service/tests/adapters/listing-adapter/get-listings.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,38 @@ describe(listingAdapter.getListings, () => {
9494
}
9595
}))
9696

97+
it('should filter on rentalObjectCode', () =>
98+
withContext(async (ctx) => {
99+
// Create listings
100+
await listingAdapter.createListing(
101+
factory.listing.build({
102+
rentalObjectCode: '1',
103+
rentalRule: 'SCORED',
104+
status: ListingStatus.Active,
105+
}),
106+
ctx.db
107+
)
108+
109+
await listingAdapter.createListing(
110+
factory.listing.build({
111+
rentalObjectCode: '2',
112+
rentalRule: 'NON_SCORED',
113+
status: ListingStatus.Active,
114+
}),
115+
ctx.db
116+
)
117+
118+
const result = await listingAdapter.getListings(
119+
{ rentalObjectCode: '1' },
120+
ctx.db
121+
)
122+
123+
expect(result.ok).toBe(true)
124+
if (result.ok) {
125+
expect(result.data).toHaveLength(1)
126+
expect(result.data[0].rentalObjectCode).toEqual('1')
127+
}
128+
}))
97129
it('should return a list of listings', () =>
98130
withContext(async (ctx) => {
99131
// Create listings

services/leasing/src/services/lease-service/tests/routes/listings.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,33 @@ describe('GET /listings', () => {
129129
})
130130
})
131131

132+
it('responds with 200 and listings with filter for a published rentalObjectCode', async () => {
133+
const getListingsSpy = jest
134+
.spyOn(listingAdapter, 'getListings')
135+
.mockResolvedValueOnce({
136+
ok: true,
137+
data: factory.listing.buildList(1),
138+
})
139+
140+
const res = await request(app.callback()).get(
141+
'/listings?rentalObjectCode=1&published=true'
142+
)
143+
144+
expect(getListingsSpy).toHaveBeenCalledWith({
145+
rentalObjectCode: '1',
146+
published: true,
147+
rentalRule: undefined,
148+
listingCategory: undefined,
149+
})
150+
151+
expect(res.status).toBe(200)
152+
expect(res.body).toEqual({
153+
content: expect.arrayContaining([
154+
expect.objectContaining({ id: expect.any(Number) }),
155+
]),
156+
})
157+
})
158+
132159
it('responds with 500 on unknown error', async () => {
133160
jest.spyOn(listingAdapter, 'getListings').mockResolvedValueOnce({
134161
ok: false,

0 commit comments

Comments
 (0)