@defra-fish/sales-api-service 1.61.0-rc.1 → 1.61.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/services/__tests__/recurring-payments.service.spec.js +38 -5
- package/src/services/recurring-payments.service.js +10 -1
- package/src/services/transactions/__tests__/process-transaction-queue.spec.js +63 -4
- package/src/services/transactions/process-transaction-queue.js +12 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/sales-api-service",
|
|
3
|
-
"version": "1.61.0-rc.
|
|
3
|
+
"version": "1.61.0-rc.3",
|
|
4
4
|
"description": "Rod Licensing Sales API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@defra-fish/business-rules-lib": "1.61.0-rc.
|
|
39
|
-
"@defra-fish/connectors-lib": "1.61.0-rc.
|
|
40
|
-
"@defra-fish/dynamics-lib": "1.61.0-rc.
|
|
38
|
+
"@defra-fish/business-rules-lib": "1.61.0-rc.3",
|
|
39
|
+
"@defra-fish/connectors-lib": "1.61.0-rc.3",
|
|
40
|
+
"@defra-fish/dynamics-lib": "1.61.0-rc.3",
|
|
41
41
|
"@hapi/boom": "^9.1.2",
|
|
42
42
|
"@hapi/hapi": "^20.1.3",
|
|
43
43
|
"@hapi/inert": "^6.0.3",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"moment-timezone": "^0.5.34",
|
|
53
53
|
"uuid": "^8.3.2"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "49154a3c32f975fcf44b17a9a04f0c4e30f6e67d"
|
|
56
56
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { findDueRecurringPayments, Permission } from '@defra-fish/dynamics-lib'
|
|
1
|
+
import { executeQuery, findDueRecurringPayments, findRecurringPaymentsByAgreementId, Permission } from '@defra-fish/dynamics-lib'
|
|
2
2
|
import {
|
|
3
3
|
getRecurringPayments,
|
|
4
4
|
processRecurringPayment,
|
|
5
5
|
generateRecurringPaymentRecord,
|
|
6
|
-
processRPResult
|
|
6
|
+
processRPResult,
|
|
7
|
+
findNewestExistingRecurringPaymentInCrm
|
|
7
8
|
} from '../recurring-payments.service.js'
|
|
8
9
|
import { calculateEndDate, generatePermissionNumber } from '../permissions.service.js'
|
|
9
10
|
import { getObfuscatedDob } from '../contacts.service.js'
|
|
@@ -20,7 +21,8 @@ jest.mock('@defra-fish/dynamics-lib', () => ({
|
|
|
20
21
|
...jest.requireActual('@defra-fish/dynamics-lib'),
|
|
21
22
|
executeQuery: jest.fn(),
|
|
22
23
|
findById: jest.fn(),
|
|
23
|
-
findDueRecurringPayments: jest.fn()
|
|
24
|
+
findDueRecurringPayments: jest.fn(),
|
|
25
|
+
findRecurringPaymentsByAgreementId: jest.fn(() => ['foo'])
|
|
24
26
|
}))
|
|
25
27
|
|
|
26
28
|
jest.mock('@defra-fish/connectors-lib', () => {
|
|
@@ -77,7 +79,7 @@ jest.mock('@defra-fish/business-rules-lib', () => ({
|
|
|
77
79
|
|
|
78
80
|
const dynamicsLib = jest.requireMock('@defra-fish/dynamics-lib')
|
|
79
81
|
|
|
80
|
-
const getMockRecurringPayment = () => ({
|
|
82
|
+
const getMockRecurringPayment = (overrides = {}) => ({
|
|
81
83
|
name: 'Test Name',
|
|
82
84
|
nextDueDate: '2019-12-14T00:00:00Z',
|
|
83
85
|
cancelledDate: null,
|
|
@@ -93,7 +95,8 @@ const getMockRecurringPayment = () => ({
|
|
|
93
95
|
activePermission: {
|
|
94
96
|
entity: getMockPermission()
|
|
95
97
|
}
|
|
96
|
-
}
|
|
98
|
+
},
|
|
99
|
+
...overrides
|
|
97
100
|
})
|
|
98
101
|
|
|
99
102
|
const getMockRPContactPermission = (contact, permission) => ({
|
|
@@ -619,4 +622,34 @@ describe('recurring payments service', () => {
|
|
|
619
622
|
})
|
|
620
623
|
})
|
|
621
624
|
})
|
|
625
|
+
|
|
626
|
+
describe('findNewestExistingRecurringPaymentInCrm', () => {
|
|
627
|
+
it('should call executeQuery with findRecurringPaymentsByAgreementId and the provided agreementId', async () => {
|
|
628
|
+
const agreementId = 'abc123'
|
|
629
|
+
await findNewestExistingRecurringPaymentInCrm(agreementId)
|
|
630
|
+
expect(executeQuery).toHaveBeenCalledWith(findRecurringPaymentsByAgreementId(agreementId))
|
|
631
|
+
})
|
|
632
|
+
|
|
633
|
+
it('should return a RecurringPayment record when there is one match', async () => {
|
|
634
|
+
const onlyRecord = getMockRecurringPayment()
|
|
635
|
+
dynamicsLib.executeQuery.mockReturnValueOnce([onlyRecord])
|
|
636
|
+
const returnedRecord = await findNewestExistingRecurringPaymentInCrm('agreementId')
|
|
637
|
+
expect(returnedRecord).toBe(onlyRecord)
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
it('should return the RecurringPayment record with the latest endDate when there are multiple matches', async () => {
|
|
641
|
+
const oldestRecord = getMockRecurringPayment({ endDate: '2021-12-15T00:00:00Z' })
|
|
642
|
+
const newestRecord = getMockRecurringPayment({ endDate: '2023-12-15T00:00:00Z' })
|
|
643
|
+
const middlestRecord = getMockRecurringPayment({ endDate: '2022-12-15T00:00:00Z' })
|
|
644
|
+
dynamicsLib.executeQuery.mockReturnValueOnce([oldestRecord, newestRecord, middlestRecord])
|
|
645
|
+
const returnedRecord = await findNewestExistingRecurringPaymentInCrm('agreementId')
|
|
646
|
+
expect(returnedRecord).toBe(newestRecord)
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
it('should return false when there are no matches', async () => {
|
|
650
|
+
dynamicsLib.executeQuery.mockReturnValueOnce([])
|
|
651
|
+
const returnedRecord = await findNewestExistingRecurringPaymentInCrm('agreementId')
|
|
652
|
+
expect(returnedRecord).toBe(false)
|
|
653
|
+
})
|
|
654
|
+
})
|
|
622
655
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { executeQuery, findDueRecurringPayments, RecurringPayment } from '@defra-fish/dynamics-lib'
|
|
1
|
+
import { executeQuery, findDueRecurringPayments, findRecurringPaymentsByAgreementId, RecurringPayment } from '@defra-fish/dynamics-lib'
|
|
2
2
|
import { calculateEndDate, generatePermissionNumber } from './permissions.service.js'
|
|
3
3
|
import { getObfuscatedDob } from './contacts.service.js'
|
|
4
4
|
import { createHash } from 'node:crypto'
|
|
@@ -126,3 +126,12 @@ export const processRPResult = async (transactionId, paymentId, createdDate) =>
|
|
|
126
126
|
|
|
127
127
|
return { permission }
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
export const findNewestExistingRecurringPaymentInCrm = async agreementId => {
|
|
131
|
+
const matchingRecords = await executeQuery(findRecurringPaymentsByAgreementId(agreementId))
|
|
132
|
+
if (matchingRecords?.length) {
|
|
133
|
+
return [...matchingRecords].sort((a, b) => a.endDate.localeCompare(b.endDate)).pop()
|
|
134
|
+
} else {
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
FulfilmentRequest,
|
|
8
8
|
Permission,
|
|
9
9
|
PoclFile,
|
|
10
|
+
RecurringPayment,
|
|
10
11
|
RecurringPaymentInstruction,
|
|
11
12
|
Transaction,
|
|
12
|
-
TransactionJournal
|
|
13
|
-
RecurringPayment
|
|
13
|
+
TransactionJournal
|
|
14
14
|
} from '@defra-fish/dynamics-lib'
|
|
15
15
|
import {
|
|
16
16
|
mockFinalisedTransactionRecord,
|
|
@@ -26,7 +26,11 @@ import { TRANSACTION_STAGING_TABLE, TRANSACTION_STAGING_HISTORY_TABLE } from '..
|
|
|
26
26
|
import AwsMock from 'aws-sdk'
|
|
27
27
|
import { POCL_DATA_SOURCE, DDE_DATA_SOURCE } from '@defra-fish/business-rules-lib'
|
|
28
28
|
import moment from 'moment'
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
findNewestExistingRecurringPaymentInCrm,
|
|
31
|
+
processRecurringPayment,
|
|
32
|
+
generateRecurringPaymentRecord
|
|
33
|
+
} from '../../recurring-payments.service.js'
|
|
30
34
|
|
|
31
35
|
jest.mock('../../reference-data.service.js', () => ({
|
|
32
36
|
...jest.requireActual('../../reference-data.service.js'),
|
|
@@ -65,7 +69,11 @@ jest.mock('@defra-fish/business-rules-lib', () => ({
|
|
|
65
69
|
START_AFTER_PAYMENT_MINUTES: 30
|
|
66
70
|
}))
|
|
67
71
|
|
|
68
|
-
jest.mock('../../recurring-payments.service.js')
|
|
72
|
+
jest.mock('../../recurring-payments.service.js', () => ({
|
|
73
|
+
findNewestExistingRecurringPaymentInCrm: jest.fn(),
|
|
74
|
+
generateRecurringPaymentRecord: jest.fn(),
|
|
75
|
+
processRecurringPayment: jest.fn()
|
|
76
|
+
}))
|
|
69
77
|
|
|
70
78
|
describe('transaction service', () => {
|
|
71
79
|
beforeAll(() => {
|
|
@@ -410,6 +418,57 @@ describe('transaction service', () => {
|
|
|
410
418
|
await processQueue({ id: finalisedTransaction.id })
|
|
411
419
|
expect(processRecurringPayment).toHaveBeenCalledWith(rprSymbol, expect.any(Contact))
|
|
412
420
|
})
|
|
421
|
+
|
|
422
|
+
it('checks for existing recurring payments with the same agreementId', async () => {
|
|
423
|
+
const agreementId = Symbol('agreementId')
|
|
424
|
+
const mockRecurringPayment = { agreementId }
|
|
425
|
+
const finalisedTransaction = mockFinalisedTransactionRecord()
|
|
426
|
+
processRecurringPayment.mockResolvedValueOnce({ recurringPayment: mockRecurringPayment })
|
|
427
|
+
AwsMock.DynamoDB.DocumentClient.__setResponse('get', { Item: finalisedTransaction })
|
|
428
|
+
|
|
429
|
+
await processQueue({ id: finalisedTransaction.id })
|
|
430
|
+
|
|
431
|
+
expect(findNewestExistingRecurringPaymentInCrm).toHaveBeenCalledWith(agreementId)
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
it("assigns the new RecurringPayment as the existing RecurringPayment's nextRecurringPayment", async () => {
|
|
435
|
+
const agreementId = Symbol('agreementId')
|
|
436
|
+
const mockRecurringPayment = { agreementId }
|
|
437
|
+
const mockExistingRecurringPayment = { bindToEntity: jest.fn() }
|
|
438
|
+
const finalisedTransaction = mockFinalisedTransactionRecord()
|
|
439
|
+
processRecurringPayment.mockResolvedValueOnce({ recurringPayment: mockRecurringPayment })
|
|
440
|
+
AwsMock.DynamoDB.DocumentClient.__setResponse('get', { Item: finalisedTransaction })
|
|
441
|
+
findNewestExistingRecurringPaymentInCrm.mockReturnValueOnce(mockExistingRecurringPayment)
|
|
442
|
+
|
|
443
|
+
await processQueue({ id: finalisedTransaction.id })
|
|
444
|
+
|
|
445
|
+
expect(mockExistingRecurringPayment.bindToEntity).toHaveBeenCalledWith(
|
|
446
|
+
RecurringPayment.definition.relationships.nextRecurringPayment,
|
|
447
|
+
mockRecurringPayment
|
|
448
|
+
)
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
it('does not attempt to update multiple recurring payment entities if no pre-existing recurring payment is found', async () => {
|
|
452
|
+
const agreementId = Symbol('agreementId')
|
|
453
|
+
const mockRecurringPayment = { agreementId }
|
|
454
|
+
const finalisedTransaction = mockFinalisedTransactionRecord()
|
|
455
|
+
processRecurringPayment.mockResolvedValueOnce({ recurringPayment: mockRecurringPayment })
|
|
456
|
+
AwsMock.DynamoDB.DocumentClient.__setResponse('get', { Item: finalisedTransaction })
|
|
457
|
+
findNewestExistingRecurringPaymentInCrm.mockReturnValueOnce(false)
|
|
458
|
+
|
|
459
|
+
await processQueue({ id: finalisedTransaction.id })
|
|
460
|
+
|
|
461
|
+
expect(persist.mock.calls[0][0]).toEqual([
|
|
462
|
+
expect.objectContaining({ referenceNumber: finalisedTransaction.id }),
|
|
463
|
+
expect.objectContaining({ referenceNumber: finalisedTransaction.id }),
|
|
464
|
+
expect.objectContaining({ referenceNumber: finalisedTransaction.id }),
|
|
465
|
+
expect.objectContaining({ firstName: finalisedTransaction.permissions[0].licensee.firstName }),
|
|
466
|
+
expect.objectContaining({ referenceNumber: finalisedTransaction.permissions[0].referenceNumber }),
|
|
467
|
+
expect.objectContaining({ agreementId }),
|
|
468
|
+
expect.objectContaining({}),
|
|
469
|
+
expect.objectContaining({ referenceNumber: finalisedTransaction.permissions[0].concessions[0].proof.referenceNumber })
|
|
470
|
+
])
|
|
471
|
+
})
|
|
413
472
|
})
|
|
414
473
|
})
|
|
415
474
|
|
|
@@ -8,11 +8,16 @@ import {
|
|
|
8
8
|
Transaction,
|
|
9
9
|
TransactionCurrency,
|
|
10
10
|
TransactionJournal,
|
|
11
|
+
RecurringPayment,
|
|
11
12
|
RecurringPaymentInstruction
|
|
12
13
|
} from '@defra-fish/dynamics-lib'
|
|
13
14
|
import { DDE_DATA_SOURCE, FULFILMENT_SWITCHOVER_DATE, POCL_TRANSACTION_SOURCES } from '@defra-fish/business-rules-lib'
|
|
14
15
|
import { getReferenceDataForEntityAndId, getGlobalOptionSetValue, getReferenceDataForEntity } from '../reference-data.service.js'
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
findNewestExistingRecurringPaymentInCrm,
|
|
18
|
+
generateRecurringPaymentRecord,
|
|
19
|
+
processRecurringPayment
|
|
20
|
+
} from '../recurring-payments.service.js'
|
|
16
21
|
import { resolveContactPayload } from '../contacts.service.js'
|
|
17
22
|
import { retrieveStagedTransaction } from './retrieve-transaction.js'
|
|
18
23
|
import { TRANSACTION_STAGING_TABLE, TRANSACTION_STAGING_HISTORY_TABLE } from '../../config.js'
|
|
@@ -82,6 +87,12 @@ export async function processQueue ({ id }) {
|
|
|
82
87
|
paymentInstruction.bindToEntity(RecurringPaymentInstruction.definition.relationships.permit, permit)
|
|
83
88
|
paymentInstruction.bindToEntity(RecurringPaymentInstruction.definition.relationships.recurringPayment, recurringPayment)
|
|
84
89
|
entities.push(paymentInstruction)
|
|
90
|
+
|
|
91
|
+
const existingRecurringPayment = await findNewestExistingRecurringPaymentInCrm(recurringPayment.agreementId)
|
|
92
|
+
if (existingRecurringPayment) {
|
|
93
|
+
existingRecurringPayment.bindToEntity(RecurringPayment.definition.relationships.nextRecurringPayment, recurringPayment)
|
|
94
|
+
entities.push(existingRecurringPayment)
|
|
95
|
+
}
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
for (const concession of concessions || []) {
|