@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.
Files changed (147) hide show
  1. package/.ncurc.yaml +3 -1
  2. package/.nvmrc +1 -1
  3. package/.nycrc.yml +16 -1
  4. package/Dockerfile +9 -10
  5. package/README.md +39 -9
  6. package/audit-ci.jsonc +15 -2
  7. package/config/default.json +17 -1
  8. package/docker/central-ledger/default.json +9 -0
  9. package/docker/config-modifier/configs/central-ledger.js +25 -0
  10. package/docker/env.sh +15 -0
  11. package/docker/kafka/scripts/provision.sh +4 -1
  12. package/docker/ml-api-adapter/default.json +4 -1
  13. package/docker-compose.yml +90 -2
  14. package/documentation/db/erd-transfer-timeout.png +0 -0
  15. package/documentation/db/erd-transfer-timeout.txt +81 -0
  16. package/documentation/fx-implementation/README.md +48 -0
  17. package/documentation/fx-implementation/assets/fx-position-movements.drawio.svg +4 -0
  18. package/documentation/fx-implementation/assets/test-scenario.drawio.svg +4 -0
  19. package/documentation/sequence-diagrams/Handler - FX timeout.plantuml +123 -0
  20. package/documentation/sequence-diagrams/Handler - FX timeout.png +0 -0
  21. package/documentation/sequence-diagrams/Handler - timeout.plantuml +81 -0
  22. package/documentation/sequence-diagrams/Handler - timeout.png +0 -0
  23. package/documentation/state-diagrams/transfer-ML-spec-states-diagram.png +0 -0
  24. package/documentation/state-diagrams/transfer-internal-states-diagram.png +0 -0
  25. package/documentation/state-diagrams/transfer-internal-states.plantuml +75 -0
  26. package/documentation/state-diagrams/transfer-states.plantuml +13 -0
  27. package/migrations/310204_transferParticipant-participantId.js +52 -0
  28. package/migrations/310403_participantPositionChange-participantCurrencyId.js +47 -0
  29. package/migrations/310404_participantPositionChange-change.js +46 -0
  30. package/migrations/600010_fxTransferType.js +43 -0
  31. package/migrations/600011_fxTransferType-indexes.js +38 -0
  32. package/migrations/600012_fxParticipantCurrencyType.js +43 -0
  33. package/migrations/600013_fxParticipantCurrencyType-indexes.js +38 -0
  34. package/migrations/600100_fxTransferDuplicateCheck.js +42 -0
  35. package/migrations/600110_fxTransferErrorDuplicateCheck.js.js +17 -0
  36. package/migrations/600200_fxTransfer.js +51 -0
  37. package/migrations/600201_fxTransfer-indexes.js +40 -0
  38. package/migrations/600400_fxTransferStateChange.js +46 -0
  39. package/migrations/600401_fxTransferStateChange-indexes.js +40 -0
  40. package/migrations/600501_fxWatchList.js +46 -0
  41. package/migrations/600502_fxWatchList-indexes.js +40 -0
  42. package/migrations/600600_fxTransferFulfilmentDuplicateCheck.js +43 -0
  43. package/migrations/600601_fxTransferFulfilmentDuplicateCheck-indexes.js +38 -0
  44. package/migrations/600700_fxTransferFulfilment.js +47 -0
  45. package/migrations/600701_fxTransferFulfilment-indexes.js +43 -0
  46. package/migrations/600800_fxTransferExtension.js +47 -0
  47. package/migrations/601400_fxTransferTimeout.js +43 -0
  48. package/migrations/601401_fxTransferTimeout-indexes.js +37 -0
  49. package/migrations/601500_fxTransferError.js +44 -0
  50. package/migrations/601501_fxTransferError-indexes.js +37 -0
  51. package/migrations/610200_fxTransferParticipant.js +52 -0
  52. package/migrations/610201_fxTransferParticipant-indexes.js +44 -0
  53. package/migrations/610202_fxTransferParticipant-participantId.js +52 -0
  54. package/migrations/610403_participantPositionChange-fxTransfer.js +46 -0
  55. package/migrations/910101_feature904DataMigration.js +46 -52
  56. package/migrations/910102_feature949DataMigration.js +219 -225
  57. package/migrations/950104_settlementModel-settlementAccountTypeId.js +15 -20
  58. package/migrations/950108_participantProxy.js +18 -0
  59. package/migrations/950109_fxQuote.js +19 -0
  60. package/migrations/950110_fxQuoteResponse.js +25 -0
  61. package/migrations/950111_fxQuoteError.js +23 -0
  62. package/migrations/950113_fxQuoteDuplicateCheck.js +18 -0
  63. package/migrations/950114_fxQuoteResponseDuplicateCheck.js +21 -0
  64. package/migrations/950115_fxQuoteConversionTerms.js +36 -0
  65. package/migrations/950116_fxQuoteConversionTermsExtension.js +21 -0
  66. package/migrations/950117_fxQuoteResponseConversionTerms.js +39 -0
  67. package/migrations/950118_fxQuoteResponseConversionTermsExtension.js +21 -0
  68. package/migrations/950119_fxCharge.js +27 -0
  69. package/migrations/960100_create_externalParticipant.js +47 -0
  70. package/migrations/960110_alter_transferParticipant__addFiled_externalParticipantId.js +50 -0
  71. package/migrations/960111_alter_fxTransferParticipant__addFiled_externalParticipantId.js +50 -0
  72. package/package.json +27 -20
  73. package/seeds/endpointType.js +18 -0
  74. package/seeds/fxParticipantCurrencyType.js +45 -0
  75. package/seeds/fxTransferType.js +45 -0
  76. package/seeds/participant.js +2 -1
  77. package/seeds/transferParticipantRoleType.js +9 -0
  78. package/seeds/transferState.js +10 -0
  79. package/src/api/interface/swagger.json +23 -30
  80. package/src/api/participants/handler.js +6 -2
  81. package/src/api/participants/routes.js +8 -7
  82. package/src/api/root/handler.js +15 -5
  83. package/src/domain/fx/cyril.js +466 -0
  84. package/src/domain/fx/index.js +107 -0
  85. package/src/domain/participant/index.js +108 -1
  86. package/src/domain/position/abort.js +215 -0
  87. package/src/domain/position/binProcessor.js +361 -99
  88. package/src/domain/position/fulfil.js +252 -111
  89. package/src/domain/position/fx-fulfil.js +138 -0
  90. package/src/domain/position/fx-prepare.js +280 -0
  91. package/src/domain/position/fx-timeout-reserved.js +159 -0
  92. package/src/domain/position/index.js +1 -0
  93. package/src/domain/position/prepare.js +69 -49
  94. package/src/domain/position/timeout-reserved.js +162 -0
  95. package/src/domain/timeout/index.js +26 -2
  96. package/src/domain/transfer/index.js +22 -5
  97. package/src/domain/transfer/transform.js +19 -6
  98. package/src/handlers/admin/handler.js +0 -2
  99. package/src/handlers/bulk/fulfil/handler.js +5 -5
  100. package/src/handlers/bulk/get/handler.js +5 -5
  101. package/src/handlers/bulk/prepare/handler.js +9 -9
  102. package/src/handlers/bulk/processing/handler.js +8 -7
  103. package/src/handlers/bulk/shared/validator.js +1 -1
  104. package/src/handlers/positions/handler.js +23 -10
  105. package/src/handlers/positions/handlerBatch.js +54 -26
  106. package/src/handlers/register.js +2 -1
  107. package/src/handlers/timeouts/handler.js +212 -68
  108. package/src/handlers/transfers/FxFulfilService.js +387 -0
  109. package/src/handlers/transfers/createRemittanceEntity.js +106 -0
  110. package/src/handlers/transfers/dto.js +53 -0
  111. package/src/handlers/transfers/handler.js +609 -571
  112. package/src/handlers/transfers/prepare.js +572 -0
  113. package/src/handlers/transfers/validator.js +75 -14
  114. package/src/lib/cache.js +1 -1
  115. package/src/lib/config.js +6 -3
  116. package/src/lib/healthCheck/subServiceHealth.js +12 -2
  117. package/src/lib/proxyCache.js +131 -0
  118. package/src/models/bulkTransfer/facade.js +58 -82
  119. package/src/models/fxTransfer/duplicateCheck.js +153 -0
  120. package/src/models/fxTransfer/fxTransfer.js +578 -0
  121. package/src/models/fxTransfer/fxTransferError.js +53 -0
  122. package/src/models/fxTransfer/fxTransferExtension.js +41 -0
  123. package/src/models/fxTransfer/fxTransferTimeout.js +68 -0
  124. package/src/models/fxTransfer/index.js +15 -0
  125. package/src/models/fxTransfer/stateChange.js +47 -0
  126. package/src/models/fxTransfer/watchList.js +49 -0
  127. package/src/models/ledgerAccountType/ledgerAccountType.js +8 -32
  128. package/src/models/misc/segment.js +0 -1
  129. package/src/models/participant/externalParticipant.js +96 -0
  130. package/src/models/participant/externalParticipantCached.js +148 -0
  131. package/src/models/participant/facade.js +192 -123
  132. package/src/models/participant/participant.js +2 -1
  133. package/src/models/participant/participantCurrency.js +1 -1
  134. package/src/models/participant/participantPosition.js +2 -8
  135. package/src/models/position/batch.js +90 -1
  136. package/src/models/position/facade.js +5 -5
  137. package/src/models/position/participantPositionChanges.js +68 -0
  138. package/src/models/settlement/settlementModel.js +5 -23
  139. package/src/models/transfer/facade.js +806 -447
  140. package/src/shared/constants.js +52 -0
  141. package/src/shared/fspiopErrorFactory.js +131 -0
  142. package/src/shared/logger/index.js +8 -0
  143. package/src/shared/loggingPlugin.js +43 -0
  144. package/src/shared/plugins.js +6 -0
  145. package/src/shared/setup.js +10 -0
  146. package/test-integration.Dockerfile +1 -1
  147. 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
- return ParticipantModel.create({ name: payload.name })
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
  }