@defra-fish/sales-api-service 1.77.0-rc.9 → 1.78.0-rc.0
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/sales-api-service",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.78.0-rc.0",
|
|
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.
|
|
39
|
-
"@defra-fish/connectors-lib": "1.
|
|
40
|
-
"@defra-fish/dynamics-lib": "1.
|
|
38
|
+
"@defra-fish/business-rules-lib": "1.78.0-rc.0",
|
|
39
|
+
"@defra-fish/connectors-lib": "1.78.0-rc.0",
|
|
40
|
+
"@defra-fish/dynamics-lib": "1.78.0-rc.0",
|
|
41
41
|
"@hapi/boom": "9.1.2",
|
|
42
42
|
"@hapi/hapi": "20.1.3",
|
|
43
43
|
"@hapi/inert": "6.0.3",
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
"moment-timezone": "0.5.34",
|
|
54
54
|
"uuid": "8.3.2"
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "ba58b90ce215474827f38d37d844937adf10f2e6"
|
|
57
57
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import db from 'debug'
|
|
1
2
|
import { processQueue, getTransactionJournalRefNumber } from '../process-transaction-queue.js'
|
|
2
3
|
import {
|
|
3
4
|
persist,
|
|
@@ -27,8 +28,12 @@ import {
|
|
|
27
28
|
generateRecurringPaymentRecord,
|
|
28
29
|
findNewestExistingRecurringPaymentInCrm
|
|
29
30
|
} from '../../recurring-payments.service.js'
|
|
31
|
+
import { retrieveStagedTransaction } from '../retrieve-transaction.js'
|
|
30
32
|
import { AWS } from '@defra-fish/connectors-lib'
|
|
31
33
|
const { docClient } = AWS.mock.results[0].value
|
|
34
|
+
const { value: debug } = db.mock.results[db.mock.calls.findIndex(c => c[0] === 'sales:transactions')]
|
|
35
|
+
|
|
36
|
+
jest.mock('debug', () => jest.fn(() => jest.fn()))
|
|
32
37
|
|
|
33
38
|
jest.mock('../../reference-data.service.js', () => ({
|
|
34
39
|
...jest.requireActual('../../reference-data.service.js'),
|
|
@@ -72,6 +77,10 @@ jest.mock('../../recurring-payments.service.js', () => ({
|
|
|
72
77
|
processRecurringPayment: jest.fn()
|
|
73
78
|
}))
|
|
74
79
|
|
|
80
|
+
jest.mock('../retrieve-transaction.js', () => ({
|
|
81
|
+
retrieveStagedTransaction: jest.fn()
|
|
82
|
+
}))
|
|
83
|
+
|
|
75
84
|
jest.mock('@defra-fish/connectors-lib', () => {
|
|
76
85
|
const mockAWS = {
|
|
77
86
|
docClient: {
|
|
@@ -204,17 +213,11 @@ describe('transaction service', () => {
|
|
|
204
213
|
]
|
|
205
214
|
])('handles %s', async (description, initialiseMockTransactionRecord, entityExpectations) => {
|
|
206
215
|
const mockRecord = initialiseMockTransactionRecord()
|
|
207
|
-
|
|
216
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
208
217
|
const result = await processQueue({ id: mockRecord.id })
|
|
209
218
|
expect(result).toBeUndefined()
|
|
210
219
|
expect(persist).toBeCalledWith(entityExpectations, undefined)
|
|
211
|
-
expect(
|
|
212
|
-
expect.objectContaining({
|
|
213
|
-
TableName: TRANSACTION_STAGING_TABLE.TableName,
|
|
214
|
-
Key: { id: mockRecord.id },
|
|
215
|
-
ConsistentRead: true
|
|
216
|
-
})
|
|
217
|
-
)
|
|
220
|
+
expect(retrieveStagedTransaction).toHaveBeenCalledWith(mockRecord.id)
|
|
218
221
|
expect(docClient.delete).toHaveBeenCalledWith(
|
|
219
222
|
expect.objectContaining({
|
|
220
223
|
TableName: TRANSACTION_STAGING_TABLE.TableName,
|
|
@@ -248,7 +251,7 @@ describe('transaction service', () => {
|
|
|
248
251
|
it('includes a FulfilmentRequest when the permit and contact are for postal fulfilment', async () => {
|
|
249
252
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
250
253
|
mockRecord.permissions[0].permitId = MOCK_12MONTH_SENIOR_PERMIT.id
|
|
251
|
-
|
|
254
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
252
255
|
await processQueue({ id: mockRecord.id })
|
|
253
256
|
expect(persist).toBeCalledWith(
|
|
254
257
|
[
|
|
@@ -267,7 +270,7 @@ describe('transaction service', () => {
|
|
|
267
270
|
it('does not include a FulfilmentRequest when the permit and contact are not for postal fulfilment', async () => {
|
|
268
271
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
269
272
|
mockRecord.permissions[0].permitId = MOCK_1DAY_SENIOR_PERMIT_ENTITY.id
|
|
270
|
-
|
|
273
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
271
274
|
await processQueue({ id: mockRecord.id })
|
|
272
275
|
expect(persist).toBeCalledWith(
|
|
273
276
|
[
|
|
@@ -295,7 +298,7 @@ describe('transaction service', () => {
|
|
|
295
298
|
it('does not include a FulfilmentRequest when the permit and contact are for postal fulfilment', async () => {
|
|
296
299
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
297
300
|
mockRecord.permissions[0].permitId = MOCK_12MONTH_SENIOR_PERMIT.id
|
|
298
|
-
|
|
301
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
299
302
|
await processQueue({ id: mockRecord.id })
|
|
300
303
|
expect(persist).toBeCalledWith(
|
|
301
304
|
[
|
|
@@ -313,7 +316,7 @@ describe('transaction service', () => {
|
|
|
313
316
|
it('does not include a FulfilmentRequest when the permit and contact are not for postal fulfilment', async () => {
|
|
314
317
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
315
318
|
mockRecord.permissions[0].permitId = MOCK_1DAY_SENIOR_PERMIT_ENTITY.id
|
|
316
|
-
|
|
319
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
317
320
|
await processQueue({ id: mockRecord.id })
|
|
318
321
|
expect(persist).toBeCalledWith(
|
|
319
322
|
[
|
|
@@ -332,7 +335,7 @@ describe('transaction service', () => {
|
|
|
332
335
|
it('sets isLicenceForYou to Yes on the transaction, if it is true on the permission', async () => {
|
|
333
336
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
334
337
|
mockRecord.permissions[0].isLicenceForYou = true
|
|
335
|
-
|
|
338
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
336
339
|
await processQueue({ id: mockRecord.id })
|
|
337
340
|
const persistMockFirstAgument = persist.mock.calls[0]
|
|
338
341
|
expect(persistMockFirstAgument[0][4].isLicenceForYou).toBeDefined()
|
|
@@ -342,7 +345,7 @@ describe('transaction service', () => {
|
|
|
342
345
|
it('sets isLicenceForYou to No on the transaction, if it is false on the permission', async () => {
|
|
343
346
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
344
347
|
mockRecord.permissions[0].isLicenceForYou = false
|
|
345
|
-
|
|
348
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
346
349
|
await processQueue({ id: mockRecord.id })
|
|
347
350
|
const persistMockFirstAgument = persist.mock.calls[0]
|
|
348
351
|
expect(persistMockFirstAgument[0][4].isLicenceForYou).toBeDefined()
|
|
@@ -352,7 +355,7 @@ describe('transaction service', () => {
|
|
|
352
355
|
it('does not set isLicenceForYou on the transaction, if it is undefined on the permission', async () => {
|
|
353
356
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
354
357
|
mockRecord.permissions[0].isLicenceForYou = undefined
|
|
355
|
-
|
|
358
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
356
359
|
await processQueue({ id: mockRecord.id })
|
|
357
360
|
const persistMockFirstAgument = persist.mock.calls[0]
|
|
358
361
|
expect(persistMockFirstAgument[0][4].isLicenceForYou).toBeUndefined()
|
|
@@ -361,7 +364,7 @@ describe('transaction service', () => {
|
|
|
361
364
|
it('does not set isLicenceForYou on the transaction, if it is null on the permission', async () => {
|
|
362
365
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
363
366
|
mockRecord.permissions[0].isLicenceForYou = null
|
|
364
|
-
|
|
367
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
365
368
|
await processQueue({ id: mockRecord.id })
|
|
366
369
|
const persistMockFirstAgument = persist.mock.calls[0]
|
|
367
370
|
expect(persistMockFirstAgument[0][4].isLicenceForYou).toBeUndefined()
|
|
@@ -371,7 +374,7 @@ describe('transaction service', () => {
|
|
|
371
374
|
const transactionFilename = 'test-file.xml'
|
|
372
375
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
373
376
|
mockRecord.transactionFile = transactionFilename
|
|
374
|
-
|
|
377
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
375
378
|
const transactionToFileBindingSpy = jest.spyOn(Transaction.prototype, 'bindToAlternateKey')
|
|
376
379
|
const permissionToFileBindingSpy = jest.spyOn(Permission.prototype, 'bindToAlternateKey')
|
|
377
380
|
await processQueue({ id: mockRecord.id })
|
|
@@ -379,22 +382,141 @@ describe('transaction service', () => {
|
|
|
379
382
|
expect(permissionToFileBindingSpy).toHaveBeenCalledWith(Permission.definition.relationships.poclFile, transactionFilename)
|
|
380
383
|
})
|
|
381
384
|
|
|
382
|
-
it('throws
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
385
|
+
it('throws an error if retrieveStagedTransaction fails', async () => {
|
|
386
|
+
const error = new Error('Boo!')
|
|
387
|
+
retrieveStagedTransaction.mockRejectedValueOnce(error)
|
|
388
|
+
|
|
389
|
+
await expect(processQueue({ id: 'foo' })).rejects.toThrow(error)
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
describe('when persisting throws an error', () => {
|
|
393
|
+
it('throws the error', async () => {
|
|
394
|
+
const transactionFilename = 'test-file.xml'
|
|
395
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
396
|
+
mockRecord.transactionFile = transactionFilename
|
|
397
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
398
|
+
|
|
399
|
+
const error = new Error('I do not like it')
|
|
400
|
+
persist.mockRejectedValueOnce(error)
|
|
401
|
+
|
|
402
|
+
await expect(processQueue({ id: mockRecord.id })).rejects.toThrow(error)
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
it('does not delete the data from the transaction staging table', async () => {
|
|
406
|
+
const transactionFilename = 'test-file.xml'
|
|
407
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
408
|
+
mockRecord.transactionFile = transactionFilename
|
|
409
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
410
|
+
|
|
411
|
+
const error = new Error('I do not like it')
|
|
412
|
+
persist.mockRejectedValueOnce(error)
|
|
413
|
+
|
|
414
|
+
try {
|
|
415
|
+
await processQueue({ id: mockRecord.id })
|
|
416
|
+
} catch (e) {}
|
|
417
|
+
|
|
418
|
+
expect(docClient.delete).not.toHaveBeenCalled()
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
it('does not move the data to the transaction staging history table', async () => {
|
|
422
|
+
const transactionFilename = 'test-file.xml'
|
|
423
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
424
|
+
mockRecord.transactionFile = transactionFilename
|
|
425
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
426
|
+
|
|
427
|
+
const error = new Error('I do not like it')
|
|
428
|
+
persist.mockRejectedValueOnce(error)
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
await processQueue({ id: mockRecord.id })
|
|
432
|
+
} catch (e) {}
|
|
433
|
+
|
|
434
|
+
expect(docClient.put).not.toHaveBeenCalled()
|
|
435
|
+
})
|
|
436
|
+
})
|
|
437
|
+
|
|
438
|
+
describe('when persisting throws an PermissionReferenceNumber_Key error', () => {
|
|
439
|
+
const permissionReferenceKeyError = () => {
|
|
440
|
+
const e = new Error()
|
|
441
|
+
e.error = {
|
|
442
|
+
message:
|
|
443
|
+
'Entity Key PermissionReferenceNumber_Key violated. A record with the same value for Permission Reference Number already exists. A duplicate record cannot be created. Select one or more unique values and try again.'
|
|
444
|
+
}
|
|
445
|
+
return e
|
|
390
446
|
}
|
|
447
|
+
|
|
448
|
+
it('does not throw an error', async () => {
|
|
449
|
+
const transactionFilename = 'test-file.xml'
|
|
450
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
451
|
+
mockRecord.transactionFile = transactionFilename
|
|
452
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
453
|
+
|
|
454
|
+
persist.mockRejectedValueOnce(permissionReferenceKeyError())
|
|
455
|
+
|
|
456
|
+
await expect(processQueue({ id: mockRecord.id })).resolves.not.toThrow()
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
it('logs that the permission has already been persisted', async () => {
|
|
460
|
+
const transactionFilename = 'test-file.xml'
|
|
461
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
462
|
+
mockRecord.transactionFile = transactionFilename
|
|
463
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
464
|
+
|
|
465
|
+
persist.mockRejectedValueOnce(permissionReferenceKeyError())
|
|
466
|
+
|
|
467
|
+
await processQueue({ id: mockRecord.id })
|
|
468
|
+
|
|
469
|
+
expect(debug).toHaveBeenCalledWith('Permission for staging id %s has already been persisted', mockRecord.id)
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
it('deletes the data from the transaction staging table', async () => {
|
|
473
|
+
const transactionFilename = 'test-file.xml'
|
|
474
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
475
|
+
mockRecord.transactionFile = transactionFilename
|
|
476
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
477
|
+
|
|
478
|
+
persist.mockRejectedValueOnce(permissionReferenceKeyError())
|
|
479
|
+
|
|
480
|
+
await processQueue({ id: mockRecord.id })
|
|
481
|
+
|
|
482
|
+
expect(docClient.delete).toHaveBeenCalledWith(
|
|
483
|
+
expect.objectContaining({
|
|
484
|
+
TableName: TRANSACTION_STAGING_TABLE.TableName,
|
|
485
|
+
Key: { id: mockRecord.id }
|
|
486
|
+
})
|
|
487
|
+
)
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
it('moves the data to the transaction staging history table', async () => {
|
|
491
|
+
const transactionFilename = 'test-file.xml'
|
|
492
|
+
const mockRecord = mockFinalisedTransactionRecord()
|
|
493
|
+
mockRecord.transactionFile = transactionFilename
|
|
494
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
495
|
+
|
|
496
|
+
persist.mockRejectedValueOnce(permissionReferenceKeyError())
|
|
497
|
+
|
|
498
|
+
await processQueue({ id: mockRecord.id })
|
|
499
|
+
|
|
500
|
+
const expectedRecord = Object.assign(mockRecord, {
|
|
501
|
+
id: expect.stringMatching(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i),
|
|
502
|
+
expires: expect.any(Number)
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
expect(docClient.put).toHaveBeenCalledWith(
|
|
506
|
+
expect.objectContaining({
|
|
507
|
+
TableName: TRANSACTION_STAGING_HISTORY_TABLE.TableName,
|
|
508
|
+
Item: expectedRecord,
|
|
509
|
+
ConditionExpression: 'attribute_not_exists(id)'
|
|
510
|
+
})
|
|
511
|
+
)
|
|
512
|
+
})
|
|
391
513
|
})
|
|
392
514
|
|
|
393
515
|
describe.each([20, 38.46, 287])('the provisional transaction amount of £%d is used for final transaction amount', cost => {
|
|
394
516
|
const setup = async () => {
|
|
395
517
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
396
518
|
mockRecord.payment.amount = cost
|
|
397
|
-
|
|
519
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
398
520
|
await processQueue({ id: mockRecord.id })
|
|
399
521
|
const {
|
|
400
522
|
mock: {
|
|
@@ -427,7 +549,7 @@ describe('transaction service', () => {
|
|
|
427
549
|
callingArgs.transaction = JSON.parse(JSON.stringify(transaction))
|
|
428
550
|
})
|
|
429
551
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
430
|
-
|
|
552
|
+
retrieveStagedTransaction.mockResolvedValueOnce({ ...mockRecord })
|
|
431
553
|
await processQueue({ id: mockRecord.id })
|
|
432
554
|
// jest.fn args aren't immutable and transaction is changed in processQueue, so we use our clone that hasn't changed
|
|
433
555
|
expect(callingArgs.transaction).toEqual(mockRecord)
|
|
@@ -440,7 +562,7 @@ describe('transaction service', () => {
|
|
|
440
562
|
for (const key of keysToCopy) {
|
|
441
563
|
expectedPermissionData[key] = mockRecord.permissions[0][key]
|
|
442
564
|
}
|
|
443
|
-
|
|
565
|
+
retrieveStagedTransaction.mockResolvedValueOnce(mockRecord)
|
|
444
566
|
|
|
445
567
|
await processQueue({ id: mockRecord.id })
|
|
446
568
|
|
|
@@ -451,7 +573,7 @@ describe('transaction service', () => {
|
|
|
451
573
|
const rprSymbol = Symbol('rpr')
|
|
452
574
|
const finalisedTransaction = mockFinalisedTransactionRecord()
|
|
453
575
|
generateRecurringPaymentRecord.mockReturnValueOnce(rprSymbol)
|
|
454
|
-
|
|
576
|
+
retrieveStagedTransaction.mockResolvedValueOnce(finalisedTransaction)
|
|
455
577
|
await processQueue({ id: finalisedTransaction.id })
|
|
456
578
|
expect(processRecurringPayment).toHaveBeenCalledWith(rprSymbol, expect.any(Contact))
|
|
457
579
|
})
|
|
@@ -464,7 +586,7 @@ describe('transaction service', () => {
|
|
|
464
586
|
const finalisedTransaction = mockFinalisedTransactionRecord()
|
|
465
587
|
findNewestExistingRecurringPaymentInCrm.mockReturnValueOnce(mockExistingRecurringPayment)
|
|
466
588
|
processRecurringPayment.mockReturnValueOnce({ recurringPayment: mockNewRecurringPayment })
|
|
467
|
-
|
|
589
|
+
retrieveStagedTransaction.mockResolvedValueOnce(finalisedTransaction)
|
|
468
590
|
await processQueue({ id: finalisedTransaction.id })
|
|
469
591
|
expect(mockExistingRecurringPayment.bindToEntity).toHaveBeenCalledWith(
|
|
470
592
|
RecurringPayment.definition.relationships.nextRecurringPayment,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Boom from '@hapi/boom'
|
|
2
|
+
import db from 'debug'
|
|
3
|
+
import { retrieveStagedTransaction } from '../retrieve-transaction.js'
|
|
4
|
+
import { TRANSACTION_STAGING_TABLE, TRANSACTION_STAGING_HISTORY_TABLE } from '../../../config.js'
|
|
5
|
+
import { AWS } from '@defra-fish/connectors-lib'
|
|
6
|
+
const { docClient } = AWS.mock.results[0].value
|
|
7
|
+
const { value: debug } = db.mock.results[db.mock.calls.findIndex(c => c[0] === 'sales:transactions')]
|
|
8
|
+
|
|
9
|
+
jest.mock('debug', () => jest.fn(() => jest.fn()))
|
|
10
|
+
|
|
11
|
+
jest.mock('@defra-fish/connectors-lib', () => {
|
|
12
|
+
const mockAWS = {
|
|
13
|
+
docClient: {
|
|
14
|
+
get: jest.fn()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
AWS: jest.fn(() => mockAWS)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const mockResultWithItem = (item = 'foo') => ({
|
|
23
|
+
Item: item
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('retrieve-transaction', () => {
|
|
27
|
+
it('checks the staging table for a match', async () => {
|
|
28
|
+
const id = 'foo'
|
|
29
|
+
docClient.get.mockResolvedValueOnce(mockResultWithItem())
|
|
30
|
+
|
|
31
|
+
await retrieveStagedTransaction(id)
|
|
32
|
+
|
|
33
|
+
expect(docClient.get).toHaveBeenCalledWith({ TableName: TRANSACTION_STAGING_TABLE.TableName, Key: { id }, ConsistentRead: true })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('when the result has an item', () => {
|
|
37
|
+
it('logs that it has retrieved a record', async () => {
|
|
38
|
+
const id = 'foo'
|
|
39
|
+
docClient.get.mockResolvedValueOnce(mockResultWithItem())
|
|
40
|
+
|
|
41
|
+
await retrieveStagedTransaction(id)
|
|
42
|
+
|
|
43
|
+
expect(debug).toHaveBeenCalledWith('Retrieved transaction record for staging id %s', id)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('returns the result item', async () => {
|
|
47
|
+
const expectedItem = Symbol('Item')
|
|
48
|
+
docClient.get.mockResolvedValueOnce(mockResultWithItem(expectedItem))
|
|
49
|
+
|
|
50
|
+
const transactionResult = await retrieveStagedTransaction('foo')
|
|
51
|
+
|
|
52
|
+
expect(transactionResult).toEqual(expectedItem)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('when the result does not have an item', () => {
|
|
57
|
+
it('logs that it has failed to retrieve a record', async () => {
|
|
58
|
+
const id = 'foo'
|
|
59
|
+
docClient.get.mockResolvedValueOnce({}).mockResolvedValueOnce(mockResultWithItem())
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
await retrieveStagedTransaction(id)
|
|
63
|
+
} catch {
|
|
64
|
+
expect(debug).toHaveBeenCalledWith('Failed to retrieve a transaction with staging id %s', id)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('checks the historical staging table for a match', async () => {
|
|
69
|
+
const id = 'foo'
|
|
70
|
+
docClient.get.mockResolvedValueOnce({}).mockResolvedValueOnce(mockResultWithItem())
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
await retrieveStagedTransaction(id)
|
|
74
|
+
} catch {
|
|
75
|
+
expect(docClient.get).toHaveBeenCalledWith({
|
|
76
|
+
TableName: TRANSACTION_STAGING_HISTORY_TABLE.TableName,
|
|
77
|
+
Key: { id },
|
|
78
|
+
ConsistentRead: true
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('throws a 410 Gone error if there is not a historical match', async () => {
|
|
84
|
+
const historicalItem = Symbol('historicalItem')
|
|
85
|
+
docClient.get.mockResolvedValueOnce({}).mockResolvedValueOnce(mockResultWithItem(historicalItem))
|
|
86
|
+
|
|
87
|
+
await expect(retrieveStagedTransaction('foo')).rejects.toThrow(
|
|
88
|
+
Boom.resourceGone('The transaction has already been finalised', historicalItem)
|
|
89
|
+
)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('throws a 404 Not Found error if there is not a historical match', async () => {
|
|
93
|
+
docClient.get.mockResolvedValueOnce({}).mockResolvedValueOnce({})
|
|
94
|
+
|
|
95
|
+
await expect(retrieveStagedTransaction('foo')).rejects.toThrow(
|
|
96
|
+
Boom.notFound('A transaction for the specified identifier was not found')
|
|
97
|
+
)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
})
|
|
@@ -102,7 +102,9 @@ export async function processQueue ({ id }) {
|
|
|
102
102
|
paymentJournal.total = totalTransactionValue
|
|
103
103
|
|
|
104
104
|
debug('Persisting %d entities for staging id %s', entities.length, id)
|
|
105
|
-
|
|
105
|
+
|
|
106
|
+
await persistEntities(entities, transactionRecord, id)
|
|
107
|
+
|
|
106
108
|
debug('Moving staging data to history table for staging id %s', id)
|
|
107
109
|
await docClient.delete({ TableName: TRANSACTION_STAGING_TABLE.TableName, Key: { id } })
|
|
108
110
|
await docClient.put({
|
|
@@ -172,6 +174,20 @@ const createTransactionEntities = async transactionRecord => {
|
|
|
172
174
|
return { transaction, chargeJournal, paymentJournal }
|
|
173
175
|
}
|
|
174
176
|
|
|
177
|
+
const persistEntities = async (entities, transactionRecord, id) => {
|
|
178
|
+
const ALREADY_PERSISTED_ERROR = /Permission Reference Number already exists/
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
await persist(entities, transactionRecord.createdBy)
|
|
182
|
+
} catch (e) {
|
|
183
|
+
if (e?.error?.message.match(ALREADY_PERSISTED_ERROR)) {
|
|
184
|
+
debug('Permission for staging id %s has already been persisted', id)
|
|
185
|
+
} else {
|
|
186
|
+
throw e
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
175
191
|
export const getTransactionJournalRefNumber = (transactionRecord, type) => {
|
|
176
192
|
if (POCL_TRANSACTION_SOURCES.includes(transactionRecord.dataSource) && type === 'Payment') {
|
|
177
193
|
if (transactionRecord.dataSource === DDE_DATA_SOURCE && transactionRecord.journalId) {
|