Skip to content

Commit 3f59e8a

Browse files
authored
chore(condo): DOMA-11135 add ability to filter by resource id while delete meter readings internally (#5821)
1 parent 4310980 commit 3f59e8a

6 files changed

+161
-12
lines changed

apps/condo/domains/meter/schema/_internalDeleteMeterAndMeterReadingsService.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const _internalDeleteMeterAndMeterReadingsService = new GQLCustomSchema('_intern
4141
types: [
4242
{
4343
access: true,
44-
type: 'input _internalDeleteMeterAndMeterReadingsInput { dv: Int!, sender: SenderFieldInput!, propertyIds: [ID], organizationId: ID! }',
44+
type: 'input _internalDeleteMeterAndMeterReadingsInput { dv: Int!, sender: SenderFieldInput!, propertyIds: [ID], organizationId: ID!, resourcesIds: [ID] }',
4545
},
4646
{
4747
access: true,
@@ -52,7 +52,7 @@ const _internalDeleteMeterAndMeterReadingsService = new GQLCustomSchema('_intern
5252
type: 'type _internalDeleteMeterAndMeterReadingsOutput { status: Status!, metersToDelete: Int!, deletedMeters: Int! }',
5353
},
5454
],
55-
55+
5656
mutations: [
5757
{
5858
access: access.can_internalDeleteMeterAndMeterReadings,
@@ -67,14 +67,15 @@ const _internalDeleteMeterAndMeterReadingsService = new GQLCustomSchema('_intern
6767
},
6868
resolver: async (parent, args, context) => {
6969
const { data } = args
70-
const { dv, sender, propertyIds, organizationId } = data
70+
const { dv, sender, propertyIds, organizationId, resourcesIds } = data
7171

7272
checkDvAndSender(data, ERRORS.DV_VERSION_MISMATCH, ERRORS.WRONG_SENDER_FORMAT, context)
7373

7474
const metersWhere = {
7575
deletedAt: null,
7676
organization: { id: organizationId },
7777
...(isArray(propertyIds) ? { property: { id_in: propertyIds } } : undefined),
78+
...(isArray(resourcesIds) ? { resource: { id_in: resourcesIds } } : undefined),
7879
}
7980

8081
const { count: metersCount } = await itemsQuery('Meter', {
@@ -149,7 +150,7 @@ const _internalDeleteMeterAndMeterReadingsService = new GQLCustomSchema('_intern
149150
},
150151
},
151152
],
152-
153+
153154
})
154155

155156
module.exports = {

apps/condo/domains/meter/schema/_internalDeleteMeterAndMeterReadingsService.test.js

+68-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ const {
1111
expectToThrowAuthenticationErrorToResult,
1212
} = require('@open-condo/keystone/test.utils')
1313

14-
const { COLD_WATER_METER_RESOURCE_ID, METER_READING_SOURCE_INTERNAL_IMPORT_TYPE } = require('@condo/domains/meter/constants/constants')
14+
const {
15+
COLD_WATER_METER_RESOURCE_ID,
16+
HOT_WATER_METER_RESOURCE_ID,
17+
METER_READING_SOURCE_INTERNAL_IMPORT_TYPE,
18+
}
19+
= require('@condo/domains/meter/constants/constants')
1520
const {
1621
_internalDeleteMeterAndMeterReadingsByTestClient,
1722
createTestMeterReading,
@@ -29,7 +34,7 @@ const {
2934
makeClientWithServiceUser,
3035
} = require('@condo/domains/user/utils/testSchema')
3136

32-
37+
3338
describe('DeleteMeterAndMeterReadingsService', () => {
3439
let adminClient, supportClient, residentClient, staffClient, serviceClient, anonymous,
3540
payload, organization, property, resource, source,
@@ -136,7 +141,7 @@ describe('DeleteMeterAndMeterReadingsService', () => {
136141
})
137142

138143
describe('Basic logic', () => {
139-
test('Meters for all properties in organization should be deleted if the "propertyIds" is not specified', async () => {
144+
test('Meters for all properties in organization should be deleted if no "propertyIds" and "resourcesIds" specified', async () => {
140145
const [property2] = await createTestProperty(adminClient, organization)
141146
const [meter2] = await createTestMeter(adminClient, organization, property2, resource, {})
142147
await createTestMeterReading(adminClient, meter2, source)
@@ -170,6 +175,65 @@ describe('DeleteMeterAndMeterReadingsService', () => {
170175
expect(deletedMeters[0].id).toBe(meter2.id)
171176
})
172177

178+
test('Meters should be deleted only if meter resource is specified in "resourcesIds"', async () => {
179+
const [resource2] = await MeterResource.getAll(adminClient, { id: HOT_WATER_METER_RESOURCE_ID })
180+
const [meter2] = await createTestMeter(adminClient, organization, property, resource2, {})
181+
await createTestMeterReading(adminClient, meter2, source)
182+
183+
const [result] = await _internalDeleteMeterAndMeterReadingsByTestClient(adminClient, {
184+
...payload,
185+
resourcesIds: [resource.id],
186+
})
187+
expect(result).toEqual(expect.objectContaining({
188+
status: 'success',
189+
metersToDelete: 1,
190+
deletedMeters: 1,
191+
}))
192+
const meters = await Meter.getAll(adminClient, { id_in: [meter.id, meter2.id] })
193+
expect(meters).toHaveLength(1)
194+
expect(meters[0].id).toBe(meter2.id)
195+
})
196+
197+
test('Meters should be deleted only if meter resource is specified in "resourcesIds" and property is specified in "propertyIds"', async () => {
198+
const [resource2] = await MeterResource.getAll(adminClient, { id: HOT_WATER_METER_RESOURCE_ID })
199+
const [meter2] = await createTestMeter(adminClient, organization, property, resource2, {})
200+
await createTestMeterReading(adminClient, meter2, source)
201+
202+
const [property2] = await createTestProperty(adminClient, organization)
203+
const [meter3] = await createTestMeter(adminClient, organization, property2, resource2, {})
204+
await createTestMeterReading(adminClient, meter3, source)
205+
206+
// Be sure that no meters will be deleted if no meters contains passed property and resource
207+
const [result1] = await _internalDeleteMeterAndMeterReadingsByTestClient(adminClient, {
208+
...payload,
209+
propertyIds: [property2.id],
210+
resourcesIds: [resource.id],
211+
})
212+
expect(result1).toEqual(expect.objectContaining({
213+
status: 'success',
214+
metersToDelete: 0,
215+
deletedMeters: 0,
216+
}))
217+
218+
// Be sure that we delete only one meter with both: property and resource
219+
const [result2] = await _internalDeleteMeterAndMeterReadingsByTestClient(adminClient, {
220+
...payload,
221+
propertyIds: [property.id],
222+
resourcesIds: [resource2.id],
223+
})
224+
expect(result2).toEqual(expect.objectContaining({
225+
status: 'success',
226+
metersToDelete: 1,
227+
deletedMeters: 1,
228+
}))
229+
230+
const meters = await Meter.getAll(adminClient, { id_in: [meter.id, meter2.id, meter3.id] })
231+
expect(meters).toEqual([
232+
expect.objectContaining({ id: meter.id }),
233+
expect.objectContaining({ id: meter3.id }),
234+
])
235+
})
236+
173237
test('Should delete a lot of meters', async () => {
174238
const createdMetersIds = [meter.id]
175239

@@ -190,4 +254,4 @@ describe('DeleteMeterAndMeterReadingsService', () => {
190254
expect(deletedMeters).toHaveLength(0)
191255
})
192256
})
193-
})
257+
})

apps/condo/domains/meter/schema/_internalDeleteMeterReadingsService.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const _internalDeleteMeterReadingsService = new GQLCustomSchema('_internalDelete
6666
types: [
6767
{
6868
access: true,
69-
type: 'input _internalDeleteMeterReadingsInput { dv: Int!, sender: SenderFieldInput!, propertyIds: [ID], organizationId: ID!, startDateTime: String!, endDateTime: String! }',
69+
type: 'input _internalDeleteMeterReadingsInput { dv: Int!, sender: SenderFieldInput!, propertyIds: [ID], resourcesIds: [ID], organizationId: ID!, startDateTime: String!, endDateTime: String! }',
7070
},
7171
{
7272
access: true,
@@ -77,7 +77,7 @@ const _internalDeleteMeterReadingsService = new GQLCustomSchema('_internalDelete
7777
type: 'type _internalDeleteMeterReadingsOutput { status: Status!, toDelete: Int!, deleted: Int! }',
7878
},
7979
],
80-
80+
8181
mutations: [
8282
{
8383
access: access.canInternalDeleteMeterReadings,
@@ -95,6 +95,7 @@ const _internalDeleteMeterReadingsService = new GQLCustomSchema('_internalDelete
9595
dv,
9696
sender,
9797
propertyIds,
98+
resourcesIds,
9899
organizationId,
99100
startDateTime: startDateTimeFromInput,
100101
endDateTime: endDateTimeFromInput,
@@ -118,6 +119,7 @@ const _internalDeleteMeterReadingsService = new GQLCustomSchema('_internalDelete
118119
createdAt_lte: dayjs(endDateTime).endOf('s').toISOString(),
119120
meter: {
120121
...(isArray(propertyIds) ? { property: { id_in: propertyIds } } : undefined),
122+
...(isArray(resourcesIds) ? { resource: { id_in: resourcesIds } } : undefined),
121123
organization: { id: organizationId },
122124
deletedAt: null,
123125
},
@@ -194,7 +196,7 @@ const _internalDeleteMeterReadingsService = new GQLCustomSchema('_internalDelete
194196
},
195197
},
196198
],
197-
199+
198200
})
199201

200202
module.exports = {

apps/condo/domains/meter/schema/_internalDeleteMeterReadingsService.test.js

+79-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const { expectToThrowAuthenticationErrorToResult } = require('@open-condo/keysto
1616
const { sleep } = require('@condo/domains/common/utils/sleep')
1717
const {
1818
COLD_WATER_METER_RESOURCE_ID,
19+
HOT_WATER_METER_RESOURCE_ID,
1920
METER_READING_SOURCE_INTERNAL_IMPORT_TYPE,
2021
METER_READING_SOURCE_CRM_TYPE,
2122
METER_READING_SOURCE_MOBILE_RESIDENT_APP_TYPE,
@@ -205,7 +206,7 @@ describe('_internalDeleteMeterReadingsService', () => {
205206
})
206207

207208
describe('Basic logic', () => {
208-
test('Readings for all properties in organization should be deleted if the "propertyIds" is not specified', async () => {
209+
test('Readings for all properties in organization should be deleted if no "propertyIds" and "resourcesIds" specified', async () => {
209210
const {
210211
organization: organization2,
211212
property: property2_1,
@@ -259,6 +260,83 @@ describe('_internalDeleteMeterReadingsService', () => {
259260
expect(readings[0].id).toBe(meterReading.id)
260261
})
261262

263+
test('Readings should be deleted only for resources that were specified in "resourcesIds"', async () => {
264+
const [resource2] = await MeterResource.getAll(admin, { id: HOT_WATER_METER_RESOURCE_ID })
265+
const [meter2] = await createTestMeter(admin, organization, property, resource2, {})
266+
const [meterReading2] = await createTestMeterReading(admin, meter2, condoImportSource)
267+
const [meterReading3] = await createTestMeterReading(admin, meter2, condoImportSource, { value1: meterReading2.value1 })
268+
269+
const [result] = await _internalDeleteMeterReadingsByTestClient(support, {
270+
...payload,
271+
resourcesIds: [resource2.id],
272+
endDateTime: dayjs().format(DATE_FORMAT),
273+
})
274+
expect(result).toEqual(expect.objectContaining({
275+
status: 'success',
276+
toDelete: 2,
277+
deleted: 2,
278+
}))
279+
const readings = await MeterReading.getAll(admin, {
280+
id_in: [meterReading.id, meterReading2.id, meterReading3.id],
281+
deletedAt: null,
282+
})
283+
expect(readings).toHaveLength(1)
284+
expect(readings[0].id).toBe(meterReading.id)
285+
})
286+
287+
test('Readings should be deleted only in properties that were specified in "propertyIds" and for resources that were specified in "resourcesIds"', async () => {
288+
const [property2] = await createTestProperty(admin, organization)
289+
const [resource2] = await MeterResource.getAll(admin, { id: HOT_WATER_METER_RESOURCE_ID })
290+
const [meter2] = await createTestMeter(admin, organization, property2, resource2, {})
291+
const [meterReading2] = await createTestMeterReading(admin, meter2, condoImportSource)
292+
const [meterReading3] = await createTestMeterReading(admin, meter2, condoImportSource, { value1: meterReading2.value1 })
293+
294+
// Be sure that we delete nothing if no meters contains passed property and resource
295+
const [result1] = await _internalDeleteMeterReadingsByTestClient(support, {
296+
...payload,
297+
propertyIds: [property.id],
298+
resourcesIds: [resource2.id],
299+
endDateTime: dayjs().format(DATE_FORMAT),
300+
})
301+
expect(result1).toEqual(expect.objectContaining({
302+
status: 'success',
303+
toDelete: 0,
304+
deleted: 0,
305+
}))
306+
307+
const [result2] = await _internalDeleteMeterReadingsByTestClient(support, {
308+
...payload,
309+
propertyIds: [property2.id],
310+
resourcesIds: [resource.id],
311+
endDateTime: dayjs().format(DATE_FORMAT),
312+
})
313+
expect(result2).toEqual(expect.objectContaining({
314+
status: 'success',
315+
toDelete: 0,
316+
deleted: 0,
317+
}))
318+
319+
// Be sure that we delete only meter readings for meters with both: property and resource
320+
const [result3] = await _internalDeleteMeterReadingsByTestClient(support, {
321+
...payload,
322+
propertyIds: [property2.id],
323+
resourcesIds: [resource2.id],
324+
endDateTime: dayjs().format(DATE_FORMAT),
325+
})
326+
expect(result3).toEqual(expect.objectContaining({
327+
status: 'success',
328+
toDelete: 2,
329+
deleted: 2,
330+
}))
331+
332+
const readings = await MeterReading.getAll(admin, {
333+
id_in: [meterReading.id, meterReading2.id, meterReading3.id],
334+
deletedAt: null,
335+
})
336+
expect(readings).toHaveLength(1)
337+
expect(readings[0].id).toBe(meterReading.id)
338+
})
339+
262340
test('Readings only for specified period should be deleted', async () => {
263341
await sleep(1200)
264342
const startDateTime = dayjs().format(DATE_FORMAT)

apps/condo/schema.graphql

+2
Original file line numberDiff line numberDiff line change
@@ -80793,6 +80793,7 @@ input _internalDeleteMeterAndMeterReadingsInput {
8079380793
sender: SenderFieldInput!
8079480794
propertyIds: [ID]
8079580795
organizationId: ID!
80796+
resourcesIds: [ID]
8079680797
}
8079780798

8079880799
enum Status {
@@ -80810,6 +80811,7 @@ input _internalDeleteMeterReadingsInput {
8081080811
dv: Int!
8081180812
sender: SenderFieldInput!
8081280813
propertyIds: [ID]
80814+
resourcesIds: [ID]
8081380815
organizationId: ID!
8081480816
startDateTime: String!
8081580817
endDateTime: String!

apps/condo/schema.ts

+2
Original file line numberDiff line numberDiff line change
@@ -103538,6 +103538,7 @@ export type _InternalDeleteMeterAndMeterReadingsInput = {
103538103538
dv: Scalars['Int']['input'];
103539103539
organizationId: Scalars['ID']['input'];
103540103540
propertyIds?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>>;
103541+
resourcesIds?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>>;
103541103542
sender: SenderFieldInput;
103542103543
};
103543103544

@@ -103553,6 +103554,7 @@ export type _InternalDeleteMeterReadingsInput = {
103553103554
endDateTime: Scalars['String']['input'];
103554103555
organizationId: Scalars['ID']['input'];
103555103556
propertyIds?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>>;
103557+
resourcesIds?: InputMaybe<Array<InputMaybe<Scalars['ID']['input']>>>;
103556103558
sender: SenderFieldInput;
103557103559
startDateTime: Scalars['String']['input'];
103558103560
};

0 commit comments

Comments
 (0)