@defra-fish/sales-api-service 1.44.0-rc.8 → 1.44.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 +5 -5
- package/src/schema/transaction.schema.js +17 -3
- package/src/server/routes/__tests__/recurring-payments.spec.js +31 -0
- package/src/server/routes/index.js +3 -1
- package/src/server/routes/recurring-payments.js +12 -0
- package/src/services/__tests__/__snapshots__/recurring-payments.service.spec.js.snap +14 -0
- package/src/services/__tests__/recurring-payments.service.spec.js +137 -0
- package/src/services/recurring-payments.service.js +27 -0
- package/src/services/transactions/__tests__/finalise-transaction.spec.js +1 -1
- package/src/services/transactions/__tests__/process-transaction-queue.spec.js +10 -6
- package/src/services/transactions/process-transaction-queue.js +7 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/sales-api-service",
|
|
3
|
-
"version": "1.44.0
|
|
3
|
+
"version": "1.44.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.44.0
|
|
39
|
-
"@defra-fish/connectors-lib": "1.44.0
|
|
40
|
-
"@defra-fish/dynamics-lib": "1.44.0
|
|
38
|
+
"@defra-fish/business-rules-lib": "1.44.0",
|
|
39
|
+
"@defra-fish/connectors-lib": "1.44.0",
|
|
40
|
+
"@defra-fish/dynamics-lib": "1.44.0",
|
|
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": "c1a99ab268a24df0eacdf151bf62a549e7e971b2"
|
|
56
56
|
}
|
|
@@ -106,9 +106,23 @@ const finaliseTransactionRequestSchemaContent = {
|
|
|
106
106
|
channelId: Joi.string().trim().optional().description('Channel specific identifier'),
|
|
107
107
|
method: buildJoiOptionSetValidator('defra_paymenttype', 'Debit card'),
|
|
108
108
|
recurring: Joi.object({
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
name: Joi.string().required().description('The default name associated with the recurring payment').example(uuidv4()),
|
|
110
|
+
nextDueDate: Joi.string()
|
|
111
|
+
.isoDate()
|
|
112
|
+
.required()
|
|
113
|
+
.description('The date of payment for a renewed permission')
|
|
114
|
+
.example(new Date().toISOString()),
|
|
115
|
+
cancelledDate: Joi.string()
|
|
116
|
+
.isoDate()
|
|
117
|
+
.optional()
|
|
118
|
+
.description('Optional field for when recurring payment cancelled')
|
|
119
|
+
.example(new Date().toISOString()),
|
|
120
|
+
cancelledReason: buildJoiOptionSetValidator('defra_cancelledreason', 'User Cancelled'),
|
|
121
|
+
endDate: Joi.string().isoDate().required().description('End of recurring payment').example(new Date().toISOString()),
|
|
122
|
+
agreementId: Joi.string().required().description('Agreement identification number, Gov.UK Pay field').example(uuidv4()),
|
|
123
|
+
publicId: Joi.string().required().description('SHA-256 hash of id').example(uuidv4()),
|
|
124
|
+
contact: contactRequestSchema,
|
|
125
|
+
activePermission: finalisePermissionResponseSchema
|
|
112
126
|
})
|
|
113
127
|
.label('finalise-transaction-recurring-payment-details')
|
|
114
128
|
.description('Used to establish a recurring payment (e.g. via Direct Debit)')
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import dueRecurringPayments from '../recurring-payments.js'
|
|
2
|
+
import { getRecurringPayments } from '../../../services/recurring-payments.service.js'
|
|
3
|
+
|
|
4
|
+
jest.mock('../../../services/recurring-payments.service.js', () => ({
|
|
5
|
+
getRecurringPayments: jest.fn()
|
|
6
|
+
}))
|
|
7
|
+
|
|
8
|
+
const getMockRequest = ({ date = '2023-10-19' }) => ({
|
|
9
|
+
params: { date }
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const getMockResponseToolkit = () => ({
|
|
13
|
+
response: jest.fn()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('recurring payments', () => {
|
|
17
|
+
beforeEach(jest.clearAllMocks)
|
|
18
|
+
|
|
19
|
+
it('handler should return continue response', async () => {
|
|
20
|
+
const request = getMockRequest({})
|
|
21
|
+
const responseToolkit = getMockResponseToolkit()
|
|
22
|
+
expect(await dueRecurringPayments[0].handler(request, responseToolkit)).toEqual(responseToolkit.continue)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should call getRecurringPayments with date', async () => {
|
|
26
|
+
const date = Symbol('date')
|
|
27
|
+
const request = getMockRequest({ date })
|
|
28
|
+
await dueRecurringPayments[0].handler(request, getMockResponseToolkit())
|
|
29
|
+
expect(getRecurringPayments).toHaveBeenCalledWith(date)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -6,6 +6,7 @@ import PaymentJournals from './payment-journals.js'
|
|
|
6
6
|
import StagingExceptions from './staging-exceptions.js'
|
|
7
7
|
import Authenticate from './authenticate.js'
|
|
8
8
|
import Users from './system-users.js'
|
|
9
|
+
import RecurringPayment from './recurring-payments.js'
|
|
9
10
|
|
|
10
11
|
import Static from './static.js'
|
|
11
12
|
|
|
@@ -18,5 +19,6 @@ export default [
|
|
|
18
19
|
...PaymentJournals,
|
|
19
20
|
...StagingExceptions,
|
|
20
21
|
...Authenticate,
|
|
21
|
-
...Users
|
|
22
|
+
...Users,
|
|
23
|
+
...RecurringPayment
|
|
22
24
|
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getRecurringPayments } from '../../services/recurring-payments.service.js'
|
|
2
|
+
export default [
|
|
3
|
+
{
|
|
4
|
+
method: 'GET',
|
|
5
|
+
path: '/dueRecurringPayments/{date}',
|
|
6
|
+
handler: async (request, h) => {
|
|
7
|
+
const { date } = request.params
|
|
8
|
+
const result = await getRecurringPayments(date)
|
|
9
|
+
return h.response(result)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`recurring payments service processRecurringPayment should return a valid recurringPayment when transactionRecord.payment.recurring is present 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"agreementId": "435678",
|
|
6
|
+
"cancelledDate": null,
|
|
7
|
+
"cancelledReason": null,
|
|
8
|
+
"endDate": 2023-11-12T00:00:00.000Z,
|
|
9
|
+
"name": "Test Name",
|
|
10
|
+
"nextDueDate": 2023-11-02T00:00:00.000Z,
|
|
11
|
+
"publicId": "1234456",
|
|
12
|
+
"status": 0,
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { findDueRecurringPayments } from '@defra-fish/dynamics-lib'
|
|
2
|
+
import { getRecurringPayments, processRecurringPayment } from '../recurring-payments.service.js'
|
|
3
|
+
|
|
4
|
+
jest.mock('@defra-fish/dynamics-lib', () => ({
|
|
5
|
+
...jest.requireActual('@defra-fish/dynamics-lib'),
|
|
6
|
+
executeQuery: jest.fn(),
|
|
7
|
+
findById: jest.fn(),
|
|
8
|
+
findDueRecurringPayments: jest.fn()
|
|
9
|
+
}))
|
|
10
|
+
|
|
11
|
+
const dynamicsLib = jest.requireMock('@defra-fish/dynamics-lib')
|
|
12
|
+
|
|
13
|
+
const getMockRecurringPayment = () => ({
|
|
14
|
+
name: 'Test Name',
|
|
15
|
+
nextDueDate: '2019-12-14T00:00:00Z',
|
|
16
|
+
cancelledDate: null,
|
|
17
|
+
cancelledReason: null,
|
|
18
|
+
endDate: '2019-12-15T00:00:00Z',
|
|
19
|
+
agreementId: 'c9267c6e-573d-488b-99ab-ea18431fc472',
|
|
20
|
+
publicId: '649-213',
|
|
21
|
+
status: 1,
|
|
22
|
+
expanded: {
|
|
23
|
+
contact: {
|
|
24
|
+
entity: getMockContact()
|
|
25
|
+
},
|
|
26
|
+
activePermission: {
|
|
27
|
+
entity: getMockPermission()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const getMockRPContactPermission = (contact, permission) => ({
|
|
33
|
+
name: 'Test Name',
|
|
34
|
+
nextDueDate: '2019-12-14T00:00:00Z',
|
|
35
|
+
cancelledDate: null,
|
|
36
|
+
cancelledReason: null,
|
|
37
|
+
endDate: '2019-12-15T00:00:00Z',
|
|
38
|
+
agreementId: 'c9267c6e-573d-488b-99ab-ea18431fc472',
|
|
39
|
+
publicId: '649-213',
|
|
40
|
+
status: 1,
|
|
41
|
+
expanded: {
|
|
42
|
+
contact,
|
|
43
|
+
activePermission: permission
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const getMockContact = () => ({
|
|
48
|
+
firstName: 'Fester',
|
|
49
|
+
lastName: 'Tester',
|
|
50
|
+
birthDate: '2000-01-01',
|
|
51
|
+
email: 'person@example.com',
|
|
52
|
+
mobilePhone: '+44 7700 900088',
|
|
53
|
+
premises: 'Example House',
|
|
54
|
+
street: 'Example Street',
|
|
55
|
+
locality: 'Near Sample',
|
|
56
|
+
town: 'Exampleton',
|
|
57
|
+
postcode: 'AB12 3CD',
|
|
58
|
+
country: 'GB-ENG',
|
|
59
|
+
preferredMethodOfConfirmation: 'Text',
|
|
60
|
+
preferredMethodOfNewsletter: 'Email',
|
|
61
|
+
preferredMethodOfReminder: 'Letter',
|
|
62
|
+
postalFulfilment: true
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const getMockPermission = () => ({
|
|
66
|
+
referenceNumber: '12345678',
|
|
67
|
+
licenceLength: '12M',
|
|
68
|
+
isLicenceForYou: true,
|
|
69
|
+
licensee: {
|
|
70
|
+
firstName: 'Fester',
|
|
71
|
+
lastName: 'Tester',
|
|
72
|
+
premises: '14 Howecroft Court',
|
|
73
|
+
street: 'Eastmead Lane',
|
|
74
|
+
town: 'Bristol',
|
|
75
|
+
postcode: 'BS9 1HJ',
|
|
76
|
+
email: 'fester@tester.com',
|
|
77
|
+
mobilePhone: '01234567890',
|
|
78
|
+
birthDate: '1996-01-01',
|
|
79
|
+
postalFulfilment: true
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('recurring payments service', () => {
|
|
84
|
+
beforeEach(jest.clearAllMocks)
|
|
85
|
+
describe('getRecurringPayments', () => {
|
|
86
|
+
it('should equal result of findDueRecurringPayments query', async () => {
|
|
87
|
+
const mockRecurringPayments = [getMockRecurringPayment()]
|
|
88
|
+
const mockContact = mockRecurringPayments[0].expanded.contact
|
|
89
|
+
const mockPermission = mockRecurringPayments[0].expanded.activePermission
|
|
90
|
+
|
|
91
|
+
dynamicsLib.executeQuery.mockResolvedValueOnce(mockRecurringPayments)
|
|
92
|
+
|
|
93
|
+
const result = await getRecurringPayments(new Date())
|
|
94
|
+
|
|
95
|
+
expect(result).toEqual([getMockRPContactPermission(mockContact, mockPermission)])
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('executeQuery is called with findDueRecurringPayments with a date', async () => {
|
|
99
|
+
const mockRecurringPayments = [getMockRecurringPayment()]
|
|
100
|
+
const mockDate = new Date()
|
|
101
|
+
dynamicsLib.executeQuery.mockResolvedValueOnce(mockRecurringPayments)
|
|
102
|
+
|
|
103
|
+
await getRecurringPayments(mockDate)
|
|
104
|
+
|
|
105
|
+
expect(dynamicsLib.executeQuery).toHaveBeenCalledWith(findDueRecurringPayments(mockDate))
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('processRecurringPayment', () => {
|
|
110
|
+
it('should return null when transactionRecord.payment.recurring is not present', async () => {
|
|
111
|
+
const transactionRecord = { payment: null }
|
|
112
|
+
const result = await processRecurringPayment(transactionRecord, getMockContact())
|
|
113
|
+
expect(result.recurringPayment).toBeNull()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('should return a valid recurringPayment when transactionRecord.payment.recurring is present', async () => {
|
|
117
|
+
const transactionRecord = {
|
|
118
|
+
payment: {
|
|
119
|
+
recurring: {
|
|
120
|
+
name: 'Test Name',
|
|
121
|
+
nextDueDate: new Date('2023-11-02'),
|
|
122
|
+
cancelledDate: null,
|
|
123
|
+
cancelledReason: null,
|
|
124
|
+
endDate: new Date('2023-11-12'),
|
|
125
|
+
agreementId: '435678',
|
|
126
|
+
publicId: '1234456',
|
|
127
|
+
status: 0
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
permissions: [getMockPermission()]
|
|
131
|
+
}
|
|
132
|
+
const contact = getMockContact()
|
|
133
|
+
const result = await processRecurringPayment(transactionRecord, contact)
|
|
134
|
+
expect(result.recurringPayment).toMatchSnapshot()
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { executeQuery, findDueRecurringPayments, RecurringPayment } from '@defra-fish/dynamics-lib'
|
|
2
|
+
|
|
3
|
+
export const getRecurringPayments = date => executeQuery(findDueRecurringPayments(date))
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Process a recurring payment instruction
|
|
7
|
+
* @param transactionRecord
|
|
8
|
+
* @returns {Promise<{recurringPayment: RecurringPayment | null}>}
|
|
9
|
+
*/
|
|
10
|
+
export const processRecurringPayment = async (transactionRecord, contact) => {
|
|
11
|
+
if (transactionRecord.payment?.recurring) {
|
|
12
|
+
const recurringPayment = new RecurringPayment()
|
|
13
|
+
recurringPayment.name = transactionRecord.payment.recurring.name
|
|
14
|
+
recurringPayment.nextDueDate = transactionRecord.payment.recurring.nextDueDate
|
|
15
|
+
recurringPayment.cancelledDate = transactionRecord.payment.recurring.cancelledDate
|
|
16
|
+
recurringPayment.cancelledReason = transactionRecord.payment.recurring.cancelledReason
|
|
17
|
+
recurringPayment.endDate = transactionRecord.payment.recurring.endDate
|
|
18
|
+
recurringPayment.agreementId = transactionRecord.payment.recurring.agreementId
|
|
19
|
+
recurringPayment.publicId = transactionRecord.payment.recurring.publicId
|
|
20
|
+
recurringPayment.status = transactionRecord.payment.recurring.status
|
|
21
|
+
const [permission] = transactionRecord.permissions
|
|
22
|
+
recurringPayment.bindToEntity(RecurringPayment.definition.relationships.activePermission, permission)
|
|
23
|
+
recurringPayment.bindToEntity(RecurringPayment.definition.relationships.contact, contact)
|
|
24
|
+
return { recurringPayment }
|
|
25
|
+
}
|
|
26
|
+
return { recurringPayment: null }
|
|
27
|
+
}
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
FulfilmentRequest,
|
|
8
8
|
Permission,
|
|
9
9
|
PoclFile,
|
|
10
|
-
RecurringPayment,
|
|
11
10
|
RecurringPaymentInstruction,
|
|
12
11
|
Transaction,
|
|
13
|
-
TransactionJournal
|
|
12
|
+
TransactionJournal,
|
|
13
|
+
RecurringPayment
|
|
14
14
|
} from '@defra-fish/dynamics-lib'
|
|
15
15
|
import {
|
|
16
16
|
mockFinalisedTransactionRecord,
|
|
@@ -126,12 +126,17 @@ describe('transaction service', () => {
|
|
|
126
126
|
'licences with a recurring payment',
|
|
127
127
|
() => {
|
|
128
128
|
const mockRecord = mockFinalisedTransactionRecord()
|
|
129
|
-
mockRecord.permissions[0].permitId = MOCK_12MONTH_SENIOR_PERMIT.id
|
|
130
129
|
mockRecord.payment.recurring = {
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
name: 'Test name',
|
|
131
|
+
nextDueDate: new Date('2020/01/11'),
|
|
132
|
+
endDate: new Date('2022/01/16'),
|
|
133
|
+
agreementId: '123446jjng',
|
|
134
|
+
publicId: 'sdf-123',
|
|
135
|
+
status: 1,
|
|
136
|
+
activePermission: mockRecord.permissions[0],
|
|
133
137
|
contact: Object.assign(mockContactPayload(), { firstName: 'Esther' })
|
|
134
138
|
}
|
|
139
|
+
mockRecord.permissions[0].permitId = MOCK_12MONTH_SENIOR_PERMIT.id
|
|
135
140
|
return mockRecord
|
|
136
141
|
},
|
|
137
142
|
[
|
|
@@ -140,7 +145,6 @@ describe('transaction service', () => {
|
|
|
140
145
|
expect.any(TransactionJournal),
|
|
141
146
|
expect.any(RecurringPayment),
|
|
142
147
|
expect.any(Contact),
|
|
143
|
-
expect.any(Contact),
|
|
144
148
|
expect.any(Permission),
|
|
145
149
|
expect.any(RecurringPaymentInstruction),
|
|
146
150
|
expect.any(ConcessionProof)
|
|
@@ -8,17 +8,17 @@ import {
|
|
|
8
8
|
Transaction,
|
|
9
9
|
TransactionCurrency,
|
|
10
10
|
TransactionJournal,
|
|
11
|
-
RecurringPayment,
|
|
12
11
|
RecurringPaymentInstruction
|
|
13
12
|
} from '@defra-fish/dynamics-lib'
|
|
14
13
|
import { DDE_DATA_SOURCE, FULFILMENT_SWITCHOVER_DATE, POCL_TRANSACTION_SOURCES } from '@defra-fish/business-rules-lib'
|
|
15
14
|
import { getReferenceDataForEntityAndId, getGlobalOptionSetValue, getReferenceDataForEntity } from '../reference-data.service.js'
|
|
15
|
+
import { processRecurringPayment } from '../recurring-payments.service.js'
|
|
16
16
|
import { resolveContactPayload } from '../contacts.service.js'
|
|
17
17
|
import { retrieveStagedTransaction } from './retrieve-transaction.js'
|
|
18
18
|
import { TRANSACTION_STAGING_TABLE, TRANSACTION_STAGING_HISTORY_TABLE } from '../../config.js'
|
|
19
|
-
import moment from 'moment'
|
|
20
19
|
import { AWS } from '@defra-fish/connectors-lib'
|
|
21
20
|
import db from 'debug'
|
|
21
|
+
import moment from 'moment'
|
|
22
22
|
const { docClient } = AWS()
|
|
23
23
|
const debug = db('sales:transactions')
|
|
24
24
|
|
|
@@ -38,9 +38,6 @@ export async function processQueue ({ id }) {
|
|
|
38
38
|
const { transaction, chargeJournal, paymentJournal } = await createTransactionEntities(transactionRecord)
|
|
39
39
|
entities.push(transaction, chargeJournal, paymentJournal)
|
|
40
40
|
|
|
41
|
-
const { recurringPayment, payer } = await processRecurringPayment(transactionRecord)
|
|
42
|
-
recurringPayment && entities.push(recurringPayment, payer)
|
|
43
|
-
|
|
44
41
|
const totalTransactionValue = transactionRecord.payment.amount
|
|
45
42
|
const dataSource = await getGlobalOptionSetValue(Permission.definition.mappings.dataSource.ref, transactionRecord.dataSource)
|
|
46
43
|
for (const {
|
|
@@ -68,6 +65,11 @@ export async function processQueue ({ id }) {
|
|
|
68
65
|
isRenewal
|
|
69
66
|
)
|
|
70
67
|
|
|
68
|
+
const { recurringPayment } = await processRecurringPayment(transactionRecord, contact)
|
|
69
|
+
if (recurringPayment) {
|
|
70
|
+
entities.push(recurringPayment)
|
|
71
|
+
}
|
|
72
|
+
|
|
71
73
|
permission.bindToEntity(Permission.definition.relationships.licensee, contact)
|
|
72
74
|
permission.bindToEntity(Permission.definition.relationships.permit, permit)
|
|
73
75
|
permission.bindToEntity(Permission.definition.relationships.transaction, transaction)
|
|
@@ -142,27 +144,6 @@ const mapToPermission = async (
|
|
|
142
144
|
return permission
|
|
143
145
|
}
|
|
144
146
|
|
|
145
|
-
/**
|
|
146
|
-
* Process a recurring payment instruction
|
|
147
|
-
* @param transactionRecord
|
|
148
|
-
* @returns {Promise<{recurringPayment: null, payer: null}>}
|
|
149
|
-
*/
|
|
150
|
-
const processRecurringPayment = async transactionRecord => {
|
|
151
|
-
let recurringPayment = null
|
|
152
|
-
let payer = null
|
|
153
|
-
if (transactionRecord.payment.recurring) {
|
|
154
|
-
const inceptionMoment = moment(transactionRecord.payment.timestamp, true).utc()
|
|
155
|
-
recurringPayment = new RecurringPayment()
|
|
156
|
-
recurringPayment.referenceNumber = transactionRecord.payment.recurring.referenceNumber
|
|
157
|
-
recurringPayment.mandate = transactionRecord.payment.recurring.mandate
|
|
158
|
-
recurringPayment.inceptionDay = inceptionMoment.date()
|
|
159
|
-
recurringPayment.inceptionMonth = inceptionMoment.month()
|
|
160
|
-
payer = await resolveContactPayload(transactionRecord.payment.recurring.payer)
|
|
161
|
-
recurringPayment.bindToEntity(RecurringPayment.definition.relationships.contact, payer)
|
|
162
|
-
}
|
|
163
|
-
return { recurringPayment, payer }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
147
|
/**
|
|
167
148
|
* Create transaction entities required to represent this transaction payload
|
|
168
149
|
*
|