@mojaloop/central-ledger 9.2.2 → 15.1.3-snapshot.2

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 (256) hide show
  1. package/.circleci/config.yml +625 -204
  2. package/.env +3 -2
  3. package/.ncurc.yaml +9 -0
  4. package/.nvmrc +1 -1
  5. package/.versionrc +15 -0
  6. package/CHANGELOG.md +353 -0
  7. package/CODEOWNERS +31 -0
  8. package/Dockerfile +20 -14
  9. package/LICENSE.md +4 -4
  10. package/Onboarding.md +0 -7
  11. package/README.md +99 -22
  12. package/audit-resolve.json +136 -1
  13. package/config/default.json +82 -27
  14. package/docker/central-ledger/default.json +68 -21
  15. package/docker/ml-api-adapter/default.json +10 -1
  16. package/docker/wait-for/wait-for-objstore.sh +1 -6
  17. package/docker/wait-for/wait-for.env +1 -1
  18. package/docker-compose.integration.yml +8 -5
  19. package/docker-compose.yml +73 -16
  20. package/migrations/310203_transferParticipant-indexes.js +38 -0
  21. package/migrations/310503_participantLimit-indexes-composite.js +38 -0
  22. package/migrations/{400401_settlementWindowStateChange-indexes.js → 400401_settlmentWindowStateChange-indexes.js} +0 -0
  23. package/migrations/401301_settlementModel-indexes.js +2 -0
  24. package/migrations/500401_quote-hotfix-2719.js +58 -0
  25. package/migrations/500501_feature-fixSubIdRef.js +53 -0
  26. package/migrations/500601_party-2480.js +63 -0
  27. package/migrations/501001_quoteExtension-quote-service-174.js +46 -0
  28. package/migrations/501002_quoteExtension-2522.js +61 -0
  29. package/migrations/800101_feature-fixSubIdRef.js +90 -0
  30. package/migrations/910102_hotfix954.js +4 -1
  31. package/migrations/940100_quotePartyIdInfoExtension.js +52 -0
  32. package/migrations/940101_quotePartyIdInfoExtension-2522.js +64 -0
  33. package/migrations/950100_settlementContentAggregation-decimal184.js +40 -0
  34. package/migrations/950101_transferParticipantStateChange.js +46 -0
  35. package/migrations/950102_settlementModel-adjustPosition.js +42 -0
  36. package/migrations/950103_dropTransferParticipantStateChange.js +47 -0
  37. package/migrations/950104_settlementModel-settlementAccountTypeId.js +79 -0
  38. package/migrations/950106_unique_settlement_model_ledger_account_currency.js +38 -0
  39. package/migrations/950107_settlementWindowContent_foreign_settlementModel.js +60 -0
  40. package/package.json +99 -81
  41. package/scripts/_wait4_all.js +146 -0
  42. package/seeds/amountType.js +4 -6
  43. package/seeds/balanceOfPayments.js +4 -6
  44. package/seeds/bulkProcessingState.js +4 -6
  45. package/seeds/bulkTransferState.js +4 -6
  46. package/seeds/currency.js +4 -6
  47. package/seeds/endpointType.js +128 -7
  48. package/seeds/ledgerAccountType.js +11 -10
  49. package/seeds/ledgerEntryType.js +5 -7
  50. package/seeds/participant.js +4 -6
  51. package/seeds/participantLimitType.js +4 -6
  52. package/seeds/partyIdentifierType.js +4 -6
  53. package/seeds/partyType.js +4 -6
  54. package/seeds/settlementDelay.js +4 -6
  55. package/seeds/settlementGranularity.js +4 -6
  56. package/seeds/settlementInterchange.js +4 -6
  57. package/seeds/settlementState.js +4 -6
  58. package/seeds/settlementWindow1State.js +4 -6
  59. package/seeds/transactionInitiator.js +4 -6
  60. package/seeds/transactionInitiatorType.js +4 -6
  61. package/seeds/transactionScenario.js +4 -6
  62. package/seeds/transferParticipantRoleType.js +4 -6
  63. package/seeds/transferState.js +9 -6
  64. package/src/api/interface/swagger.json +728 -948
  65. package/src/api/ledgerAccountTypes/handler.js +55 -0
  66. package/src/api/ledgerAccountTypes/routes.js +63 -0
  67. package/src/api/metrics/handler.js +2 -2
  68. package/src/api/metrics/routes.js +1 -1
  69. package/src/api/participants/handler.js +43 -35
  70. package/src/api/participants/routes.js +13 -13
  71. package/src/api/root/routes.js +2 -2
  72. package/src/api/settlementModels/handler.js +9 -26
  73. package/src/api/settlementModels/routes.js +4 -4
  74. package/src/api/transactions/handler.js +46 -0
  75. package/src/api/transactions/routes.js +45 -0
  76. package/src/domain/bulkTransfer/index.js +6 -5
  77. package/src/domain/ledgerAccountTypes/index.js +58 -0
  78. package/src/domain/participant/index.js +55 -4
  79. package/src/domain/position/index.js +18 -2
  80. package/src/domain/settlement/index.js +39 -6
  81. package/src/domain/transactions/index.js +61 -0
  82. package/src/domain/transfer/index.js +22 -2
  83. package/src/domain/transfer/transform.js +3 -3
  84. package/src/handlers/admin/handler.js +24 -32
  85. package/src/handlers/bulk/fulfil/handler.js +89 -56
  86. package/src/handlers/bulk/get/handler.js +203 -0
  87. package/src/handlers/bulk/index.js +4 -1
  88. package/src/handlers/bulk/prepare/handler.js +30 -29
  89. package/src/handlers/bulk/processing/handler.js +61 -32
  90. package/src/handlers/bulk/shared/validator.js +13 -1
  91. package/src/handlers/index.js +18 -9
  92. package/src/handlers/positions/handler.js +67 -46
  93. package/src/handlers/register.js +7 -7
  94. package/src/handlers/timeouts/handler.js +9 -4
  95. package/src/handlers/transfers/handler.js +408 -182
  96. package/src/handlers/transfers/validator.js +41 -11
  97. package/src/lib/cache.js +8 -34
  98. package/src/lib/config.js +5 -7
  99. package/src/lib/enum.js +22 -22
  100. package/src/lib/enumCached.js +76 -0
  101. package/src/lib/healthCheck/subServiceHealth.js +2 -2
  102. package/src/lib/requestLogger.js +9 -9
  103. package/src/lib/urlParser.js +1 -1
  104. package/src/models/bulkTransfer/bulkTransfer.js +6 -6
  105. package/src/models/bulkTransfer/bulkTransferAssociation.js +3 -3
  106. package/src/models/bulkTransfer/bulkTransferDuplicateCheck.js +4 -4
  107. package/src/models/bulkTransfer/bulkTransferExtension.js +2 -2
  108. package/src/models/bulkTransfer/bulkTransferFulfilmentDuplicateCheck.js +4 -4
  109. package/src/models/bulkTransfer/bulkTransferStateChange.js +7 -7
  110. package/src/models/bulkTransfer/facade.js +54 -3
  111. package/src/models/bulkTransfer/individualTransfer.js +2 -2
  112. package/src/models/ilpPackets/ilpPacket.js +36 -0
  113. package/src/models/ledgerAccountType/ledgerAccountType.js +139 -3
  114. package/src/models/misc/migrationLock.js +1 -1
  115. package/src/models/misc/segment.js +1 -1
  116. package/src/models/participant/facade.js +226 -76
  117. package/src/models/participant/participant.js +6 -5
  118. package/src/models/participant/participantCached.js +8 -0
  119. package/src/models/participant/participantCurrency.js +7 -7
  120. package/src/models/participant/participantCurrencyCached.js +11 -1
  121. package/src/models/participant/participantLimit.js +13 -13
  122. package/src/models/participant/participantLimitCached.js +124 -0
  123. package/src/models/participant/participantPosition.js +34 -5
  124. package/src/models/participant/participantPositionChange.js +10 -2
  125. package/src/models/position/facade.js +112 -18
  126. package/src/models/position/participantPosition.js +6 -6
  127. package/src/models/settlement/settlementModel.js +92 -17
  128. package/src/models/settlement/settlementModelCached.js +139 -0
  129. package/src/models/transfer/facade.js +97 -32
  130. package/src/models/transfer/ilpPacket.js +4 -4
  131. package/src/models/transfer/transfer.js +7 -7
  132. package/src/models/transfer/transferDuplicateCheck.js +21 -5
  133. package/src/models/transfer/transferError.js +5 -5
  134. package/src/models/transfer/transferErrorDuplicateCheck.js +4 -4
  135. package/src/models/transfer/transferExtension.js +4 -4
  136. package/src/models/transfer/transferFulfilment.js +5 -5
  137. package/src/models/transfer/transferFulfilmentDuplicateCheck.js +4 -4
  138. package/src/models/transfer/transferParticipant.js +3 -3
  139. package/src/models/transfer/transferStateChange.js +11 -11
  140. package/src/models/transfer/transferTimeout.js +5 -5
  141. package/src/schema/bulkTransfer.js +4 -4
  142. package/src/shared/plugins.js +10 -9
  143. package/src/shared/setup.js +69 -46
  144. package/test/integration/domain/participant/index.test.js +2 -0
  145. package/test/integration/handlers/handlers.test.js +605 -166
  146. package/test/integration/handlers/root.test.js +1 -1
  147. package/test/integration/helpers/hubAccounts.js +62 -0
  148. package/test/integration/helpers/ilpPacket.js +1 -1
  149. package/test/integration/helpers/participantFundsInOut.js +80 -0
  150. package/test/integration/helpers/participantLimit.js +6 -1
  151. package/test/integration/helpers/settlementModels.js +88 -0
  152. package/test/integration/helpers/testConsumer.js +163 -0
  153. package/test/integration/helpers/testProducer.js +0 -1
  154. package/test/integration/helpers/transferDuplicateCheck.js +1 -1
  155. package/test/integration/helpers/transferStateChange.js +1 -1
  156. package/test/integration/helpers/transferTestHelper.js +3 -5
  157. package/test/integration/models/transfer/transferStateChange.test.js +6 -0
  158. package/test/unit/api/ledgerAccountTypes/handler.test.js +126 -0
  159. package/test/unit/api/ledgerAccountTypes/routes.test.js +52 -0
  160. package/test/unit/api/participants/handler.test.js +75 -33
  161. package/test/unit/api/root/handler.test.js +1 -1
  162. package/test/unit/api/root/routes.test.js +2 -2
  163. package/test/unit/api/settlementModels/handler.test.js +21 -57
  164. package/test/unit/api/transactions/handler.test.js +108 -0
  165. package/test/unit/api/transactions/routes.test.js +38 -0
  166. package/test/unit/domain/ledgerAccountTypes/index.test.js +197 -0
  167. package/test/unit/domain/participant/index.test.js +115 -2
  168. package/test/unit/domain/settlement/index.test.js +199 -29
  169. package/test/unit/domain/transactions/index.test.js +128 -0
  170. package/test/unit/domain/transfer/index.test.js +1 -0
  171. package/test/unit/domain/transfer/transform.test.js +2 -0
  172. package/test/unit/handlers/admin/handler.test.js +5 -5
  173. package/test/unit/handlers/bulk/get/handler.test.js +401 -0
  174. package/test/unit/handlers/index.test.js +6 -0
  175. package/test/unit/handlers/positions/handler.test.js +26 -0
  176. package/test/unit/handlers/register.test.js +2 -0
  177. package/test/unit/handlers/transfers/handler.test.js +491 -36
  178. package/test/unit/handlers/transfers/validator.test.js +31 -31
  179. package/test/unit/lib/cache.test.js +0 -64
  180. package/test/unit/lib/cachingOfEnums.test.js +121 -0
  181. package/test/unit/lib/config.test.js +34 -0
  182. package/test/unit/lib/enum.test.js +6 -1
  183. package/test/unit/lib/enumCached.test.js +82 -0
  184. package/test/unit/lib/healthCheck/subServiceHealth.test.js +2 -0
  185. package/test/unit/lib/requestLogger.test.js +14 -12
  186. package/test/unit/models/ilpPackets/ilpPacket.test.js +89 -0
  187. package/test/unit/models/ledgerAccountType/ledgerAccountType.test.js +255 -6
  188. package/test/unit/models/misc/migrationLock.test.js +4 -0
  189. package/test/unit/models/misc/segment.test.js +5 -0
  190. package/test/unit/models/participant/facade.test.js +493 -54
  191. package/test/unit/models/participant/participant.test.js +4 -0
  192. package/test/unit/models/participant/participantCurrency.test.js +22 -9
  193. package/test/unit/models/participant/participantCurrencyCached.test.js +1 -1
  194. package/test/unit/models/participant/participantLimit.test.js +97 -0
  195. package/test/unit/models/participant/participantLimitCached.test.js +232 -0
  196. package/test/unit/models/participant/participantPosition.test.js +217 -0
  197. package/test/unit/models/participant/participantPositionChange.test.js +3 -0
  198. package/test/unit/models/position/facade.test.js +318 -29
  199. package/test/unit/models/position/participantPosition.test.js +22 -7
  200. package/test/unit/models/settlement/settlementModel.test.js +18 -37
  201. package/test/unit/models/settlement/settlementModelCached.test.js +171 -0
  202. package/test/unit/models/transfer/facade.test.js +115 -0
  203. package/test/unit/models/transfer/ilpPacket.test.js +28 -11
  204. package/test/unit/models/transfer/transfer.test.js +13 -4
  205. package/test/unit/models/transfer/transferDuplicateCheck.test.js +4 -0
  206. package/test/unit/models/transfer/transferError.test.js +5 -1
  207. package/test/unit/models/transfer/transferErrorDuplicateCheck.test.js +4 -0
  208. package/test/unit/models/transfer/transferExtension.test.js +26 -9
  209. package/test/unit/models/transfer/transferFulfilment.test.js +14 -5
  210. package/test/unit/models/transfer/transferFulfilmentDuplicateCheck.test.js +4 -0
  211. package/test/unit/models/transfer/transferParticipant.test.js +14 -5
  212. package/test/unit/models/transfer/transferStateChange.test.js +3 -0
  213. package/test/unit/models/transfer/transferTimeout.test.js +6 -0
  214. package/test/unit/seeds/amountType.test.js +6 -22
  215. package/test/unit/seeds/balanceOfPayments.test.js +6 -22
  216. package/test/unit/seeds/bulkProcessingState.test.js +84 -0
  217. package/test/unit/{lib/sidecar/nullClient.test.js → seeds/bulkTransferState.test.js} +36 -39
  218. package/test/unit/seeds/currency.test.js +6 -22
  219. package/test/unit/seeds/endpointType.test.js +6 -22
  220. package/test/unit/seeds/ledgerAccountType.test.js +5 -22
  221. package/test/unit/seeds/ledgerEntryType.test.js +6 -22
  222. package/test/unit/seeds/participant.test.js +5 -22
  223. package/test/unit/seeds/participantLimitType.test.js +6 -22
  224. package/test/unit/seeds/partyIdentifierType.test.js +6 -22
  225. package/test/unit/seeds/partyType.test.js +6 -22
  226. package/test/unit/seeds/settlementState.test.js +5 -22
  227. package/test/unit/seeds/settlementWindow1State.test.js +5 -22
  228. package/test/unit/seeds/transactionInitiator.test.js +6 -22
  229. package/test/unit/seeds/transactionInitiatorType.test.js +6 -22
  230. package/test/unit/seeds/transactionScenario.test.js +6 -22
  231. package/test/unit/seeds/transferParticipantRoleType.test.js +6 -22
  232. package/test/unit/seeds/transferState.test.js +6 -22
  233. package/test/unit/shared/plugins.test.js +31 -1
  234. package/test/unit/shared/setup.test.js +25 -36
  235. package/test/util/helpers.js +37 -2
  236. package/test/util/randomTransfers.js +1 -1
  237. package/test/util/scripts/env.sh +6 -5
  238. package/test/util/scripts/populateTestData.sh +204 -181
  239. package/test/util/scripts/populateTestDataForLegacySimulator.sh +261 -0
  240. package/test/util/scripts/restartObjStore.sh +1 -1
  241. package/test-integration.Dockerfile +15 -15
  242. package/test.Dockerfile +12 -12
  243. package/.circleci/_set_up_deploy_envs.sh +0 -47
  244. package/.dockerignore +0 -17
  245. package/.ncurc.json +0 -3
  246. package/server.sh +0 -4
  247. package/sonar-project.properties +0 -17
  248. package/src/lib/sidecar/index.js +0 -47
  249. package/src/lib/sidecar/nullClient.js +0 -18
  250. package/test/.env +0 -8
  251. package/test/integration-config.json +0 -367
  252. package/test/integration-runner.env +0 -31
  253. package/test/integration-runner.sh +0 -264
  254. package/test/spec-runner.sh +0 -132
  255. package/test/unit/lib/sidecar/index.test.js +0 -148
  256. package/test/unit/models/position/participantLimit.test.js +0 -135
@@ -30,7 +30,6 @@
30
30
  ******/
31
31
  'use strict'
32
32
 
33
- const AwaitifyStream = require('awaitify-stream')
34
33
  const Logger = require('@mojaloop/central-services-logger')
35
34
  const BulkTransferService = require('../../../domain/bulkTransfer')
36
35
  const Util = require('@mojaloop/central-services-shared').Util
@@ -41,7 +40,7 @@ const Validator = require('../shared/validator')
41
40
  const Enum = require('@mojaloop/central-services-shared').Enum
42
41
  const Metrics = require('@mojaloop/central-services-metrics')
43
42
  const Config = require('../../../lib/config')
44
- const BulkTransferModels = require('@mojaloop/central-object-store').Models.BulkTransfer
43
+ const BulkTransferModels = require('@mojaloop/object-store-lib').Models.BulkTransfer
45
44
  const encodePayload = require('@mojaloop/central-services-shared').Util.StreamingProtocol.encodePayload
46
45
  const Comparators = require('@mojaloop/central-services-shared').Util.Comparators
47
46
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
@@ -97,21 +96,21 @@ const bulkPrepare = async (error, messages) => {
97
96
  const action = message.value.metadata.event.action
98
97
  const bulkTransferId = payload.bulkTransferId
99
98
  const kafkaTopic = message.topic
100
- Logger.info(Util.breadcrumb(location, { method: 'bulkPrepare' }))
99
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { method: 'bulkPrepare' }))
101
100
 
102
101
  const actionLetter = action === Enum.Events.Event.Action.BULK_PREPARE ? Enum.Events.ActionLetter.bulkPrepare : Enum.Events.ActionLetter.unknown
103
102
  let params = { message, kafkaTopic, decodedPayload: payload, consumer: Consumer, producer: Producer }
104
103
 
105
- Logger.info(Util.breadcrumb(location, { path: 'dupCheck' }))
104
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { path: 'dupCheck' }))
106
105
 
107
106
  const { hasDuplicateId, hasDuplicateHash } = await Comparators.duplicateCheckComparator(bulkTransferId, payload, BulkTransferService.getBulkTransferDuplicateCheck, BulkTransferService.saveBulkTransferDuplicateCheck)
108
107
  if (hasDuplicateId && hasDuplicateHash) { // TODO: handle resend :: GET /bulkTransfer
109
- Logger.info(Util.breadcrumb(location, `resend--${actionLetter}1`))
110
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
108
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `resend--${actionLetter}1`))
109
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
111
110
  return true
112
111
  }
113
112
  if (hasDuplicateId && !hasDuplicateHash) { // TODO: handle modified request
114
- Logger.error(Util.breadcrumb(location, `callbackErrorModified--${actionLetter}2`))
113
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, `callbackErrorModified--${actionLetter}2`))
115
114
  const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST)
116
115
  const eventDetail = { functionality: Enum.Events.Event.Type.NOTIFICATION, action }
117
116
  params.message.value.content.uriParams = { id: bulkTransferId }
@@ -121,26 +120,24 @@ const bulkPrepare = async (error, messages) => {
121
120
 
122
121
  const { isValid, reasons, payerParticipantId, payeeParticipantId } = await Validator.validateBulkTransfer(payload, headers)
123
122
  if (isValid) {
124
- Logger.info(Util.breadcrumb(location, { path: 'isValid' }))
123
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { path: 'isValid' }))
125
124
  try {
126
- Logger.info(Util.breadcrumb(location, 'saveBulkTransfer'))
125
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, 'saveBulkTransfer'))
127
126
  const participants = { payerParticipantId, payeeParticipantId }
128
127
  await BulkTransferService.bulkPrepare(payload, participants)
129
128
  } catch (err) { // TODO: handle insert error
130
- Logger.info(Util.breadcrumb(location, `callbackErrorInternal1--${actionLetter}5`))
131
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
129
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorInternal1--${actionLetter}5`))
130
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
131
+ Logger.isErrorEnabled && Logger.error(err)
132
132
  return true
133
133
  }
134
134
  try {
135
- Logger.info(Util.breadcrumb(location, 'individualTransfers'))
136
- // stream initialization
135
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, 'individualTransfers'))
136
+
137
137
  const IndividualTransferModel = BulkTransferModels.getIndividualTransferModel()
138
- const indvidualTransfersStream = IndividualTransferModel.find({ messageId }).cursor()
139
- // enable async/await operations for the stream
140
- const streamReader = AwaitifyStream.createReader(indvidualTransfersStream)
141
- let doc
142
138
 
143
- while ((doc = await streamReader.readAsync()) !== null) {
139
+ // for loop on a stream cursor
140
+ for await (const doc of IndividualTransferModel.find({ messageId }).cursor()) {
144
141
  const individualTransfer = doc.payload
145
142
  individualTransfer.payerFsp = payload.payerFsp
146
143
  individualTransfer.payeeFsp = payload.payeeFsp
@@ -164,26 +161,30 @@ const bulkPrepare = async (error, messages) => {
164
161
  histTimerEnd({ success: true, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
165
162
  }
166
163
  } catch (err) { // TODO: handle individual transfers streaming error
167
- Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}6`))
168
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
164
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}6`))
165
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
166
+ Logger.isErrorEnabled && Logger.error(err)
169
167
  return true
170
168
  }
171
169
  } else { // TODO: handle validation failure
172
- Logger.error(Util.breadcrumb(location, { path: 'validationFailed' }))
170
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, { path: 'validationFailed' }))
171
+ Logger.isErrorEnabled && Logger.error(`validationFailure Reasons - ${JSON.stringify(reasons)}`)
173
172
  try {
174
- Logger.info(Util.breadcrumb(location, 'saveInvalidRequest'))
173
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, 'saveInvalidRequest'))
175
174
  await BulkTransferService.bulkPrepare(payload, { payerParticipantId, payeeParticipantId }, reasons.toString(), false)
176
175
  } catch (err) { // TODO: handle insert error
177
- Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}7`))
178
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
176
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}7`))
177
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
178
+ Logger.isErrorEnabled && Logger.error(err)
179
179
  return true
180
180
  }
181
- Logger.info(Util.breadcrumb(location, `callbackErrorGeneric--${actionLetter}8`))
182
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
181
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorGeneric--${actionLetter}8`))
182
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
183
183
  return true // TODO: store invalid bulk transfer to database and produce callback notification to payer
184
184
  }
185
185
  } catch (err) {
186
- Logger.error(`${Util.breadcrumb(location)}::${err.message}--BP0`)
186
+ Logger.isErrorEnabled && Logger.error(`${Util.breadcrumb(location)}::${err.message}--BP0`)
187
+ Logger.isErrorEnabled && Logger.error(err)
187
188
  histTimerEnd({ success: false, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
188
189
  throw err
189
190
  }
@@ -208,7 +209,7 @@ const registerBulkPrepareHandler = async () => {
208
209
  await Consumer.createHandler(bulkPrepareHandler.topicName, bulkPrepareHandler.config, bulkPrepareHandler.command)
209
210
  return true
210
211
  } catch (err) {
211
- Logger.error(err)
212
+ Logger.isErrorEnabled && Logger.error(err)
212
213
  throw err
213
214
  }
214
215
  }
@@ -226,7 +227,7 @@ const registerAllHandlers = async () => {
226
227
  await registerBulkPrepareHandler()
227
228
  return true
228
229
  } catch (err) {
229
- Logger.error(err)
230
+ Logger.isErrorEnabled && Logger.error(err)
230
231
  throw err
231
232
  }
232
233
  }
@@ -39,7 +39,7 @@ const Enum = require('@mojaloop/central-services-shared').Enum
39
39
  const Metrics = require('@mojaloop/central-services-metrics')
40
40
  const Config = require('../../../lib/config')
41
41
  const decodePayload = require('@mojaloop/central-services-shared').Util.StreamingProtocol.decodePayload
42
- const BulkTransferModels = require('@mojaloop/central-object-store').Models.BulkTransfer
42
+ const BulkTransferModels = require('@mojaloop/object-store-lib').Models.BulkTransfer
43
43
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
44
44
 
45
45
  const location = { module: 'BulkProcessingHandler', method: '', path: '' } // var object used as pointer
@@ -72,7 +72,7 @@ const bulkProcessing = async (error, messages) => {
72
72
  ['success', 'fspId']
73
73
  ).startTimer()
74
74
  if (error) {
75
- // Logger.error(error)
75
+ // Logger.isErrorEnabled && Logger.error(error)
76
76
  throw error
77
77
  }
78
78
  let message = {}
@@ -89,15 +89,23 @@ const bulkProcessing = async (error, messages) => {
89
89
  const state = message.value.metadata.event.state
90
90
  const transferId = payload.transferId || (message.value.content.uriParams && message.value.content.uriParams.id)
91
91
  const kafkaTopic = message.topic
92
- Logger.info(Util.breadcrumb(location, { method: 'bulkProcessing' }))
92
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { method: 'bulkProcessing' }))
93
93
 
94
- const actionLetter = action === Enum.Events.Event.Action.BULK_PREPARE ? Enum.Events.ActionLetter.bulkPrepare
95
- : (action === Enum.Events.Event.Action.BULK_COMMIT ? Enum.Events.ActionLetter.bulkCommit
96
- : (action === Enum.Events.Event.Action.BULK_TIMEOUT_RECEIVED ? Enum.Events.ActionLetter.bulkTimeoutReceived
97
- : (action === Enum.Events.Event.Action.BULK_TIMEOUT_RESERVED ? Enum.Events.ActionLetter.bulkTimeoutReserved
98
- : (action === Enum.Events.Event.Action.PREPARE_DUPLICATE ? Enum.Events.ActionLetter.bulkPrepareDuplicate
99
- : (action === Enum.Events.Event.Action.FULFIL_DUPLICATE ? Enum.Events.ActionLetter.bulkFulfilDuplicate
100
- : Enum.Events.ActionLetter.unknown)))))
94
+ const actionLetter = action === Enum.Events.Event.Action.BULK_PREPARE
95
+ ? Enum.Events.ActionLetter.bulkPrepare
96
+ : (action === Enum.Events.Event.Action.BULK_COMMIT
97
+ ? Enum.Events.ActionLetter.bulkCommit
98
+ : (action === Enum.Events.Event.Action.BULK_TIMEOUT_RECEIVED
99
+ ? Enum.Events.ActionLetter.bulkTimeoutReceived
100
+ : (action === Enum.Events.Event.Action.BULK_TIMEOUT_RESERVED
101
+ ? Enum.Events.ActionLetter.bulkTimeoutReserved
102
+ : (action === Enum.Events.Event.Action.PREPARE_DUPLICATE
103
+ ? Enum.Events.ActionLetter.bulkPrepareDuplicate
104
+ : (action === Enum.Events.Event.Action.FULFIL_DUPLICATE
105
+ ? Enum.Events.ActionLetter.bulkFulfilDuplicate
106
+ : (action === Enum.Events.Event.Action.BULK_ABORT
107
+ ? Enum.Events.ActionLetter.bulkAbort
108
+ : Enum.Events.ActionLetter.unknown))))))
101
109
  const params = { message, kafkaTopic, decodedPayload: payload, consumer: Consumer, producer: Producer }
102
110
  const eventDetail = { functionality: Enum.Events.Event.Type.NOTIFICATION, action }
103
111
 
@@ -175,6 +183,12 @@ const bulkProcessing = async (error, messages) => {
175
183
  processingStateId = Enum.Transfers.BulkProcessingState.EXPIRED
176
184
  errorCode = payload.errorInformation && payload.errorInformation.errorCode
177
185
  errorDescription = payload.errorInformation && payload.errorInformation.errorDescription
186
+ } else if (action === Enum.Events.Event.Action.BULK_ABORT) {
187
+ // TODO: Need to validate `state.status`
188
+ processingStateId = Enum.Transfers.BulkProcessingState.REJECTED
189
+ completedBulkState = Enum.Transfers.BulkTransferState.REJECTED
190
+ errorCode = payload.errorInformation && payload.errorInformation.errorCode
191
+ errorDescription = payload.errorInformation && payload.errorInformation.errorDescription
178
192
  } else {
179
193
  const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `Invalid action for bulk in ${Enum.Transfers.BulkTransferState.PROCESSING} state`)
180
194
  throw fspiopError
@@ -233,23 +247,24 @@ const bulkProcessing = async (error, messages) => {
233
247
  if (bulkTransferState !== bulkTransferInfo.bulkTransferStateId) {
234
248
  await BulkTransferService.createBulkTransferState({
235
249
  bulkTransferId: bulkTransferInfo.bulkTransferId,
236
- bulkTransferStateId: bulkTransferState
250
+ bulkTransferStateId: bulkTransferState,
251
+ reason: errorDescription || null
237
252
  })
238
253
  }
239
254
 
240
255
  let getBulkTransferByIdResult
241
256
  if (produceNotification) {
242
- Logger.info(Util.breadcrumb(location, { path: 'produceNotification' }))
257
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { path: 'produceNotification' }))
243
258
  getBulkTransferByIdResult = await BulkTransferService.getBulkTransferById(bulkTransferInfo.bulkTransferId)
244
259
  } else {
245
- Logger.info(Util.breadcrumb(location, { path: 'awaitAllTransfers' }))
260
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { path: 'awaitAllTransfers' }))
246
261
  criteriaState = null // debugging breakpoint line
247
262
  return true
248
263
  }
249
264
 
250
265
  if (produceNotification) {
251
266
  if (eventType === Enum.Events.Event.Type.BULK_PROCESSING && action === Enum.Events.Event.Action.BULK_PREPARE) {
252
- Logger.info(Util.breadcrumb(location, `bulkPrepare--${actionLetter}2`))
267
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `bulkPrepare--${actionLetter}2`))
253
268
  const payeeBulkResponse = Object.assign({}, { messageId: message.value.id, headers }, getBulkTransferByIdResult.payeeBulkTransfer)
254
269
  const payeeIndividualTransfers = payeeBulkResponse.individualTransferResults.filter(individualTransfer => {
255
270
  return !individualTransfer.errorInformation
@@ -275,12 +290,12 @@ const bulkProcessing = async (error, messages) => {
275
290
  // TODO: handle use case when no individual transfer has been accepted:
276
291
  // Switch to finilize bulk state and notify payer with PUT /bulkTransfers/{id}
277
292
  // const payerBulkResponse = Object.assign({}, { messageId: message.value.id, headers }, getBulkTransferByIdResult.payerBulkTransfer)
278
- Logger.info(Util.breadcrumb(location, `noTransfers--${actionLetter}1`))
279
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
293
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `noTransfers--${actionLetter}1`))
294
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
280
295
  return true
281
296
  }
282
- } else if (eventType === Enum.Events.Event.Type.BULK_PROCESSING && [Enum.Events.Event.Action.BULK_COMMIT, Enum.Events.Event.Action.BULK_TIMEOUT_RECEIVED, Enum.Events.Event.Action.BULK_TIMEOUT_RESERVED].includes(action)) {
283
- Logger.info(Util.breadcrumb(location, `bulkFulfil--${actionLetter}3`))
297
+ } else if (eventType === Enum.Events.Event.Type.BULK_PROCESSING && [Enum.Events.Event.Action.BULK_COMMIT, Enum.Events.Event.Action.BULK_TIMEOUT_RECEIVED, Enum.Events.Event.Action.BULK_TIMEOUT_RESERVED, Enum.Events.Event.Action.BULK_ABORT].includes(action)) {
298
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `bulkFulfil--${actionLetter}3`))
284
299
  const participants = await BulkTransferService.getParticipantsById(bulkTransferInfo.bulkTransferId)
285
300
  const normalizedKeys = Object.keys(headers).reduce((keys, k) => { keys[k.toLowerCase()] = k; return keys }, {})
286
301
  const payeeBulkResponseHeaders = Util.Headers.transformHeaders(headers, { httpMethod: headers[normalizedKeys[Enum.Http.Headers.FSPIOP.HTTP_METHOD]], sourceFsp: Enum.Http.Headers.FSPIOP.SWITCH.value, destinationFsp: participants.payeeFsp })
@@ -292,25 +307,36 @@ const bulkProcessing = async (error, messages) => {
292
307
  await (new BulkTransferResultModel(payeeBulkResponse)).save()
293
308
  const payerParams = Util.clone(params)
294
309
  const payeeParams = Util.clone(params)
310
+ let payerPayload
311
+ let payeePayload
312
+
313
+ if (action === Enum.Events.Event.Action.BULK_ABORT && params.decodedPayload.errorInformation) {
314
+ payerPayload = { bulkTransferId: payerBulkResponse.bulkTransferId, errorInformation: params.decodedPayload.errorInformation }
315
+ payeePayload = { bulkTransferId: payeeBulkResponse.bulkTransferId, errorInformation: params.decodedPayload.errorInformation }
316
+ } else {
317
+ payerPayload = Util.omitNil({
318
+ bulkTransferId: payerBulkResponse.bulkTransferId,
319
+ bulkTransferState: payerBulkResponse.bulkTransferState,
320
+ completedTimestamp: payerBulkResponse.completedTimestamp,
321
+ extensionList: payerBulkResponse.extensionList
322
+ })
323
+ payeePayload = Util.omitNil({
324
+ bulkTransferId: payeeBulkResponse.bulkTransferId,
325
+ bulkTransferState: payeeBulkResponse.bulkTransferState,
326
+ completedTimestamp: payeeBulkResponse.completedTimestamp,
327
+ extensionList: payeeBulkResponse.extensionList
328
+ })
329
+ }
295
330
 
296
- const payerPayload = Util.omitNil({
297
- bulkTransferId: payerBulkResponse.bulkTransferId,
298
- bulkTransferState: payerBulkResponse.bulkTransferState,
299
- completedTimestamp: payerBulkResponse.completedTimestamp,
300
- extensionList: payerBulkResponse.extensionList
301
- })
302
331
  const payerMetadata = Util.StreamingProtocol.createMetadataWithCorrelatedEvent(params.message.value.metadata.event.id, payerParams.message.value.metadata.type, payerParams.message.value.metadata.action, Enum.Events.EventStatus.SUCCESS)
303
332
  payerParams.message.value = Util.StreamingProtocol.createMessage(params.message.value.id, participants.payerFsp, payerBulkResponse.headers[normalizedKeys[Enum.Http.Headers.FSPIOP.SOURCE]], payerMetadata, payerBulkResponse.headers, payerPayload)
304
- const payeePayload = Util.omitNil({
305
- bulkTransferId: payeeBulkResponse.bulkTransferId,
306
- bulkTransferState: payeeBulkResponse.bulkTransferState,
307
- completedTimestamp: payeeBulkResponse.completedTimestamp,
308
- extensionList: payeeBulkResponse.extensionList
309
- })
333
+
310
334
  const payeeMetadata = Util.StreamingProtocol.createMetadataWithCorrelatedEvent(params.message.value.metadata.event.id, payeeParams.message.value.metadata.type, payeeParams.message.value.metadata.action, Enum.Events.EventStatus.SUCCESS)
311
335
  payeeParams.message.value = Util.StreamingProtocol.createMessage(params.message.value.id, participants.payeeFsp, Enum.Http.Headers.FSPIOP.SWITCH.value, payeeMetadata, payeeBulkResponse.headers, payeePayload)
312
336
  if ([Enum.Events.Event.Action.BULK_TIMEOUT_RECEIVED, Enum.Events.Event.Action.BULK_TIMEOUT_RESERVED].includes(action)) {
313
337
  eventDetail.action = Enum.Events.Event.Action.BULK_COMMIT
338
+ } else if ([Enum.Events.Event.Action.BULK_ABORT].includes(action)) {
339
+ eventDetail.action = Enum.Events.Event.Action.BULK_ABORT
314
340
  }
315
341
  await Kafka.proceed(Config.KAFKA_CONFIG, payerParams, { consumerCommit, eventDetail })
316
342
  histTimerEnd({ success: true, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
@@ -326,7 +352,7 @@ const bulkProcessing = async (error, messages) => {
326
352
  } else {
327
353
  // TODO: For the following (Internal Server Error) scenario a notification is produced for each individual transfer.
328
354
  // It also needs to be processed first in order to accumulate transfers and send the callback notification at bulk level.
329
- Logger.info(Util.breadcrumb(location, `invalidEventTypeOrAction--${actionLetter}4`))
355
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `invalidEventTypeOrAction--${actionLetter}4`))
330
356
  const fspiopError = ErrorHandler.Factory.createInternalServerFSPIOPError(`Invalid event action:(${action}) and/or type:(${eventType})`).toApiErrorObject(Config.ERROR_HANDLING)
331
357
  const eventDetail = { functionality: Enum.Events.Event.Type.NOTIFICATION, action: Enum.Events.Event.Action.BULK_PROCESSING }
332
358
  await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, fspiopError, eventDetail, fromSwitch })
@@ -335,7 +361,8 @@ const bulkProcessing = async (error, messages) => {
335
361
  }
336
362
  }
337
363
  } catch (err) {
338
- Logger.error(`${Util.breadcrumb(location)}::${err.message}--BP0`)
364
+ Logger.isErrorEnabled && Logger.error(`${Util.breadcrumb(location)}::${err.message}--BP0`)
365
+ Logger.isErrorEnabled && Logger.error(err)
339
366
  histTimerEnd({ success: false, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
340
367
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
341
368
  }
@@ -360,6 +387,7 @@ const registerBulkProcessingHandler = async () => {
360
387
  await Consumer.createHandler(bulkProcessingHandler.topicName, bulkProcessingHandler.config, bulkProcessingHandler.command)
361
388
  return true
362
389
  } catch (err) {
390
+ Logger.isErrorEnabled && Logger.error(err)
363
391
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
364
392
  }
365
393
  }
@@ -377,6 +405,7 @@ const registerAllHandlers = async () => {
377
405
  await registerBulkProcessingHandler()
378
406
  return true
379
407
  } catch (err) {
408
+ Logger.isErrorEnabled && Logger.error(err)
380
409
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
381
410
  }
382
411
  }
@@ -25,6 +25,7 @@
25
25
  * ModusBox
26
26
  - Georgi Georgiev <georgi.georgiev@modusbox.com>
27
27
  - Rajiv Mothilal <rajiv.mothilal@modusbox.com>
28
+ - Steven Oderayi <steven.oderayi@modusbox.com>
28
29
  --------------
29
30
  ******/
30
31
  'use strict'
@@ -130,7 +131,18 @@ const validateBulkTransferFulfilment = async (payload, headers) => {
130
131
  return { isValid, reasons }
131
132
  }
132
133
 
134
+ const validateParticipantBulkTransferId = async function (participantName, bulkTransferId) {
135
+ const bulkTransferParticipant = await BulkTransferService.getBulkTransferParticipant(participantName, bulkTransferId)
136
+ let validationPassed = false
137
+ if (Array.isArray(bulkTransferParticipant) && bulkTransferParticipant.length > 0) {
138
+ validationPassed = true
139
+ }
140
+ return validationPassed
141
+ }
142
+
133
143
  module.exports = {
134
144
  validateBulkTransfer,
135
- validateBulkTransferFulfilment
145
+ validateBulkTransferFulfilment,
146
+ validateParticipantByName,
147
+ validateParticipantBulkTransferId
136
148
  }
@@ -59,13 +59,14 @@ Program.command('handler') // sub-command name, coffeeType = type, required
59
59
  .option('--bulkprepare', 'Start the Bulk Prepare Handler')
60
60
  .option('--bulkfulfil', 'Start the Bulk Fulfil Handler')
61
61
  .option('--bulkprocessing', 'Start the Bulk Processing Handler')
62
+ .option('--bulkget', 'Start the Bulk Get Handler')
62
63
  // .option('--reject', 'Start the Reject Handler')
63
64
 
64
65
  // function to execute when command is uses
65
66
  .action(async (args) => {
66
67
  const handlerList = []
67
68
  if (args.prepare) {
68
- Logger.debug('CLI: Executing --prepare')
69
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --prepare')
69
70
  const handler = {
70
71
  type: 'prepare',
71
72
  enabled: true
@@ -73,7 +74,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
73
74
  handlerList.push(handler)
74
75
  }
75
76
  if (args.position) {
76
- Logger.debug('CLI: Executing --position')
77
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --position')
77
78
  const handler = {
78
79
  type: 'position',
79
80
  enabled: true
@@ -81,7 +82,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
81
82
  handlerList.push(handler)
82
83
  }
83
84
  if (args.get) {
84
- Logger.debug('CLI: Executing --get')
85
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --get')
85
86
  const handler = {
86
87
  type: 'get',
87
88
  enabled: true
@@ -89,7 +90,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
89
90
  handlerList.push(handler)
90
91
  }
91
92
  if (args.fulfil) {
92
- Logger.debug('CLI: Executing --fulfil')
93
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --fulfil')
93
94
  const handler = {
94
95
  type: 'fulfil',
95
96
  enabled: true
@@ -97,7 +98,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
97
98
  handlerList.push(handler)
98
99
  }
99
100
  if (args.timeout) {
100
- Logger.debug('CLI: Executing --timeout')
101
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --timeout')
101
102
  const handler = {
102
103
  type: 'timeout',
103
104
  enabled: true
@@ -105,7 +106,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
105
106
  handlerList.push(handler)
106
107
  }
107
108
  if (args.admin) {
108
- Logger.debug('CLI: Executing --admin')
109
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --admin')
109
110
  const handler = {
110
111
  type: 'admin',
111
112
  enabled: true
@@ -113,7 +114,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
113
114
  handlerList.push(handler)
114
115
  }
115
116
  if (args.bulkprepare) {
116
- Logger.debug('CLI: Executing --bulkprepare')
117
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --bulkprepare')
117
118
  const handler = {
118
119
  type: 'bulkprepare',
119
120
  enabled: true
@@ -121,7 +122,7 @@ Program.command('handler') // sub-command name, coffeeType = type, required
121
122
  handlerList.push(handler)
122
123
  }
123
124
  if (args.bulkfulfil) {
124
- Logger.debug('CLI: Executing --bulkfulfil')
125
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --bulkfulfil')
125
126
  const handler = {
126
127
  type: 'bulkfulfil',
127
128
  enabled: true
@@ -129,13 +130,21 @@ Program.command('handler') // sub-command name, coffeeType = type, required
129
130
  handlerList.push(handler)
130
131
  }
131
132
  if (args.bulkprocessing) {
132
- Logger.debug('CLI: Executing --bulkprocessing')
133
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --bulkprocessing')
133
134
  const handler = {
134
135
  type: 'bulkprocessing',
135
136
  enabled: true
136
137
  }
137
138
  handlerList.push(handler)
138
139
  }
140
+ if (args.bulkget) {
141
+ Logger.isDebugEnabled && Logger.debug('CLI: Executing --bulkget')
142
+ const handler = {
143
+ type: 'bulkget',
144
+ enabled: true
145
+ }
146
+ handlerList.push(handler)
147
+ }
139
148
 
140
149
  module.exports = Setup.initialize({
141
150
  service: 'handler',