@defra-fish/sales-api-service 1.63.0-rc.1 → 1.63.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/sales-api-service",
3
- "version": "1.63.0-rc.1",
3
+ "version": "1.63.0-rc.11",
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.63.0-rc.1",
39
- "@defra-fish/connectors-lib": "1.63.0-rc.1",
40
- "@defra-fish/dynamics-lib": "1.63.0-rc.1",
38
+ "@defra-fish/business-rules-lib": "1.63.0-rc.11",
39
+ "@defra-fish/connectors-lib": "1.63.0-rc.11",
40
+ "@defra-fish/dynamics-lib": "1.63.0-rc.11",
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": "93c7097feecf01ce2d207cafe43227f7aaa77376"
55
+ "gitHead": "7d0e5dab76d8aebb0dbaecb857c3d44fdc6f79f9"
56
56
  }
@@ -33,10 +33,10 @@ const getResponseSampleData = () => ({
33
33
  mobilePhone: null,
34
34
  organisation: null,
35
35
  premises: '1',
36
- street: 'Catharine Place',
36
+ street: 'Test Street',
37
37
  locality: null,
38
- town: 'Bath',
39
- postcode: 'BA1 2PR'
38
+ town: 'Testville',
39
+ postcode: 'TE1 1ST'
40
40
  }
41
41
  },
42
42
  activePermission: {
@@ -166,3 +166,19 @@ describe('cancelRecurringPaymentRequestParamsSchema', () => {
166
166
  expect(() => cancelRecurringPaymentRequestParamsSchema.validateAsync(sampleData).rejects.toThrow())
167
167
  })
168
168
  })
169
+
170
+ describe('cancelRecurringPaymentRequestParamsSchema', () => {
171
+ it('validates expected object', async () => {
172
+ const sampleData = { id: 'abc123' }
173
+ expect(() => cancelRecurringPaymentRequestParamsSchema.validateAsync(sampleData)).not.toThrow()
174
+ })
175
+
176
+ it('throws an error if id missing', async () => {
177
+ expect(() => cancelRecurringPaymentRequestParamsSchema.validateAsync({}).rejects.toThrow())
178
+ })
179
+
180
+ it('throws an error if id is not the correct type', async () => {
181
+ const sampleData = { id: 99 }
182
+ expect(() => cancelRecurringPaymentRequestParamsSchema.validateAsync(sampleData).rejects.toThrow())
183
+ })
184
+ })
@@ -1,4 +1,9 @@
1
- import { createTransactionSchema, createTransactionResponseSchema, finaliseTransactionResponseSchema } from '../transaction.schema.js'
1
+ import {
2
+ createTransactionSchema,
3
+ createTransactionResponseSchema,
4
+ finaliseTransactionResponseSchema,
5
+ retrieveStagedTransactionParamsSchema
6
+ } from '../transaction.schema.js'
2
7
  import { mockTransactionPayload, mockStagedTransactionRecord, mockFinalisedTransactionRecord } from '../../__mocks__/test-data.js'
3
8
 
4
9
  jest.mock('../validators/validators.js', () => ({
@@ -96,27 +101,42 @@ describe('createTransactionSchema', () => {
96
101
  await expect(createTransactionSchema.validateAsync(mockPayload)).rejects.toThrow()
97
102
  })
98
103
 
99
- it('validates successfully when an agreementId is supplied', async () => {
104
+ it('validates successfully when recurring payment detail is supplied', async () => {
100
105
  const mockPayload = mockTransactionPayload()
101
- mockPayload.agreementId = 't3jl08v2nqqmujrnhs09pmhtjx'
106
+ mockPayload.recurringPayment = {
107
+ agreementId: 't3jl08v2nqqmujrnhs09pmhtjx',
108
+ id: 'fdc73d20-a0bf-4da6-9a49-2f0a24bd3509'
109
+ }
102
110
  await expect(createTransactionSchema.validateAsync(mockPayload)).resolves.not.toThrow()
103
111
  })
104
112
 
105
- it('validates successfully when agreementId is omitted', async () => {
113
+ it('validates successfully when recurring payment detail is omitted', async () => {
106
114
  const mockPayload = mockTransactionPayload()
107
115
  await expect(createTransactionSchema.validateAsync(mockPayload)).resolves.not.toThrow()
108
116
  })
109
117
 
118
+ it('fails validation if agreement id is omitted from recurring payment detail', async () => {
119
+ const mockPayload = mockTransactionPayload()
120
+ mockPayload.recurringPayment = { id: 'fdc73d20-a0bf-4da6-9a49-2f0a24bd3509' }
121
+ await expect(() => createTransactionSchema.validateAsync(mockPayload)).rejects.toThrow()
122
+ })
123
+
110
124
  it.each([
111
- ['too short string', 'foo'],
112
- ['too long string', 'foobarbazfoobarbazfoobarbaz'],
113
- ['string containing invalid characters', '!3j@08v2nqqmujrnhs09_mhtjx'],
114
- ['null', null],
115
- ['numeric', 4567]
116
- ])('fails validation when provided with a %s for agreementId', async (_d, agreementId) => {
125
+ ['agreement id is too long', { agreementId: 'thisistoolongtobeanagreementid' }],
126
+ ['agreement id is too short', { agreementId: 'tooshorttobeanagreementid' }],
127
+ ['agreement id contains invalid characters', '!3j@08v2nqqmujrnhs09_mhtjx'],
128
+ ['agreement id is null', { agreementId: null }],
129
+ ['agreement id is a numeric', { agreementId: 4567 }],
130
+ ['id is not a guid', { id: 'not-a-guid' }],
131
+ ['id is null', { id: null }]
132
+ ])('fails validation if %s', async (_d, recurringPayment) => {
117
133
  const mockPayload = mockTransactionPayload()
118
- mockPayload.agreementId = agreementId
119
- await expect(createTransactionSchema.validateAsync(mockPayload)).rejects.toThrow()
134
+ mockPayload.recurringPayment = {
135
+ agreementId: 'jhyu78iujhy7u87y6thu87uyj8',
136
+ id: '7a0660ec-8535-4357-b925-e598a9358119',
137
+ ...recurringPayment
138
+ }
139
+ await expect(() => createTransactionSchema.validateAsync(mockPayload)).rejects.toThrow()
120
140
  })
121
141
  })
122
142
 
@@ -135,3 +155,32 @@ describe('finaliseTransactionResponseSchema', () => {
135
155
  expect(result).toBeInstanceOf(Object)
136
156
  })
137
157
  })
158
+
159
+ describe('retrieveStagedTransactionParamsSchema', () => {
160
+ it.each([
161
+ ['36fb757c-6377-49c5-ab6e-32eb9782fcf0'],
162
+ ['c290b78d-3bbc-4445-b4dd-b36f6ee044a2'],
163
+ ['2323a890-b36f-47b1-ab9f-d60e292ac4ae'],
164
+ ['9c6b79be-28be-4916-aa5c-08520aa1e804']
165
+ ])('validates successfully when a uuid v4 transactionId is %s', async transactionId => {
166
+ const sampleData = { id: transactionId }
167
+ await expect(retrieveStagedTransactionParamsSchema.validateAsync(sampleData)).resolves.not.toThrow()
168
+ })
169
+
170
+ it.each([
171
+ ['uuid1 string', '5a429f62-871b-11ef-b864-0242ac120002'],
172
+ ['uuid2 string', '000003e8-871b-21ef-8000-325096b39f47'],
173
+ ['uuid3 string', 'a3bb189e-8bf9-3888-9912-ace4e6543002'],
174
+ ['uuid5 string', 'a6edc906-2f9f-5fb2-a373-efac406f0ef2'],
175
+ ['uuid6 string', 'a3bb189e-8bf9-3888-9912-ace4e6543002'],
176
+ ['uuid7 string', '01927705-ffac-77b5-89af-c97451b1bbe2'],
177
+ ['numeric', 4567]
178
+ ])('fails validation when provided with a %s for transactionId', async (_d, transactionId) => {
179
+ const sampleData = { id: transactionId }
180
+ await expect(() => retrieveStagedTransactionParamsSchema.validateAsync(sampleData)).rejects.toThrow()
181
+ })
182
+
183
+ it('throws an error if id missing', async () => {
184
+ await expect(() => retrieveStagedTransactionParamsSchema.validateAsync({}).rejects.toThrow())
185
+ })
186
+ })
@@ -36,7 +36,10 @@ const createTransactionRequestSchemaContent = {
36
36
  createdBy: Joi.string().optional(),
37
37
  journalId: Joi.string().optional(),
38
38
  transactionId: Joi.string().guid({ version: 'uuidv4' }).optional(),
39
- agreementId: Joi.string().alphanum().length(AGREEMENT_ID_LENGTH).optional()
39
+ recurringPayment: Joi.object({
40
+ agreementId: Joi.string().alphanum().length(AGREEMENT_ID_LENGTH).required(),
41
+ id: Joi.string().guid()
42
+ }).optional()
40
43
  }
41
44
 
42
45
  /**
@@ -153,3 +156,7 @@ export const finaliseTransactionResponseSchema = Joi.object({
153
156
  .required()
154
157
  .label('finalise-transaction-status')
155
158
  }).label('finalise-transaction-response')
159
+
160
+ export const retrieveStagedTransactionParamsSchema = Joi.object({
161
+ id: Joi.string().guid({ version: 'uuidv4' }).required()
162
+ })
@@ -2,9 +2,19 @@ import initialiseServer from '../server.js'
2
2
  import Boom from '@hapi/boom'
3
3
  import dotProp from 'dot-prop'
4
4
  import { SERVER } from '../../config.js'
5
+ import fs from 'fs'
6
+
7
+ jest.mock('fs', () => {
8
+ const actual = jest.requireActual('fs')
9
+ return {
10
+ ...actual,
11
+ readFileSync: jest.fn(() => JSON.stringify({ name: 'sales-api-test', version: '1.2.3' }))
12
+ }
13
+ })
5
14
 
6
15
  describe('hapi server', () => {
7
16
  describe('initialisation', () => {
17
+ const serverInfoUri = 'test'
8
18
  let serverConfigSpy
9
19
  beforeAll(() => {
10
20
  const Hapi = jest.requireActual('@hapi/hapi')
@@ -15,7 +25,7 @@ describe('hapi server', () => {
15
25
  register: jest.fn(),
16
26
  route: jest.fn(),
17
27
  info: {
18
- uri: 'test'
28
+ uri: serverInfoUri
19
29
  },
20
30
  listener: {}
21
31
  }))
@@ -48,6 +58,22 @@ describe('hapi server', () => {
48
58
  headersTimeout: 5123
49
59
  })
50
60
  })
61
+
62
+ it('logs startup details including name and version', async () => {
63
+ const mockPkg = { name: 'sales-api-test', version: '1.2.3' }
64
+ fs.readFileSync.mockReturnValue(JSON.stringify(mockPkg))
65
+ const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
66
+
67
+ await initialiseServer({ port: 4000 })
68
+
69
+ expect(logSpy).toHaveBeenCalledWith(
70
+ expect.stringContaining('Server started at %s. Listening on %s. name: %s. version: %s'),
71
+ expect.any(String),
72
+ serverInfoUri,
73
+ mockPkg.name,
74
+ mockPkg.version
75
+ )
76
+ })
51
77
  })
52
78
 
53
79
  describe('configuration', () => {
@@ -1,6 +1,10 @@
1
1
  import initialiseServer from '../../server.js'
2
2
  import { mockTransactionPayload, mockStagedTransactionRecord } from '../../../__mocks__/test-data.js'
3
3
  import { v4 as uuidv4 } from 'uuid'
4
+ import { retrieveStagedTransactionParamsSchema } from '../../../schema/transaction.schema.js'
5
+ import { retrieveStagedTransaction } from '../../../services/transactions/retrieve-transaction.js'
6
+ import transactions from '../transactions.js'
7
+
4
8
  jest.mock('../../../services/transactions/transactions.service.js', () => ({
5
9
  createTransaction: jest.fn(async () => mockStagedTransactionRecord()),
6
10
  createTransactions: jest.fn(async payloads => Array(payloads.length).fill(mockStagedTransactionRecord())),
@@ -9,6 +13,10 @@ jest.mock('../../../services/transactions/transactions.service.js', () => ({
9
13
  processDlq: jest.fn(async () => {})
10
14
  }))
11
15
 
16
+ jest.mock('../../../services/transactions/retrieve-transaction.js', () => ({
17
+ retrieveStagedTransaction: jest.fn()
18
+ }))
19
+
12
20
  jest.mock('../../../schema/validators/validators.js', () => ({
13
21
  ...jest.requireActual('../../../schema/validators/validators.js'),
14
22
  createOptionSetValidator: () => async () => undefined,
@@ -18,6 +26,20 @@ jest.mock('../../../schema/validators/validators.js', () => ({
18
26
  createPermitConcessionValidator: () => async () => undefined
19
27
  }))
20
28
 
29
+ jest.mock('@defra-fish/connectors-lib', () => {
30
+ const awsMock = {
31
+ docClient: {
32
+ get: jest.fn(() => ({ Item: { id: 'abc123' } }))
33
+ }
34
+ }
35
+ return {
36
+ AWS: jest.fn(() => awsMock),
37
+ airbrake: {
38
+ initialise: jest.fn()
39
+ }
40
+ }
41
+ })
42
+
21
43
  let server = null
22
44
 
23
45
  describe('transaction handler', () => {
@@ -214,4 +236,30 @@ describe('transaction handler', () => {
214
236
  expect(result).toBeUnprocessableEntityErrorResponse()
215
237
  })
216
238
  })
239
+
240
+ describe('retrieveStagedTransaction', () => {
241
+ const getMockRequest = ({ id = 'abc123' }) => ({ params: { id } })
242
+ const getMockResponseToolkit = () => ({ response: jest.fn() })
243
+ const retrieveHandler = transactions[transactions.length - 1].options.handler
244
+
245
+ it('handler should return continue response', async () => {
246
+ const request = getMockRequest({})
247
+ const responseToolkit = getMockResponseToolkit()
248
+ expect(await retrieveHandler(request, responseToolkit)).toEqual(responseToolkit.continue)
249
+ })
250
+
251
+ it('should call retrieveStagedTransaction with id', async () => {
252
+ const id = 'transaction-id'
253
+ const request = getMockRequest({ id })
254
+ await retrieveHandler(request, getMockResponseToolkit())
255
+ expect(retrieveStagedTransaction).toHaveBeenCalledWith(id)
256
+ })
257
+
258
+ it('should validate with cancelRecurringPaymentRequestParamsSchema', async () => {
259
+ const id = 'transaction-id'
260
+ const request = getMockRequest({ id })
261
+ await retrieveHandler(request, getMockResponseToolkit())
262
+ expect(transactions[5].options.validate.params).toBe(retrieveStagedTransactionParamsSchema)
263
+ })
264
+ })
217
265
  })
@@ -7,6 +7,7 @@ import {
7
7
  processQueue,
8
8
  processDlq
9
9
  } from '../../services/transactions/transactions.service.js'
10
+ import { retrieveStagedTransaction } from '../../services/transactions/retrieve-transaction.js'
10
11
  import {
11
12
  createTransactionSchema,
12
13
  createTransactionResponseSchema,
@@ -14,6 +15,7 @@ import {
14
15
  createTransactionBatchResponseSchema,
15
16
  finaliseTransactionRequestSchema,
16
17
  finaliseTransactionResponseSchema,
18
+ retrieveStagedTransactionParamsSchema,
17
19
  BATCH_CREATE_MAX_COUNT
18
20
  } from '../../schema/transaction.schema.js'
19
21
  import db from 'debug'
@@ -174,5 +176,29 @@ export default [
174
176
  }
175
177
  }
176
178
  }
179
+ },
180
+ {
181
+ method: 'GET',
182
+ path: '/retrieveStagedTransaction/{id}',
183
+ options: {
184
+ handler: async (request, h) => {
185
+ const { id } = request.params
186
+ const result = await retrieveStagedTransaction(id)
187
+ return h.response(result)
188
+ },
189
+ description: 'Retrieve a staged transaction',
190
+ tags: ['api', 'transactions'],
191
+ validate: {
192
+ params: retrieveStagedTransactionParamsSchema
193
+ },
194
+ plugins: {
195
+ 'hapi-swagger': {
196
+ responses: {
197
+ 200: { description: 'Staged transaction retreived' }
198
+ },
199
+ order: 5
200
+ }
201
+ }
202
+ }
177
203
  }
178
204
  ]
@@ -8,6 +8,8 @@ import Boom from '@hapi/boom'
8
8
  import { SERVER } from '../config.js'
9
9
  import moment from 'moment'
10
10
  import { airbrake } from '@defra-fish/connectors-lib'
11
+ import path from 'path'
12
+ import fs from 'fs'
11
13
 
12
14
  export default async (opts = { port: SERVER.Port }) => {
13
15
  airbrake.initialise()
@@ -49,7 +51,17 @@ export default async (opts = { port: SERVER.Port }) => {
49
51
  server.route(Routes)
50
52
 
51
53
  await server.start()
52
- console.log('Server started at %s. Listening on %s', moment().toISOString(), server.info.uri)
54
+
55
+ const pkgPath = path.join(process.cwd(), 'package.json')
56
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
57
+
58
+ console.log(
59
+ 'Server started at %s. Listening on %s. name: %s. version: %s',
60
+ moment().toISOString(),
61
+ server.info.uri,
62
+ pkg.name,
63
+ pkg.version
64
+ )
53
65
 
54
66
  const shutdown = async code => {
55
67
  await server.stop()
@@ -5,6 +5,7 @@ import {
5
5
  findRecurringPaymentsByAgreementId,
6
6
  findById,
7
7
  Permission,
8
+ persist,
8
9
  RecurringPayment
9
10
  } from '@defra-fish/dynamics-lib'
10
11
  import {
@@ -48,7 +49,8 @@ jest.mock('@defra-fish/dynamics-lib', () => ({
48
49
  findRecurringPaymentsByAgreementId: jest.fn(() => ({ toRetrieveRequest: () => {} })),
49
50
  dynamicsClient: {
50
51
  retrieveMultipleRequest: jest.fn(() => ({ value: [] }))
51
- }
52
+ },
53
+ persist: jest.fn()
52
54
  }))
53
55
 
54
56
  jest.mock('@defra-fish/connectors-lib', () => ({
@@ -392,7 +394,9 @@ describe('recurring payments service', () => {
392
394
  ...permission
393
395
  }
394
396
  ],
395
- agreementId,
397
+ recurringPayment: {
398
+ agreementId
399
+ },
396
400
  payment: {
397
401
  amount: 35.8,
398
402
  source: 'Gov Pay',
@@ -528,6 +532,15 @@ describe('recurring payments service', () => {
528
532
  await expect(generateRecurringPaymentRecord(sampleTransaction)).rejects.toThrow('Invalid dates provided for permission')
529
533
  })
530
534
 
535
+ it('returns a false flag when recurringPayment is not present', async () => {
536
+ const sampleTransaction = createFinalisedSampleTransaction()
537
+ delete sampleTransaction.recurringPayment
538
+
539
+ const rpRecord = await generateRecurringPaymentRecord(sampleTransaction)
540
+
541
+ expect(rpRecord.payment?.recurring).toBeFalsy()
542
+ })
543
+
531
544
  it('returns a false flag when agreementId is not present', async () => {
532
545
  const sampleTransaction = createFinalisedSampleTransaction(
533
546
  null,
@@ -859,28 +872,29 @@ describe('recurring payments service', () => {
859
872
 
860
873
  describe('cancelRecurringPayment', () => {
861
874
  it('should call findById with RecurringPayment and the provided id', async () => {
875
+ findById.mockReturnValueOnce(getMockRecurringPayment())
862
876
  const id = 'abc123'
863
877
  await cancelRecurringPayment(id)
864
878
  expect(findById).toHaveBeenCalledWith(RecurringPayment, id)
865
879
  })
866
880
 
867
- it('should log a RecurringPayment record when there is one match', async () => {
868
- const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(jest.fn())
869
- const recurringPayment = { entity: getMockRecurringPayment() }
881
+ it('should call persist with the updated RecurringPayment', async () => {
882
+ const recurringPayment = getMockRecurringPayment()
870
883
  findById.mockReturnValueOnce(recurringPayment)
871
884
 
885
+ const cancelledDate = new Date().toISOString().split('T')[0]
886
+ const cancelledReason = { description: 'Payment Failure', id: 910400002, label: 'Payment Failure' }
887
+ const expectedUpdatedRecurringPayment = { ...recurringPayment, cancelledReason, cancelledDate }
888
+
872
889
  await cancelRecurringPayment('id')
873
890
 
874
- expect(consoleLogSpy).toHaveBeenCalledWith('RecurringPayment for cancellation: ', recurringPayment)
891
+ expect(persist).toHaveBeenCalledWith([expect.objectContaining(expectedUpdatedRecurringPayment)])
875
892
  })
876
893
 
877
- it('should log no matches when there are no matches', async () => {
878
- const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(jest.fn())
894
+ it('should raise an error when there are no matches', async () => {
879
895
  findById.mockReturnValueOnce(undefined)
880
896
 
881
- await cancelRecurringPayment('id')
882
-
883
- expect(consoleLogSpy).toHaveBeenCalledWith('No matches found for cancellation')
897
+ await expect(cancelRecurringPayment('id')).rejects.toThrow('Invalid id provided for recurring payment cancellation')
884
898
  })
885
899
  })
886
900
  })
@@ -1,10 +1,11 @@
1
1
  import {
2
+ dynamicsClient,
2
3
  executeQuery,
3
4
  findById,
4
5
  findDueRecurringPayments,
5
6
  findRecurringPaymentsByAgreementId,
6
- RecurringPayment,
7
- dynamicsClient
7
+ persist,
8
+ RecurringPayment
8
9
  } from '@defra-fish/dynamics-lib'
9
10
  import { calculateEndDate, generatePermissionNumber } from './permissions.service.js'
10
11
  import { getObfuscatedDob } from './contacts.service.js'
@@ -14,6 +15,7 @@ import { TRANSACTION_STAGING_TABLE, TRANSACTION_QUEUE } from '../config.js'
14
15
  import { TRANSACTION_STATUS } from '../services/transactions/constants.js'
15
16
  import { retrieveStagedTransaction } from '../services/transactions/retrieve-transaction.js'
16
17
  import { createPaymentJournal, getPaymentJournal, updatePaymentJournal } from '../services/paymentjournals/payment-journals.service.js'
18
+ import { getGlobalOptionSetValue } from './reference-data.service.js'
17
19
  import moment from 'moment'
18
20
  import { AWS, govUkPayApi } from '@defra-fish/connectors-lib'
19
21
  import db from 'debug'
@@ -37,8 +39,8 @@ const getNextDueDate = (startDate, issueDate, endDate) => {
37
39
  }
38
40
 
39
41
  export const generateRecurringPaymentRecord = async (transactionRecord, permission) => {
40
- if (transactionRecord.agreementId) {
41
- const agreementResponse = await getRecurringPaymentAgreement(transactionRecord.agreementId)
42
+ if (transactionRecord.recurringPayment?.agreementId) {
43
+ const agreementResponse = await getRecurringPaymentAgreement(transactionRecord.recurringPayment.agreementId)
42
44
  const lastDigitsCardNumbers = agreementResponse.payment_instrument?.card_details?.last_digits_card_number
43
45
  const [{ startDate, issueDate, endDate }] = transactionRecord.permissions
44
46
  return {
@@ -49,7 +51,7 @@ export const generateRecurringPaymentRecord = async (transactionRecord, permissi
49
51
  cancelledDate: null,
50
52
  cancelledReason: null,
51
53
  endDate,
52
- agreementId: transactionRecord.agreementId,
54
+ agreementId: transactionRecord.recurringPayment.agreementId,
53
55
  status: 1,
54
56
  last_digits_card_number: lastDigitsCardNumbers
55
57
  }
@@ -165,9 +167,14 @@ export const findNewestExistingRecurringPaymentInCrm = async agreementId => {
165
167
  export const cancelRecurringPayment = async id => {
166
168
  const recurringPayment = await findById(RecurringPayment, id)
167
169
  if (recurringPayment) {
168
- console.log('RecurringPayment for cancellation: ', recurringPayment)
170
+ const data = recurringPayment
171
+ data.cancelledDate = new Date().toISOString().split('T')[0]
172
+ data.cancelledReason = await getGlobalOptionSetValue(RecurringPayment.definition.mappings.cancelledReason.ref, 'Payment Failure')
173
+ const updatedRecurringPayment = Object.assign(new RecurringPayment(), data)
174
+ await persist([updatedRecurringPayment])
175
+ return updatedRecurringPayment
169
176
  } else {
170
- console.log('No matches found for cancellation')
177
+ throw new Error('Invalid id provided for recurring payment cancellation')
171
178
  }
172
179
  }
173
180