@mojaloop/central-ledger 17.7.8 → 17.8.0-orb.1
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/.ncurc.yaml +3 -1
- package/.nvmrc +1 -1
- package/.nycrc.yml +16 -1
- package/Dockerfile +9 -10
- package/README.md +39 -9
- package/audit-ci.jsonc +15 -2
- package/config/default.json +17 -1
- package/docker/central-ledger/default.json +9 -0
- package/docker/config-modifier/configs/central-ledger.js +25 -0
- package/docker/env.sh +15 -0
- package/docker/kafka/scripts/provision.sh +4 -1
- package/docker/ml-api-adapter/default.json +4 -1
- package/docker-compose.yml +90 -2
- package/documentation/db/erd-transfer-timeout.png +0 -0
- package/documentation/db/erd-transfer-timeout.txt +81 -0
- package/documentation/fx-implementation/README.md +48 -0
- package/documentation/fx-implementation/assets/fx-position-movements.drawio.svg +4 -0
- package/documentation/fx-implementation/assets/test-scenario.drawio.svg +4 -0
- package/documentation/sequence-diagrams/Handler - FX timeout.plantuml +123 -0
- package/documentation/sequence-diagrams/Handler - FX timeout.png +0 -0
- package/documentation/sequence-diagrams/Handler - timeout.plantuml +81 -0
- package/documentation/sequence-diagrams/Handler - timeout.png +0 -0
- package/documentation/state-diagrams/transfer-ML-spec-states-diagram.png +0 -0
- package/documentation/state-diagrams/transfer-internal-states-diagram.png +0 -0
- package/documentation/state-diagrams/transfer-internal-states.plantuml +75 -0
- package/documentation/state-diagrams/transfer-states.plantuml +13 -0
- package/migrations/310204_transferParticipant-participantId.js +52 -0
- package/migrations/310403_participantPositionChange-participantCurrencyId.js +47 -0
- package/migrations/310404_participantPositionChange-change.js +46 -0
- package/migrations/600010_fxTransferType.js +43 -0
- package/migrations/600011_fxTransferType-indexes.js +38 -0
- package/migrations/600012_fxParticipantCurrencyType.js +43 -0
- package/migrations/600013_fxParticipantCurrencyType-indexes.js +38 -0
- package/migrations/600100_fxTransferDuplicateCheck.js +42 -0
- package/migrations/600110_fxTransferErrorDuplicateCheck.js.js +17 -0
- package/migrations/600200_fxTransfer.js +51 -0
- package/migrations/600201_fxTransfer-indexes.js +40 -0
- package/migrations/600400_fxTransferStateChange.js +46 -0
- package/migrations/600401_fxTransferStateChange-indexes.js +40 -0
- package/migrations/600501_fxWatchList.js +46 -0
- package/migrations/600502_fxWatchList-indexes.js +40 -0
- package/migrations/600600_fxTransferFulfilmentDuplicateCheck.js +43 -0
- package/migrations/600601_fxTransferFulfilmentDuplicateCheck-indexes.js +38 -0
- package/migrations/600700_fxTransferFulfilment.js +47 -0
- package/migrations/600701_fxTransferFulfilment-indexes.js +43 -0
- package/migrations/600800_fxTransferExtension.js +47 -0
- package/migrations/601400_fxTransferTimeout.js +43 -0
- package/migrations/601401_fxTransferTimeout-indexes.js +37 -0
- package/migrations/601500_fxTransferError.js +44 -0
- package/migrations/601501_fxTransferError-indexes.js +37 -0
- package/migrations/610200_fxTransferParticipant.js +52 -0
- package/migrations/610201_fxTransferParticipant-indexes.js +44 -0
- package/migrations/610202_fxTransferParticipant-participantId.js +52 -0
- package/migrations/610403_participantPositionChange-fxTransfer.js +46 -0
- package/migrations/910101_feature904DataMigration.js +46 -52
- package/migrations/910102_feature949DataMigration.js +219 -225
- package/migrations/950104_settlementModel-settlementAccountTypeId.js +15 -20
- package/migrations/950108_participantProxy.js +18 -0
- package/migrations/950109_fxQuote.js +19 -0
- package/migrations/950110_fxQuoteResponse.js +25 -0
- package/migrations/950111_fxQuoteError.js +23 -0
- package/migrations/950113_fxQuoteDuplicateCheck.js +18 -0
- package/migrations/950114_fxQuoteResponseDuplicateCheck.js +21 -0
- package/migrations/950115_fxQuoteConversionTerms.js +36 -0
- package/migrations/950116_fxQuoteConversionTermsExtension.js +21 -0
- package/migrations/950117_fxQuoteResponseConversionTerms.js +39 -0
- package/migrations/950118_fxQuoteResponseConversionTermsExtension.js +21 -0
- package/migrations/950119_fxCharge.js +27 -0
- package/migrations/960100_create_externalParticipant.js +47 -0
- package/migrations/960110_alter_transferParticipant__addFiled_externalParticipantId.js +50 -0
- package/migrations/960111_alter_fxTransferParticipant__addFiled_externalParticipantId.js +50 -0
- package/package.json +27 -20
- package/seeds/endpointType.js +18 -0
- package/seeds/fxParticipantCurrencyType.js +45 -0
- package/seeds/fxTransferType.js +45 -0
- package/seeds/participant.js +2 -1
- package/seeds/transferParticipantRoleType.js +9 -0
- package/seeds/transferState.js +10 -0
- package/src/api/interface/swagger.json +23 -30
- package/src/api/participants/handler.js +6 -2
- package/src/api/participants/routes.js +8 -7
- package/src/api/root/handler.js +15 -5
- package/src/domain/fx/cyril.js +466 -0
- package/src/domain/fx/index.js +107 -0
- package/src/domain/participant/index.js +108 -1
- package/src/domain/position/abort.js +215 -0
- package/src/domain/position/binProcessor.js +361 -99
- package/src/domain/position/fulfil.js +252 -111
- package/src/domain/position/fx-fulfil.js +138 -0
- package/src/domain/position/fx-prepare.js +280 -0
- package/src/domain/position/fx-timeout-reserved.js +159 -0
- package/src/domain/position/index.js +1 -0
- package/src/domain/position/prepare.js +69 -49
- package/src/domain/position/timeout-reserved.js +162 -0
- package/src/domain/timeout/index.js +26 -2
- package/src/domain/transfer/index.js +22 -5
- package/src/domain/transfer/transform.js +19 -6
- package/src/handlers/admin/handler.js +0 -2
- package/src/handlers/bulk/fulfil/handler.js +5 -5
- package/src/handlers/bulk/get/handler.js +5 -5
- package/src/handlers/bulk/prepare/handler.js +9 -9
- package/src/handlers/bulk/processing/handler.js +8 -7
- package/src/handlers/bulk/shared/validator.js +1 -1
- package/src/handlers/positions/handler.js +23 -10
- package/src/handlers/positions/handlerBatch.js +54 -26
- package/src/handlers/register.js +2 -1
- package/src/handlers/timeouts/handler.js +212 -68
- package/src/handlers/transfers/FxFulfilService.js +387 -0
- package/src/handlers/transfers/createRemittanceEntity.js +106 -0
- package/src/handlers/transfers/dto.js +53 -0
- package/src/handlers/transfers/handler.js +609 -571
- package/src/handlers/transfers/prepare.js +572 -0
- package/src/handlers/transfers/validator.js +75 -14
- package/src/lib/cache.js +1 -1
- package/src/lib/config.js +6 -3
- package/src/lib/healthCheck/subServiceHealth.js +12 -2
- package/src/lib/proxyCache.js +131 -0
- package/src/models/bulkTransfer/facade.js +58 -82
- package/src/models/fxTransfer/duplicateCheck.js +153 -0
- package/src/models/fxTransfer/fxTransfer.js +578 -0
- package/src/models/fxTransfer/fxTransferError.js +53 -0
- package/src/models/fxTransfer/fxTransferExtension.js +41 -0
- package/src/models/fxTransfer/fxTransferTimeout.js +68 -0
- package/src/models/fxTransfer/index.js +15 -0
- package/src/models/fxTransfer/stateChange.js +47 -0
- package/src/models/fxTransfer/watchList.js +49 -0
- package/src/models/ledgerAccountType/ledgerAccountType.js +8 -32
- package/src/models/misc/segment.js +0 -1
- package/src/models/participant/externalParticipant.js +96 -0
- package/src/models/participant/externalParticipantCached.js +148 -0
- package/src/models/participant/facade.js +192 -123
- package/src/models/participant/participant.js +2 -1
- package/src/models/participant/participantCurrency.js +1 -1
- package/src/models/participant/participantPosition.js +2 -8
- package/src/models/position/batch.js +90 -1
- package/src/models/position/facade.js +5 -5
- package/src/models/position/participantPositionChanges.js +68 -0
- package/src/models/settlement/settlementModel.js +5 -23
- package/src/models/transfer/facade.js +806 -447
- package/src/shared/constants.js +52 -0
- package/src/shared/fspiopErrorFactory.js +131 -0
- package/src/shared/logger/index.js +8 -0
- package/src/shared/loggingPlugin.js +43 -0
- package/src/shared/plugins.js +6 -0
- package/src/shared/setup.js +10 -0
- package/test-integration.Dockerfile +1 -1
- package/test.Dockerfile +1 -1
|
@@ -42,6 +42,7 @@ const KafkaProducer = require('@mojaloop/central-services-stream').Util.Producer
|
|
|
42
42
|
const { randomUUID } = require('crypto')
|
|
43
43
|
const Enum = require('@mojaloop/central-services-shared').Enum
|
|
44
44
|
const Enums = require('../../lib/enumCached')
|
|
45
|
+
const { logger } = require('../../shared/logger')
|
|
45
46
|
|
|
46
47
|
// Alphabetically ordered list of error texts used below
|
|
47
48
|
const AccountInactiveErrorText = 'Account is currently set inactive'
|
|
@@ -58,9 +59,12 @@ const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
|
58
59
|
const { destroyParticipantEndpointByParticipantId } = require('../../models/participant/participant')
|
|
59
60
|
|
|
60
61
|
const create = async (payload) => {
|
|
62
|
+
const log = logger.child({ payload })
|
|
61
63
|
try {
|
|
62
|
-
|
|
64
|
+
log.info('creating participant with payload')
|
|
65
|
+
return ParticipantModel.create({ name: payload.name, isProxy: !!payload.isProxy })
|
|
63
66
|
} catch (err) {
|
|
67
|
+
log.error('error creating participant', err)
|
|
64
68
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
65
69
|
}
|
|
66
70
|
}
|
|
@@ -71,13 +75,16 @@ const getAll = async () => {
|
|
|
71
75
|
await Promise.all(all.map(async (participant) => {
|
|
72
76
|
participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId)
|
|
73
77
|
}))
|
|
78
|
+
logger.debug('getAll participants', { participants: all })
|
|
74
79
|
return all
|
|
75
80
|
} catch (err) {
|
|
81
|
+
logger.error('error getting all participants', err)
|
|
76
82
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
const getById = async (id) => {
|
|
87
|
+
logger.debug('getting participant by id', { id })
|
|
81
88
|
const participant = await ParticipantModel.getById(id)
|
|
82
89
|
if (participant) {
|
|
83
90
|
participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId)
|
|
@@ -86,6 +93,7 @@ const getById = async (id) => {
|
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
const getByName = async (name) => {
|
|
96
|
+
logger.debug('getting participant by name', { name })
|
|
89
97
|
const participant = await ParticipantModel.getByName(name)
|
|
90
98
|
if (participant) {
|
|
91
99
|
participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId)
|
|
@@ -94,17 +102,23 @@ const getByName = async (name) => {
|
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
const participantExists = (participant, checkIsActive = false) => {
|
|
105
|
+
const log = logger.child({ participant, checkIsActive })
|
|
106
|
+
log.debug('checking if participant exists')
|
|
97
107
|
if (participant) {
|
|
98
108
|
if (!checkIsActive || participant.isActive) {
|
|
99
109
|
return participant
|
|
100
110
|
}
|
|
111
|
+
log.warn('participant is inactive')
|
|
101
112
|
throw ErrorHandler.Factory.createInternalServerFSPIOPError(ParticipantInactiveText)
|
|
102
113
|
}
|
|
114
|
+
log.warn('participant not found')
|
|
103
115
|
throw ErrorHandler.Factory.createInternalServerFSPIOPError(ParticipantNotFoundText)
|
|
104
116
|
}
|
|
105
117
|
|
|
106
118
|
const update = async (name, payload) => {
|
|
119
|
+
const log = logger.child({ name, payload })
|
|
107
120
|
try {
|
|
121
|
+
log.info('updating participant')
|
|
108
122
|
const participant = await ParticipantModel.getByName(name)
|
|
109
123
|
participantExists(participant)
|
|
110
124
|
await ParticipantModel.update(participant, payload.isActive)
|
|
@@ -112,38 +126,50 @@ const update = async (name, payload) => {
|
|
|
112
126
|
participant.currencyList = await ParticipantCurrencyModel.getByParticipantId(participant.participantId)
|
|
113
127
|
return participant
|
|
114
128
|
} catch (err) {
|
|
129
|
+
log.error('error updating participant', err)
|
|
115
130
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
116
131
|
}
|
|
117
132
|
}
|
|
118
133
|
|
|
119
134
|
const createParticipantCurrency = async (participantId, currencyId, ledgerAccountTypeId, isActive = true) => {
|
|
135
|
+
const log = logger.child({ participantId, currencyId, ledgerAccountTypeId, isActive })
|
|
120
136
|
try {
|
|
137
|
+
log.info('creating participant currency')
|
|
121
138
|
const participantCurrency = await ParticipantCurrencyModel.create(participantId, currencyId, ledgerAccountTypeId, isActive)
|
|
122
139
|
return participantCurrency
|
|
123
140
|
} catch (err) {
|
|
141
|
+
log.error('error creating participant currency', err)
|
|
124
142
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
125
143
|
}
|
|
126
144
|
}
|
|
127
145
|
|
|
128
146
|
const createHubAccount = async (participantId, currencyId, ledgerAccountTypeId) => {
|
|
147
|
+
const log = logger.child({ participantId, currencyId, ledgerAccountTypeId })
|
|
129
148
|
try {
|
|
149
|
+
log.info('creating hub account')
|
|
130
150
|
const participantCurrency = await ParticipantFacade.addHubAccountAndInitPosition(participantId, currencyId, ledgerAccountTypeId)
|
|
131
151
|
return participantCurrency
|
|
132
152
|
} catch (err) {
|
|
153
|
+
log.error('error creating hub account', err)
|
|
133
154
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
134
155
|
}
|
|
135
156
|
}
|
|
136
157
|
|
|
137
158
|
const getParticipantCurrencyById = async (participantCurrencyId) => {
|
|
159
|
+
const log = logger.child({ participantCurrencyId })
|
|
138
160
|
try {
|
|
161
|
+
log.debug('getting participant currency by id')
|
|
139
162
|
return await ParticipantCurrencyModel.getById(participantCurrencyId)
|
|
140
163
|
} catch (err) {
|
|
164
|
+
log.error('error getting participant currency by id', err)
|
|
141
165
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
142
166
|
}
|
|
143
167
|
}
|
|
144
168
|
|
|
145
169
|
const destroyByName = async (name) => {
|
|
170
|
+
const log = logger.child({ name })
|
|
146
171
|
try {
|
|
172
|
+
log.debug('destroying participant by name')
|
|
147
173
|
const participant = await ParticipantModel.getByName(name)
|
|
148
174
|
await ParticipantLimitModel.destroyByParticipantId(participant.participantId)
|
|
149
175
|
await ParticipantPositionModel.destroyByParticipantId(participant.participantId)
|
|
@@ -151,6 +177,7 @@ const destroyByName = async (name) => {
|
|
|
151
177
|
await destroyParticipantEndpointByParticipantId(participant.participantId)
|
|
152
178
|
return await ParticipantModel.destroyByName(name)
|
|
153
179
|
} catch (err) {
|
|
180
|
+
log.error('error destroying participant by name', err)
|
|
154
181
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
155
182
|
}
|
|
156
183
|
}
|
|
@@ -174,11 +201,15 @@ const destroyByName = async (name) => {
|
|
|
174
201
|
*/
|
|
175
202
|
|
|
176
203
|
const addEndpoint = async (name, payload) => {
|
|
204
|
+
const log = logger.child({ name, payload })
|
|
177
205
|
try {
|
|
206
|
+
log.info('adding endpoint')
|
|
178
207
|
const participant = await ParticipantModel.getByName(name)
|
|
179
208
|
participantExists(participant)
|
|
209
|
+
log.info('adding endpoint for participant', { participant })
|
|
180
210
|
return ParticipantFacade.addEndpoint(participant.participantId, payload)
|
|
181
211
|
} catch (err) {
|
|
212
|
+
log.error('error adding endpoint', err)
|
|
182
213
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
183
214
|
}
|
|
184
215
|
}
|
|
@@ -199,11 +230,15 @@ const addEndpoint = async (name, payload) => {
|
|
|
199
230
|
*/
|
|
200
231
|
|
|
201
232
|
const getEndpoint = async (name, type) => {
|
|
233
|
+
const log = logger.child({ name, type })
|
|
202
234
|
try {
|
|
235
|
+
log.debug('getting endpoint')
|
|
203
236
|
const participant = await ParticipantModel.getByName(name)
|
|
204
237
|
participantExists(participant)
|
|
238
|
+
log.debug('getting endpoint for participant', { participant })
|
|
205
239
|
return ParticipantFacade.getEndpoint(participant.participantId, type)
|
|
206
240
|
} catch (err) {
|
|
241
|
+
log.error('error getting endpoint', err)
|
|
207
242
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
208
243
|
}
|
|
209
244
|
}
|
|
@@ -223,11 +258,15 @@ const getEndpoint = async (name, type) => {
|
|
|
223
258
|
*/
|
|
224
259
|
|
|
225
260
|
const getAllEndpoints = async (name) => {
|
|
261
|
+
const log = logger.child({ name })
|
|
226
262
|
try {
|
|
263
|
+
log.debug('getting all endpoints for participant name')
|
|
227
264
|
const participant = await ParticipantModel.getByName(name)
|
|
228
265
|
participantExists(participant)
|
|
266
|
+
log.debug('getting all endpoints for participant', { participant })
|
|
229
267
|
return ParticipantFacade.getAllEndpoints(participant.participantId)
|
|
230
268
|
} catch (err) {
|
|
269
|
+
log.error('error getting all endpoints', err)
|
|
231
270
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
232
271
|
}
|
|
233
272
|
}
|
|
@@ -245,11 +284,15 @@ const getAllEndpoints = async (name) => {
|
|
|
245
284
|
*/
|
|
246
285
|
|
|
247
286
|
const destroyParticipantEndpointByName = async (name) => {
|
|
287
|
+
const log = logger.child({ name })
|
|
248
288
|
try {
|
|
289
|
+
log.debug('destroying participant endpoint by name')
|
|
249
290
|
const participant = await ParticipantModel.getByName(name)
|
|
250
291
|
participantExists(participant)
|
|
292
|
+
log.debug('destroying participant endpoint for participant', { participant })
|
|
251
293
|
return ParticipantModel.destroyParticipantEndpointByParticipantId(participant.participantId)
|
|
252
294
|
} catch (err) {
|
|
295
|
+
log.error('error destroying participant endpoint by name', err)
|
|
253
296
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
254
297
|
}
|
|
255
298
|
}
|
|
@@ -278,14 +321,18 @@ const destroyParticipantEndpointByName = async (name) => {
|
|
|
278
321
|
*/
|
|
279
322
|
|
|
280
323
|
const addLimitAndInitialPosition = async (participantName, limitAndInitialPositionObj) => {
|
|
324
|
+
const log = logger.child({ participantName, limitAndInitialPositionObj })
|
|
281
325
|
try {
|
|
326
|
+
log.debug('adding limit and initial position', { participantName, limitAndInitialPositionObj })
|
|
282
327
|
const participant = await ParticipantFacade.getByNameAndCurrency(participantName, limitAndInitialPositionObj.currency, Enum.Accounts.LedgerAccountType.POSITION)
|
|
283
328
|
participantExists(participant)
|
|
329
|
+
log.debug('adding limit and initial position for participant', { participant })
|
|
284
330
|
const settlementAccount = await ParticipantFacade.getByNameAndCurrency(participantName, limitAndInitialPositionObj.currency, Enum.Accounts.LedgerAccountType.SETTLEMENT)
|
|
285
331
|
const existingLimit = await ParticipantLimitModel.getByParticipantCurrencyId(participant.participantCurrencyId)
|
|
286
332
|
const existingPosition = await ParticipantPositionModel.getByParticipantCurrencyId(participant.participantCurrencyId)
|
|
287
333
|
const existingSettlementPosition = await ParticipantPositionModel.getByParticipantCurrencyId(settlementAccount.participantCurrencyId)
|
|
288
334
|
if (existingLimit || existingPosition || existingSettlementPosition) {
|
|
335
|
+
log.warn('participant limit or initial position already set')
|
|
289
336
|
throw ErrorHandler.Factory.createInternalServerFSPIOPError(ParticipantInitialPositionExistsText)
|
|
290
337
|
}
|
|
291
338
|
const limitAndInitialPosition = Object.assign({}, limitAndInitialPositionObj, { name: participantName })
|
|
@@ -296,6 +343,7 @@ const addLimitAndInitialPosition = async (participantName, limitAndInitialPositi
|
|
|
296
343
|
await Kafka.produceGeneralMessage(Config.KAFKA_CONFIG, KafkaProducer, Enum.Events.Event.Type.NOTIFICATION, Enum.Transfers.AdminNotificationActions.LIMIT_ADJUSTMENT, createLimitAdjustmentMessageProtocol(payload), Enum.Events.EventStatus.SUCCESS)
|
|
297
344
|
return ParticipantFacade.addLimitAndInitialPosition(participant.participantCurrencyId, settlementAccount.participantCurrencyId, limitAndInitialPosition, true)
|
|
298
345
|
} catch (err) {
|
|
346
|
+
log.error('error adding limit and initial position', err)
|
|
299
347
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
300
348
|
}
|
|
301
349
|
}
|
|
@@ -313,9 +361,12 @@ const addLimitAndInitialPosition = async (participantName, limitAndInitialPositi
|
|
|
313
361
|
*/
|
|
314
362
|
|
|
315
363
|
const getPositionByParticipantCurrencyId = async (participantCurrencyId) => {
|
|
364
|
+
const log = logger.child({ participantCurrencyId })
|
|
316
365
|
try {
|
|
366
|
+
log.debug('getting position by participant currency id')
|
|
317
367
|
return ParticipantPositionModel.getByParticipantCurrencyId(participantCurrencyId)
|
|
318
368
|
} catch (err) {
|
|
369
|
+
log.error('error getting position by participant currency id', err)
|
|
319
370
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
320
371
|
}
|
|
321
372
|
}
|
|
@@ -333,9 +384,12 @@ const getPositionByParticipantCurrencyId = async (participantCurrencyId) => {
|
|
|
333
384
|
*/
|
|
334
385
|
|
|
335
386
|
const getPositionChangeByParticipantPositionId = async (participantPositionId) => {
|
|
387
|
+
const log = logger.child({ participantPositionId })
|
|
336
388
|
try {
|
|
389
|
+
log.debug('getting position change by participant position id')
|
|
337
390
|
return ParticipantPositionChangeModel.getByParticipantPositionId(participantPositionId)
|
|
338
391
|
} catch (err) {
|
|
392
|
+
log.error('error getting position change by participant position id', err)
|
|
339
393
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
340
394
|
}
|
|
341
395
|
}
|
|
@@ -353,11 +407,15 @@ const getPositionChangeByParticipantPositionId = async (participantPositionId) =
|
|
|
353
407
|
*/
|
|
354
408
|
|
|
355
409
|
const destroyParticipantPositionByNameAndCurrency = async (name, currencyId) => {
|
|
410
|
+
const log = logger.child({ name, currencyId })
|
|
356
411
|
try {
|
|
412
|
+
log.debug('destroying participant position by participant name and currency')
|
|
357
413
|
const participant = await ParticipantFacade.getByNameAndCurrency(name, currencyId, Enum.Accounts.LedgerAccountType.POSITION)
|
|
414
|
+
log.debug('destroying participant position for participant', { participant })
|
|
358
415
|
participantExists(participant)
|
|
359
416
|
return ParticipantPositionModel.destroyByParticipantCurrencyId(participant.participantCurrencyId)
|
|
360
417
|
} catch (err) {
|
|
418
|
+
log.error('error destroying participant position by name and currency', err)
|
|
361
419
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
362
420
|
}
|
|
363
421
|
}
|
|
@@ -376,11 +434,15 @@ const destroyParticipantPositionByNameAndCurrency = async (name, currencyId) =>
|
|
|
376
434
|
*/
|
|
377
435
|
|
|
378
436
|
const destroyParticipantLimitByNameAndCurrency = async (name, currencyId) => {
|
|
437
|
+
const log = logger.child({ name, currencyId })
|
|
379
438
|
try {
|
|
439
|
+
log.debug('destroying participant limit by participant name and currency')
|
|
380
440
|
const participant = await ParticipantFacade.getByNameAndCurrency(name, currencyId, Enum.Accounts.LedgerAccountType.POSITION)
|
|
441
|
+
log.debug('destroying participant limit for participant', { participant })
|
|
381
442
|
participantExists(participant)
|
|
382
443
|
return ParticipantLimitModel.destroyByParticipantCurrencyId(participant.participantCurrencyId)
|
|
383
444
|
} catch (err) {
|
|
445
|
+
log.error('error destroying participant limit by name and currency', err)
|
|
384
446
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
385
447
|
}
|
|
386
448
|
}
|
|
@@ -403,18 +465,24 @@ const destroyParticipantLimitByNameAndCurrency = async (name, currencyId) => {
|
|
|
403
465
|
*/
|
|
404
466
|
|
|
405
467
|
const getLimits = async (name, { currency = null, type = null }) => {
|
|
468
|
+
const log = logger.child({ name, currency, type })
|
|
406
469
|
try {
|
|
407
470
|
let participant
|
|
408
471
|
if (currency != null) {
|
|
472
|
+
log.debug('getting limits by name and currency')
|
|
409
473
|
participant = await ParticipantFacade.getByNameAndCurrency(name, currency, Enum.Accounts.LedgerAccountType.POSITION)
|
|
474
|
+
log.debug('getting limits for participant', { participant })
|
|
410
475
|
participantExists(participant)
|
|
411
476
|
return ParticipantFacade.getParticipantLimitsByCurrencyId(participant.participantCurrencyId, type)
|
|
412
477
|
} else {
|
|
478
|
+
log.debug('getting limits by name')
|
|
413
479
|
participant = await ParticipantModel.getByName(name)
|
|
480
|
+
log.debug('getting limits for participant', { participant })
|
|
414
481
|
participantExists(participant)
|
|
415
482
|
return ParticipantFacade.getParticipantLimitsByParticipantId(participant.participantId, type, Enum.Accounts.LedgerAccountType.POSITION)
|
|
416
483
|
}
|
|
417
484
|
} catch (err) {
|
|
485
|
+
log.error('error getting limits', err)
|
|
418
486
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
419
487
|
}
|
|
420
488
|
}
|
|
@@ -434,9 +502,12 @@ const getLimits = async (name, { currency = null, type = null }) => {
|
|
|
434
502
|
*/
|
|
435
503
|
|
|
436
504
|
const getLimitsForAllParticipants = async ({ currency = null, type = null }) => {
|
|
505
|
+
const log = logger.child({ currency, type })
|
|
437
506
|
try {
|
|
507
|
+
log.debug('getting limits for all participants', { currency, type })
|
|
438
508
|
return ParticipantFacade.getLimitsForAllParticipants(currency, type, Enum.Accounts.LedgerAccountType.POSITION)
|
|
439
509
|
} catch (err) {
|
|
510
|
+
log.error('error getting limits for all participants', err)
|
|
440
511
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
441
512
|
}
|
|
442
513
|
}
|
|
@@ -465,15 +536,19 @@ const getLimitsForAllParticipants = async ({ currency = null, type = null }) =>
|
|
|
465
536
|
*/
|
|
466
537
|
|
|
467
538
|
const adjustLimits = async (name, payload) => {
|
|
539
|
+
const log = logger.child({ name, payload })
|
|
468
540
|
try {
|
|
541
|
+
log.debug('adjusting limits')
|
|
469
542
|
const { limit, currency } = payload
|
|
470
543
|
const participant = await ParticipantFacade.getByNameAndCurrency(name, currency, Enum.Accounts.LedgerAccountType.POSITION)
|
|
544
|
+
log.debug('adjusting limits for participant', { participant })
|
|
471
545
|
participantExists(participant)
|
|
472
546
|
const result = await ParticipantFacade.adjustLimits(participant.participantCurrencyId, limit)
|
|
473
547
|
payload.name = name
|
|
474
548
|
await Kafka.produceGeneralMessage(Config.KAFKA_CONFIG, KafkaProducer, Enum.Events.Event.Type.NOTIFICATION, Enum.Transfers.AdminNotificationActions.LIMIT_ADJUSTMENT, createLimitAdjustmentMessageProtocol(payload), Enum.Events.EventStatus.SUCCESS)
|
|
475
549
|
return result
|
|
476
550
|
} catch (err) {
|
|
551
|
+
log.error('error adjusting limits', err)
|
|
477
552
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
478
553
|
}
|
|
479
554
|
}
|
|
@@ -546,9 +621,12 @@ const createLimitAdjustmentMessageProtocol = (payload, action = Enum.Transfers.A
|
|
|
546
621
|
*/
|
|
547
622
|
|
|
548
623
|
const getPositions = async (name, query) => {
|
|
624
|
+
const log = logger.child({ name, query })
|
|
549
625
|
try {
|
|
626
|
+
log.debug('getting positions')
|
|
550
627
|
if (query.currency) {
|
|
551
628
|
const participant = await ParticipantFacade.getByNameAndCurrency(name, query.currency, Enum.Accounts.LedgerAccountType.POSITION)
|
|
629
|
+
log.debug('getting positions for participant', { participant })
|
|
552
630
|
participantExists(participant)
|
|
553
631
|
const result = await PositionFacade.getByNameAndCurrency(name, Enum.Accounts.LedgerAccountType.POSITION, query.currency) // TODO this function only takes a max of 3 params, this has 4
|
|
554
632
|
let position = {}
|
|
@@ -559,9 +637,11 @@ const getPositions = async (name, query) => {
|
|
|
559
637
|
changedDate: result[0].changedDate
|
|
560
638
|
}
|
|
561
639
|
}
|
|
640
|
+
log.debug('found positions for participant', { participant, position })
|
|
562
641
|
return position
|
|
563
642
|
} else {
|
|
564
643
|
const participant = await ParticipantModel.getByName(name)
|
|
644
|
+
log.debug('getting positions for participant', { participant })
|
|
565
645
|
participantExists(participant)
|
|
566
646
|
const result = await await PositionFacade.getByNameAndCurrency(name, Enum.Accounts.LedgerAccountType.POSITION)
|
|
567
647
|
const positions = []
|
|
@@ -574,16 +654,21 @@ const getPositions = async (name, query) => {
|
|
|
574
654
|
})
|
|
575
655
|
})
|
|
576
656
|
}
|
|
657
|
+
log.debug('found positions for participant', { participant, positions })
|
|
577
658
|
return positions
|
|
578
659
|
}
|
|
579
660
|
} catch (err) {
|
|
661
|
+
log.error('error getting positions', err)
|
|
580
662
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
581
663
|
}
|
|
582
664
|
}
|
|
583
665
|
|
|
584
666
|
const getAccounts = async (name, query) => {
|
|
667
|
+
const log = logger.child({ name, query })
|
|
585
668
|
try {
|
|
669
|
+
log.debug('getting accounts')
|
|
586
670
|
const participant = await ParticipantModel.getByName(name)
|
|
671
|
+
log.debug('getting accounts for participant', { participant })
|
|
587
672
|
participantExists(participant)
|
|
588
673
|
const result = await PositionFacade.getAllByNameAndCurrency(name, query.currency)
|
|
589
674
|
const positions = []
|
|
@@ -600,18 +685,24 @@ const getAccounts = async (name, query) => {
|
|
|
600
685
|
})
|
|
601
686
|
})
|
|
602
687
|
}
|
|
688
|
+
log.debug('found accounts for participant', { participant, positions })
|
|
603
689
|
return positions
|
|
604
690
|
} catch (err) {
|
|
691
|
+
log.error('error getting accounts', err)
|
|
605
692
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
606
693
|
}
|
|
607
694
|
}
|
|
608
695
|
|
|
609
696
|
const updateAccount = async (payload, params, enums) => {
|
|
697
|
+
const log = logger.child({ payload, params, enums })
|
|
610
698
|
try {
|
|
699
|
+
log.debug('updating account')
|
|
611
700
|
const { name, id } = params
|
|
612
701
|
const participant = await ParticipantModel.getByName(name)
|
|
702
|
+
log.debug('updating account for participant', { participant })
|
|
613
703
|
participantExists(participant)
|
|
614
704
|
const account = await ParticipantCurrencyModel.getById(id)
|
|
705
|
+
log.debug('updating account for participant', { participant, account })
|
|
615
706
|
if (!account) {
|
|
616
707
|
throw ErrorHandler.Factory.createInternalServerFSPIOPError(AccountNotFoundErrorText)
|
|
617
708
|
} else if (account.participantId !== participant.participantId) {
|
|
@@ -621,22 +712,29 @@ const updateAccount = async (payload, params, enums) => {
|
|
|
621
712
|
}
|
|
622
713
|
return await ParticipantCurrencyModel.update(id, payload.isActive)
|
|
623
714
|
} catch (err) {
|
|
715
|
+
log.error('error updating account', err)
|
|
624
716
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
625
717
|
}
|
|
626
718
|
}
|
|
627
719
|
|
|
628
720
|
const getLedgerAccountTypeName = async (name) => {
|
|
721
|
+
const log = logger.child({ name })
|
|
629
722
|
try {
|
|
723
|
+
log.debug('getting ledger account type by name')
|
|
630
724
|
return await LedgerAccountTypeModel.getLedgerAccountByName(name)
|
|
631
725
|
} catch (err) {
|
|
726
|
+
log.error('error getting ledger account type by name', err)
|
|
632
727
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
633
728
|
}
|
|
634
729
|
}
|
|
635
730
|
|
|
636
731
|
const getParticipantAccount = async (accountParams) => {
|
|
732
|
+
const log = logger.child({ accountParams })
|
|
637
733
|
try {
|
|
734
|
+
log.debug('getting participant account by params')
|
|
638
735
|
return await ParticipantCurrencyModel.findOneByParams(accountParams)
|
|
639
736
|
} catch (err) {
|
|
737
|
+
log.error('error getting participant account by params', err)
|
|
640
738
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
641
739
|
}
|
|
642
740
|
}
|
|
@@ -690,7 +788,9 @@ const setPayerPayeeFundsInOut = (fspName, payload, enums) => {
|
|
|
690
788
|
}
|
|
691
789
|
|
|
692
790
|
const recordFundsInOut = async (payload, params, enums) => {
|
|
791
|
+
const log = logger.child({ payload, params, enums })
|
|
693
792
|
try {
|
|
793
|
+
log.debug('recording funds in/out')
|
|
694
794
|
const { name, id, transferId } = params
|
|
695
795
|
const participant = await ParticipantModel.getByName(name)
|
|
696
796
|
const currency = (payload.amount && payload.amount.currency) || null
|
|
@@ -699,6 +799,7 @@ const recordFundsInOut = async (payload, params, enums) => {
|
|
|
699
799
|
participantExists(participant, checkIsActive)
|
|
700
800
|
const accounts = await ParticipantFacade.getAllAccountsByNameAndCurrency(name, currency, isAccountActive)
|
|
701
801
|
const accountMatched = accounts[accounts.map(account => account.participantCurrencyId).findIndex(i => i === id)]
|
|
802
|
+
log.debug('recording funds in/out for participant account', { participant, accountMatched })
|
|
702
803
|
if (!accountMatched) {
|
|
703
804
|
throw ErrorHandler.Factory.createInternalServerFSPIOPError(ParticipantAccountCurrencyMismatchText)
|
|
704
805
|
} else if (!accountMatched.accountIsActive) {
|
|
@@ -714,6 +815,7 @@ const recordFundsInOut = async (payload, params, enums) => {
|
|
|
714
815
|
}
|
|
715
816
|
return await Kafka.produceGeneralMessage(Config.KAFKA_CONFIG, KafkaProducer, Enum.Events.Event.Type.ADMIN, Enum.Events.Event.Action.TRANSFER, messageProtocol, Enum.Events.EventStatus.SUCCESS)
|
|
716
817
|
} catch (err) {
|
|
818
|
+
log.error('error recording funds in/out', err)
|
|
717
819
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
718
820
|
}
|
|
719
821
|
}
|
|
@@ -722,17 +824,21 @@ const validateHubAccounts = async (currency) => {
|
|
|
722
824
|
const ledgerAccountTypes = await Enums.getEnums('ledgerAccountType')
|
|
723
825
|
const hubReconciliationAccountExists = await ParticipantCurrencyModel.hubAccountExists(currency, ledgerAccountTypes.HUB_RECONCILIATION)
|
|
724
826
|
if (!hubReconciliationAccountExists) {
|
|
827
|
+
logger.error('Hub reconciliation account for the specified currency does not exist')
|
|
725
828
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Hub reconciliation account for the specified currency does not exist')
|
|
726
829
|
}
|
|
727
830
|
const hubMlnsAccountExists = await ParticipantCurrencyModel.hubAccountExists(currency, ledgerAccountTypes.HUB_MULTILATERAL_SETTLEMENT)
|
|
728
831
|
if (!hubMlnsAccountExists) {
|
|
832
|
+
logger.error('Hub multilateral net settlement account for the specified currency does not exist')
|
|
729
833
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Hub multilateral net settlement account for the specified currency does not exist')
|
|
730
834
|
}
|
|
731
835
|
return true
|
|
732
836
|
}
|
|
733
837
|
|
|
734
838
|
const createAssociatedParticipantAccounts = async (currency, ledgerAccountTypeId, trx) => {
|
|
839
|
+
const log = logger.child({ currency, ledgerAccountTypeId })
|
|
735
840
|
try {
|
|
841
|
+
log.info('creating associated participant accounts')
|
|
736
842
|
const nonHubParticipantWithCurrencies = await ParticipantFacade.getAllNonHubParticipantsWithCurrencies(trx)
|
|
737
843
|
|
|
738
844
|
const participantCurrencies = nonHubParticipantWithCurrencies.map(item => ({
|
|
@@ -760,6 +866,7 @@ const createAssociatedParticipantAccounts = async (currency, ledgerAccountTypeId
|
|
|
760
866
|
}
|
|
761
867
|
await ParticipantPositionModel.createParticipantPositionRecords(participantPositionRecords, trx)
|
|
762
868
|
} catch (err) {
|
|
869
|
+
log.error('error creating associated participant accounts', err)
|
|
763
870
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
764
871
|
}
|
|
765
872
|
}
|