@defra-fish/recurring-payments-job 1.58.0-rc.1 → 1.58.0-rc.11
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/recurring-payments-job",
|
|
3
|
-
"version": "1.58.0-rc.
|
|
3
|
+
"version": "1.58.0-rc.11",
|
|
4
4
|
"description": "Rod Licensing Recurring Payments Job",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@defra-fish/business-rules-lib": "1.58.0-rc.
|
|
40
|
-
"@defra-fish/connectors-lib": "1.58.0-rc.
|
|
39
|
+
"@defra-fish/business-rules-lib": "1.58.0-rc.11",
|
|
40
|
+
"@defra-fish/connectors-lib": "1.58.0-rc.11",
|
|
41
41
|
"commander": "^7.2.0",
|
|
42
42
|
"moment-timezone": "^0.5.34"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "07d834ede6126348ee4073360e20fbddac50041c"
|
|
45
45
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { salesApi } from '@defra-fish/connectors-lib'
|
|
2
2
|
import { processRecurringPayments } from '../recurring-payments-processor.js'
|
|
3
|
+
import { sendPayment } from '../services/govuk-pay-service.js'
|
|
3
4
|
|
|
4
5
|
jest.mock('@defra-fish/business-rules-lib')
|
|
5
6
|
jest.mock('@defra-fish/connectors-lib', () => ({
|
|
@@ -8,9 +9,12 @@ jest.mock('@defra-fish/connectors-lib', () => ({
|
|
|
8
9
|
preparePermissionDataForRenewal: jest.fn(() => ({
|
|
9
10
|
licensee: { countryCode: 'GB-ENG' }
|
|
10
11
|
})),
|
|
11
|
-
createTransaction: jest.fn()
|
|
12
|
+
createTransaction: jest.fn(() => ({
|
|
13
|
+
cost: 30
|
|
14
|
+
}))
|
|
12
15
|
}
|
|
13
16
|
}))
|
|
17
|
+
jest.mock('../services/govuk-pay-service.js')
|
|
14
18
|
|
|
15
19
|
describe('recurring-payments-processor', () => {
|
|
16
20
|
beforeEach(() => {
|
|
@@ -53,7 +57,7 @@ describe('recurring-payments-processor', () => {
|
|
|
53
57
|
|
|
54
58
|
it('prepares the data for found recurring payments', async () => {
|
|
55
59
|
const referenceNumber = Symbol('reference')
|
|
56
|
-
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
60
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment(referenceNumber)])
|
|
57
61
|
|
|
58
62
|
await processRecurringPayments()
|
|
59
63
|
|
|
@@ -61,7 +65,7 @@ describe('recurring-payments-processor', () => {
|
|
|
61
65
|
})
|
|
62
66
|
|
|
63
67
|
it('creates a transaction with the correct data', async () => {
|
|
64
|
-
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
68
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
|
|
65
69
|
|
|
66
70
|
const isLicenceForYou = Symbol('isLicenceForYou')
|
|
67
71
|
const isRenewal = Symbol('isRenewal')
|
|
@@ -108,7 +112,7 @@ describe('recurring-payments-processor', () => {
|
|
|
108
112
|
})
|
|
109
113
|
|
|
110
114
|
it('strips the concession name returned by preparePermissionDataForRenewal before passing to createTransaction', async () => {
|
|
111
|
-
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
115
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
|
|
112
116
|
|
|
113
117
|
salesApi.preparePermissionDataForRenewal.mockReturnValueOnce({
|
|
114
118
|
licensee: {
|
|
@@ -141,7 +145,7 @@ describe('recurring-payments-processor', () => {
|
|
|
141
145
|
})
|
|
142
146
|
|
|
143
147
|
it('assigns the correct startDate when licenceStartTime is present', async () => {
|
|
144
|
-
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
148
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
|
|
145
149
|
|
|
146
150
|
salesApi.preparePermissionDataForRenewal.mockReturnValueOnce({
|
|
147
151
|
licensee: { countryCode: 'GB-ENG' },
|
|
@@ -159,7 +163,7 @@ describe('recurring-payments-processor', () => {
|
|
|
159
163
|
})
|
|
160
164
|
|
|
161
165
|
it('assigns the correct startDate when licenceStartTime is not present', async () => {
|
|
162
|
-
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
166
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
|
|
163
167
|
|
|
164
168
|
salesApi.preparePermissionDataForRenewal.mockReturnValueOnce({
|
|
165
169
|
licensee: { countryCode: 'GB-ENG' },
|
|
@@ -176,7 +180,7 @@ describe('recurring-payments-processor', () => {
|
|
|
176
180
|
})
|
|
177
181
|
|
|
178
182
|
it('raises an error if createTransaction fails', async () => {
|
|
179
|
-
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
183
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
|
|
180
184
|
const error = 'Wuh-oh!'
|
|
181
185
|
salesApi.createTransaction.mockImplementationOnce(() => {
|
|
182
186
|
throw new Error(error)
|
|
@@ -185,6 +189,34 @@ describe('recurring-payments-processor', () => {
|
|
|
185
189
|
await expect(processRecurringPayments()).rejects.toThrowError(error)
|
|
186
190
|
})
|
|
187
191
|
|
|
192
|
+
it('prepares and sends the payment request', async () => {
|
|
193
|
+
const agreementId = Symbol('agreementId')
|
|
194
|
+
const transactionId = Symbol('transactionId')
|
|
195
|
+
|
|
196
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment('foo', agreementId)])
|
|
197
|
+
|
|
198
|
+
salesApi.preparePermissionDataForRenewal.mockReturnValueOnce({
|
|
199
|
+
licensee: { countryCode: 'GB-ENG' }
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
salesApi.createTransaction.mockReturnValueOnce({
|
|
203
|
+
cost: 50,
|
|
204
|
+
id: transactionId
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
const expectedData = {
|
|
208
|
+
amount: 5000,
|
|
209
|
+
description: 'The recurring card payment for your rod fishing licence',
|
|
210
|
+
reference: transactionId,
|
|
211
|
+
authorisation_mode: 'agreement',
|
|
212
|
+
agreement_id: agreementId
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
await processRecurringPayments()
|
|
216
|
+
|
|
217
|
+
expect(sendPayment).toHaveBeenCalledWith(expectedData)
|
|
218
|
+
})
|
|
219
|
+
|
|
188
220
|
describe.each([2, 3, 10])('if there are %d recurring payments', count => {
|
|
189
221
|
it('prepares the data for each one', async () => {
|
|
190
222
|
const references = []
|
|
@@ -194,7 +226,7 @@ describe('recurring-payments-processor', () => {
|
|
|
194
226
|
|
|
195
227
|
const mockGetDueRecurringPayments = []
|
|
196
228
|
references.forEach(reference => {
|
|
197
|
-
mockGetDueRecurringPayments.push(
|
|
229
|
+
mockGetDueRecurringPayments.push(getMockDueRecurringPayment(reference))
|
|
198
230
|
})
|
|
199
231
|
salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
|
|
200
232
|
|
|
@@ -211,7 +243,7 @@ describe('recurring-payments-processor', () => {
|
|
|
211
243
|
it('creates a transaction for each one', async () => {
|
|
212
244
|
const mockGetDueRecurringPayments = []
|
|
213
245
|
for (let i = 0; i < count; i++) {
|
|
214
|
-
mockGetDueRecurringPayments.push(
|
|
246
|
+
mockGetDueRecurringPayments.push(getMockDueRecurringPayment(i))
|
|
215
247
|
}
|
|
216
248
|
salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
|
|
217
249
|
|
|
@@ -241,5 +273,53 @@ describe('recurring-payments-processor', () => {
|
|
|
241
273
|
|
|
242
274
|
expect(salesApi.createTransaction.mock.calls).toEqual(expectedData)
|
|
243
275
|
})
|
|
276
|
+
|
|
277
|
+
it('sends a payment for each one', async () => {
|
|
278
|
+
const mockGetDueRecurringPayments = []
|
|
279
|
+
const agreementIds = []
|
|
280
|
+
for (let i = 0; i < count; i++) {
|
|
281
|
+
const agreementId = Symbol(`agreementId${1}`)
|
|
282
|
+
agreementIds.push(agreementId)
|
|
283
|
+
mockGetDueRecurringPayments.push(getMockDueRecurringPayment(i, agreementId))
|
|
284
|
+
}
|
|
285
|
+
salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
|
|
286
|
+
|
|
287
|
+
const permits = []
|
|
288
|
+
for (let i = 0; i < count; i++) {
|
|
289
|
+
permits.push(Symbol(`permit${i}`))
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
permits.forEach((permit, i) => {
|
|
293
|
+
salesApi.preparePermissionDataForRenewal.mockReturnValueOnce({
|
|
294
|
+
licensee: { countryCode: 'GB-ENG' }
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
salesApi.createTransaction.mockReturnValueOnce({
|
|
298
|
+
cost: i,
|
|
299
|
+
id: permit
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
const expectedData = []
|
|
304
|
+
permits.forEach((permit, i) => {
|
|
305
|
+
expectedData.push([
|
|
306
|
+
{
|
|
307
|
+
amount: i * 100,
|
|
308
|
+
description: 'The recurring card payment for your rod fishing licence',
|
|
309
|
+
reference: permit,
|
|
310
|
+
authorisation_mode: 'agreement',
|
|
311
|
+
agreement_id: agreementIds[i]
|
|
312
|
+
}
|
|
313
|
+
])
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
await processRecurringPayments()
|
|
317
|
+
expect(sendPayment.mock.calls).toEqual(expectedData)
|
|
318
|
+
})
|
|
244
319
|
})
|
|
245
320
|
})
|
|
321
|
+
|
|
322
|
+
const getMockDueRecurringPayment = (referenceNumber = '123', agreementId = '456') => ({
|
|
323
|
+
entity: { agreementId },
|
|
324
|
+
expanded: { activePermission: { entity: { referenceNumber } } }
|
|
325
|
+
})
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import moment from 'moment-timezone'
|
|
2
2
|
import { SERVICE_LOCAL_TIME } from '@defra-fish/business-rules-lib'
|
|
3
3
|
import { salesApi } from '@defra-fish/connectors-lib'
|
|
4
|
+
import { sendPayment } from './services/govuk-pay-service.js'
|
|
4
5
|
|
|
5
6
|
export const processRecurringPayments = async () => {
|
|
6
7
|
if (process.env.RUN_RECURRING_PAYMENTS?.toLowerCase() === 'true') {
|
|
@@ -16,17 +17,30 @@ export const processRecurringPayments = async () => {
|
|
|
16
17
|
|
|
17
18
|
const processRecurringPayment = async record => {
|
|
18
19
|
const referenceNumber = record.expanded.activePermission.entity.referenceNumber
|
|
20
|
+
const agreementId = record.entity.agreementId
|
|
21
|
+
const transaction = await createNewTransaction(referenceNumber)
|
|
22
|
+
takeRecurringPayment(agreementId, transaction)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const createNewTransaction = async referenceNumber => {
|
|
19
26
|
const transactionData = await processPermissionData(referenceNumber)
|
|
20
27
|
console.log('Creating new transaction based on', referenceNumber)
|
|
21
28
|
try {
|
|
22
29
|
const response = await salesApi.createTransaction(transactionData)
|
|
23
30
|
console.log('New transaction created:', response)
|
|
31
|
+
return response
|
|
24
32
|
} catch (e) {
|
|
25
33
|
console.log('Error creating transaction', JSON.stringify(transactionData))
|
|
26
34
|
throw e
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
|
|
38
|
+
const takeRecurringPayment = (agreementId, transaction) => {
|
|
39
|
+
const preparedPayment = preparePayment(agreementId, transaction)
|
|
40
|
+
console.log('Requesting payment:', preparedPayment)
|
|
41
|
+
sendPayment(preparedPayment)
|
|
42
|
+
}
|
|
43
|
+
|
|
30
44
|
const processPermissionData = async referenceNumber => {
|
|
31
45
|
console.log('Preparing data based on', referenceNumber)
|
|
32
46
|
const data = await salesApi.preparePermissionDataForRenewal(referenceNumber)
|
|
@@ -56,3 +70,15 @@ const prepareStartDate = permission => {
|
|
|
56
70
|
.utc()
|
|
57
71
|
.toISOString()
|
|
58
72
|
}
|
|
73
|
+
|
|
74
|
+
const preparePayment = (agreementId, transaction) => {
|
|
75
|
+
const result = {
|
|
76
|
+
amount: Math.round(transaction.cost * 100),
|
|
77
|
+
description: 'The recurring card payment for your rod fishing licence',
|
|
78
|
+
reference: transaction.id,
|
|
79
|
+
authorisation_mode: 'agreement',
|
|
80
|
+
agreement_id: agreementId
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { sendPayment } from '../govuk-pay-service.js'
|
|
2
|
+
import { govUkPayApi } from '@defra-fish/connectors-lib'
|
|
3
|
+
|
|
4
|
+
jest.mock('@defra-fish/connectors-lib')
|
|
5
|
+
|
|
6
|
+
describe('govuk-pay-service', () => {
|
|
7
|
+
describe('sendPayment', () => {
|
|
8
|
+
it('should send provided payload data to Gov.UK Pay', async () => {
|
|
9
|
+
govUkPayApi.createPayment.mockResolvedValue({
|
|
10
|
+
ok: true,
|
|
11
|
+
json: jest.fn().mockResolvedValue({ success: true, paymentId: 'abc123' })
|
|
12
|
+
})
|
|
13
|
+
const unique = Symbol('payload')
|
|
14
|
+
const payload = {
|
|
15
|
+
amount: '100',
|
|
16
|
+
description: 'The recurring card payment for your rod fishing licence',
|
|
17
|
+
reference: unique
|
|
18
|
+
}
|
|
19
|
+
await sendPayment(payload)
|
|
20
|
+
expect(govUkPayApi.createPayment).toHaveBeenCalledWith(payload, true)
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
})
|