@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
@@ -52,29 +52,20 @@ const createRecordFundsInOut = async (payload, transactionTimestamp, enums) => {
52
52
  /** @namespace Db.getKnex **/
53
53
  const knex = Db.getKnex()
54
54
 
55
- Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::newEntry`)
55
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::newEntry`)
56
56
  // Save the valid transfer into the database
57
57
  if (payload.action === Enum.Events.Event.Action.RECORD_FUNDS_IN) {
58
- Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::newEntry::RECORD_FUNDS_IN`)
59
- return knex.transaction(async trx => {
60
- try {
61
- await TransferService.reconciliationTransferPrepare(payload, transactionTimestamp, enums, trx)
62
- await TransferService.reconciliationTransferReserve(payload, transactionTimestamp, enums, trx)
63
- await TransferService.reconciliationTransferCommit(payload, transactionTimestamp, enums, trx)
64
- await trx.commit
65
- } catch (err) {
66
- await trx.rollback
67
- throw ErrorHandler.Factory.reformatFSPIOPError(err)
68
- }
69
- })
58
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::newEntry::RECORD_FUNDS_IN`)
59
+ return await TransferService.recordFundsIn(payload, transactionTimestamp, enums)
70
60
  } else {
71
- Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::newEntry::RECORD_FUNDS_OUT_PREPARE_RESERVE`)
61
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::newEntry::RECORD_FUNDS_OUT_PREPARE_RESERVE`)
72
62
  return knex.transaction(async trx => {
73
63
  try {
74
64
  await TransferService.reconciliationTransferPrepare(payload, transactionTimestamp, enums, trx)
75
65
  await TransferService.reconciliationTransferReserve(payload, transactionTimestamp, enums, trx)
76
66
  await trx.commit
77
67
  } catch (err) {
68
+ Logger.isErrorEnabled && Logger.error(err)
78
69
  await trx.rollback
79
70
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
80
71
  }
@@ -86,18 +77,18 @@ const changeStatusOfRecordFundsOut = async (payload, transferId, transactionTime
86
77
  const existingTransfer = await TransferService.getTransferById(transferId)
87
78
  const transferState = await TransferService.getTransferState(transferId)
88
79
  if (!existingTransfer) {
89
- Logger.info(`AdminTransferHandler::${payload.action}::validationFailed::notFound`)
80
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationFailed::notFound`)
90
81
  } else if (transferState.transferStateId !== Enum.Transfers.TransferState.RESERVED) {
91
- Logger.info(`AdminTransferHandler::${payload.action}::validationFailed::nonReservedState`)
82
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationFailed::nonReservedState`)
92
83
  } else if (new Date(existingTransfer.expirationDate) <= new Date()) {
93
- Logger.info(`AdminTransferHandler::${payload.action}::validationFailed::transferExpired`)
84
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationFailed::transferExpired`)
94
85
  } else {
95
- Logger.info(`AdminTransferHandler::${payload.action}::validationPassed`)
86
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationPassed`)
96
87
  if (payload.action === Enum.Events.Event.Action.RECORD_FUNDS_OUT_COMMIT) {
97
- Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::RECORD_FUNDS_OUT_COMMIT`)
88
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::RECORD_FUNDS_OUT_COMMIT`)
98
89
  await TransferService.reconciliationTransferCommit(payload, transactionTimestamp, enums)
99
90
  } else if (payload.action === Enum.Events.Event.Action.RECORD_FUNDS_OUT_ABORT) {
100
- Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::RECORD_FUNDS_OUT_ABORT`)
91
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::validationPassed::RECORD_FUNDS_OUT_ABORT`)
101
92
  payload.amount = {
102
93
  amount: existingTransfer.amount,
103
94
  currency: existingTransfer.currencyId
@@ -109,16 +100,16 @@ const changeStatusOfRecordFundsOut = async (payload, transferId, transactionTime
109
100
  }
110
101
 
111
102
  const transferExists = async (payload, transferId) => {
112
- Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching`)
103
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching`)
113
104
  const currentTransferState = await TransferService.getTransferStateChange(transferId)
114
105
  if (!currentTransferState || !currentTransferState.enumeration) {
115
- Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching::transfer state not found`)
106
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching::transfer state not found`)
116
107
  } else {
117
108
  const transferStateEnum = currentTransferState.enumeration
118
109
  if (transferStateEnum === Enum.Transfers.TransferState.COMMITTED || transferStateEnum === Enum.Transfers.TransferInternalState.ABORTED_REJECTED) {
119
- Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching::request already finalized`)
110
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching::request already finalized`)
120
111
  } else if (transferStateEnum === Enum.Transfers.TransferInternalState.RECEIVED_PREPARE || transferStateEnum === Enum.Transfers.TransferState.RESERVED) {
121
- Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching::previous request still in progress do nothing`)
112
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsMatching::previous request still in progress do nothing`)
122
113
  }
123
114
  }
124
115
  return true
@@ -126,7 +117,7 @@ const transferExists = async (payload, transferId) => {
126
117
 
127
118
  const transfer = async (error, messages) => {
128
119
  if (error) {
129
- Logger.error(error)
120
+ Logger.isErrorEnabled && Logger.error(error)
130
121
  throw ErrorHandler.Factory.reformatFSPIOPError(error)
131
122
  }
132
123
  let message = {}
@@ -141,7 +132,7 @@ const transfer = async (error, messages) => {
141
132
  const transferId = message.value.id
142
133
 
143
134
  if (!payload) {
144
- Logger.info('AdminTransferHandler::validationFailed')
135
+ Logger.isInfoEnabled && Logger.info('AdminTransferHandler::validationFailed')
145
136
  // TODO: Cannot be saved because no payload has been provided. What action should be taken?
146
137
  return false
147
138
  }
@@ -149,21 +140,21 @@ const transfer = async (error, messages) => {
149
140
  payload.participantCurrencyId = metadata.request.params.id
150
141
  const enums = metadata.request.enums
151
142
  const transactionTimestamp = Time.getUTCString(new Date())
152
- Logger.info(`AdminTransferHandler::${metadata.event.action}::${transferId}`)
143
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${metadata.event.action}::${transferId}`)
153
144
  const kafkaTopic = message.topic
154
145
 
155
146
  if (!allowedActions.includes(payload.action)) {
156
- Logger.info(`AdminTransferHandler::${payload.action}::invalidPayloadAction`)
147
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::invalidPayloadAction`)
157
148
  }
158
149
  if (httpPostRelatedActions.includes(payload.action)) {
159
150
  const { hasDuplicateId, hasDuplicateHash } = await Comparators.duplicateCheckComparator(transferId, payload, TransferService.getTransferDuplicateCheck, TransferService.saveTransferDuplicateCheck)
160
151
  if (!hasDuplicateId) {
161
- Logger.info(`AdminTransferHandler::${payload.action}::transfer does not exist`)
152
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::transfer does not exist`)
162
153
  await createRecordFundsInOut(payload, transactionTimestamp, enums)
163
154
  } else if (hasDuplicateHash) {
164
155
  await transferExists(payload, transferId)
165
156
  } else {
166
- Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsNotMatching::request exists with different parameters`)
157
+ Logger.isInfoEnabled && Logger.info(`AdminTransferHandler::${payload.action}::dupcheck::existsNotMatching::request exists with different parameters`)
167
158
  }
168
159
  } else {
169
160
  await changeStatusOfRecordFundsOut(payload, transferId, transactionTimestamp, enums)
@@ -171,7 +162,7 @@ const transfer = async (error, messages) => {
171
162
  await Kafka.commitMessageSync(Consumer, kafkaTopic, message)
172
163
  return true
173
164
  } catch (err) {
174
- Logger.error(err)
165
+ Logger.isErrorEnabled && Logger.error(err)
175
166
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
176
167
  }
177
168
  }
@@ -195,7 +186,7 @@ const registerTransferHandler = async () => {
195
186
  await Consumer.createHandler(transferHandler.topicName, transferHandler.config, transferHandler.command)
196
187
  return true
197
188
  } catch (err) {
198
- Logger.error(err)
189
+ Logger.isErrorEnabled && Logger.error(err)
199
190
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
200
191
  }
201
192
  }
@@ -213,6 +204,7 @@ const registerAllHandlers = async () => {
213
204
  await registerTransferHandler()
214
205
  return true
215
206
  } catch (err) {
207
+ Logger.isErrorEnabled && Logger.error(err)
216
208
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
217
209
  }
218
210
  }
@@ -29,7 +29,6 @@
29
29
  ******/
30
30
  'use strict'
31
31
 
32
- const AwaitifyStream = require('awaitify-stream')
33
32
  const Logger = require('@mojaloop/central-services-logger')
34
33
  const BulkTransferService = require('../../../domain/bulkTransfer')
35
34
  const Util = require('@mojaloop/central-services-shared').Util
@@ -40,7 +39,7 @@ const Validator = require('../shared/validator')
40
39
  const Enum = require('@mojaloop/central-services-shared').Enum
41
40
  const Metrics = require('@mojaloop/central-services-metrics')
42
41
  const Config = require('../../../lib/config')
43
- const BulkTransferModels = require('@mojaloop/central-object-store').Models.BulkTransfer
42
+ const BulkTransferModels = require('@mojaloop/object-store-lib').Models.BulkTransfer
44
43
  const encodePayload = require('@mojaloop/central-services-shared').Util.StreamingProtocol.encodePayload
45
44
  const Comparators = require('@mojaloop/central-services-shared').Util.Comparators
46
45
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
@@ -75,6 +74,7 @@ const bulkFulfil = async (error, messages) => {
75
74
  ['success', 'fspId']
76
75
  ).startTimer()
77
76
  if (error) {
77
+ Logger.isErrorEnabled && Logger.error(error)
78
78
  throw error
79
79
  }
80
80
  let message = {}
@@ -90,20 +90,24 @@ const bulkFulfil = async (error, messages) => {
90
90
  const action = message.value.metadata.event.action
91
91
  const bulkTransferId = payload.bulkTransferId
92
92
  const kafkaTopic = message.topic
93
- Logger.info(Util.breadcrumb(location, { method: 'bulkFulfil' }))
94
- const actionLetter = action === Enum.Events.Event.Action.BULK_COMMIT ? Enum.Events.ActionLetter.bulkCommit : Enum.Events.ActionLetter.unknown
95
- let params = { message, kafkaTopic, decodedPayload: payload, consumer: Consumer, producer: Producer }
93
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { method: 'bulkFulfil' }))
94
+ const actionLetter = action === Enum.Events.Event.Action.BULK_COMMIT
95
+ ? Enum.Events.ActionLetter.bulkCommit
96
+ : (action === Enum.Events.Event.Action.BULK_ABORT
97
+ ? Enum.Events.ActionLetter.bulkAbort
98
+ : Enum.Events.ActionLetter.unknown)
99
+ const params = { message, kafkaTopic, decodedPayload: payload, consumer: Consumer, producer: Producer }
96
100
 
97
- Logger.info(Util.breadcrumb(location, { path: 'dupCheck' }))
101
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { path: 'dupCheck' }))
98
102
 
99
103
  const { hasDuplicateId, hasDuplicateHash } = await Comparators.duplicateCheckComparator(bulkTransferId, payload.hash, BulkTransferService.getBulkTransferFulfilmentDuplicateCheck, BulkTransferService.saveBulkTransferFulfilmentDuplicateCheck)
100
104
  if (hasDuplicateId && hasDuplicateHash) { // TODO: handle resend :: GET /bulkTransfer
101
- Logger.info(Util.breadcrumb(location, `resend--${actionLetter}1`))
102
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
105
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `resend--${actionLetter}1`))
106
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
103
107
  return true
104
108
  }
105
109
  if (hasDuplicateId && !hasDuplicateHash) {
106
- Logger.error(Util.breadcrumb(location, `callbackErrorModified--${actionLetter}2`))
110
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, `callbackErrorModified--${actionLetter}2`))
107
111
  const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.MODIFIED_REQUEST)
108
112
  const eventDetail = { functionality: Enum.Events.Event.Type.NOTIFICATION, action }
109
113
  await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, fspiopError: fspiopError.toApiErrorObject(Config.ERROR_HANDLING), eventDetail, fromSwitch })
@@ -114,82 +118,111 @@ const bulkFulfil = async (error, messages) => {
114
118
  const { isValid, reasons } = await Validator.validateBulkTransferFulfilment(payload, headers)
115
119
  if (isValid) {
116
120
  let state
117
- Logger.info(Util.breadcrumb(location, { path: 'isValid' }))
121
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { path: 'isValid' }))
118
122
  try {
119
- Logger.info(Util.breadcrumb(location, 'saveBulkTransfer'))
120
- state = await BulkTransferService.bulkFulfil(payload)
123
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, 'saveBulkTransfer'))
124
+ if (payload.errorInformation) {
125
+ state = await BulkTransferService.bulkFulfilError(payload, payload.errorInformation.errorDescription)
126
+ } else {
127
+ state = await BulkTransferService.bulkFulfil(payload)
128
+ }
121
129
  } catch (err) { // TODO: handle insert errors
122
- Logger.info(Util.breadcrumb(location, `callbackErrorInternal1--${actionLetter}5`))
123
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
130
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorInternal1--${actionLetter}5`))
131
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
132
+ Logger.isErrorEnabled && Logger.error(err)
124
133
  return true
125
134
  }
126
135
  try {
127
- Logger.info(Util.breadcrumb(location, 'individualTransferFulfils'))
136
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, 'individualTransferFulfils'))
128
137
  // stream initialization
129
- const IndividualTransferFulfilModel = BulkTransferModels.getIndividualTransferFulfilModel()
130
- const indvidualTransfersFulfilStream = IndividualTransferFulfilModel.find({ messageId }).cursor()
131
- // enable async/await operations for the stream
132
- const streamReader = AwaitifyStream.createReader(indvidualTransfersFulfilStream)
133
- let doc
134
- while ((doc = await streamReader.readAsync()) !== null) {
135
- const individualTransferFulfil = doc.payload
136
- const transferId = individualTransferFulfil.transferId
137
- delete individualTransferFulfil.transferId
138
- const bulkTransferAssociationRecord = {
139
- transferId,
140
- bulkTransferId: payload.bulkTransferId,
141
- bulkProcessingStateId: Enum.Transfers.BulkProcessingState.PROCESSING
142
- }
143
- await BulkTransferService.bulkTransferAssociationUpdate(transferId, bulkTransferId, bulkTransferAssociationRecord)
144
- if (state === Enum.Transfers.BulkTransferState.INVALID ||
145
- individualTransferFulfil.errorInformation ||
146
- !individualTransferFulfil.fulfilment) {
147
- individualTransferFulfil.transferState = Enum.Transfers.TransferState.ABORTED
148
- } else {
149
- individualTransferFulfil.transferState = Enum.Transfers.TransferState.COMMITTED
138
+ if (payload.errorInformation) {
139
+ const bulkTransfers = await BulkTransferService.getBulkTransferById(payload.bulkTransferId)
140
+ for (const individualTransferFulfil of bulkTransfers.payeeBulkTransfer.individualTransferResults) {
141
+ individualTransferFulfil.errorInformation = payload.errorInformation
142
+ await sendIndividualTransfer(message, messageId, kafkaTopic, headers, payload, state, params, individualTransferFulfil, histTimerEnd)
150
143
  }
151
- const dataUri = encodePayload(JSON.stringify(individualTransferFulfil), headers[Enum.Http.Headers.GENERAL.CONTENT_TYPE.value])
152
- const metadata = Util.StreamingProtocol.createMetadataWithCorrelatedEventState(message.value.metadata.event.id, Enum.Events.Event.Type.FULFIL, Enum.Events.Event.Action.COMMIT, Enum.Events.EventStatus.SUCCESS.status, Enum.Events.EventStatus.SUCCESS.code, Enum.Events.EventStatus.SUCCESS.description) // TODO: switch action to 'bulk-fulfil' flow
153
- const msg = {
154
- value: Util.StreamingProtocol.createMessage(messageId, headers[Enum.Http.Headers.FSPIOP.DESTINATION], headers[Enum.Http.Headers.FSPIOP.SOURCE], metadata, headers, dataUri, { id: transferId })
144
+ } else {
145
+ const IndividualTransferFulfilModel = BulkTransferModels.getIndividualTransferFulfilModel()
146
+
147
+ // enable async/await operations for the stream
148
+ for await (const doc of IndividualTransferFulfilModel.find({ messageId }).cursor()) {
149
+ await sendIndividualTransfer(message, messageId, kafkaTopic, headers, payload, state, params, doc.payload, histTimerEnd)
155
150
  }
156
- params = { message: msg, kafkaTopic, consumer: Consumer, producer: Producer }
157
- const eventDetail = { functionality: Enum.Events.Event.Type.FULFIL, action: Enum.Events.Event.Action.BULK_COMMIT }
158
- await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, histTimerEnd, eventDetail })
159
- histTimerEnd({ success: true, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
160
151
  }
161
152
  } catch (err) { // TODO: handle individual transfers streaming error
162
- Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}6`))
163
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
153
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}6`))
154
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
155
+ Logger.isErrorEnabled && Logger.error(err)
164
156
  return true
165
157
  }
166
158
  } else { // TODO: handle validation failure
167
- Logger.error(Util.breadcrumb(location, { path: 'validationFailed' }))
159
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, { path: 'validationFailed' }))
160
+ Logger.isErrorEnabled && Logger.error(`validationFailure Reasons - ${JSON.stringify(reasons)}`)
168
161
  try {
169
- Logger.info(Util.breadcrumb(location, 'saveInvalidRequest'))
162
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, 'saveInvalidRequest'))
170
163
  /**
171
- * TODO: Following the example for regular transfers, the folloing should ABORT the
164
+ * TODO: Following the example for regular transfers, the following should ABORT the
172
165
  * entire bulk. CAUTION: As of 20191111 this code would also execute when failure
173
166
  * reason is "FSPIOP-Source header should match Payee". In this case we should not
174
167
  * abort the bulk as we would have accepted non-legitimate source.
175
168
  */
176
169
  await BulkTransferService.bulkFulfil(payload, reasons.toString(), false)
177
170
  } catch (err) { // TODO: handle insert error
178
- Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}7`))
179
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
171
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorInternal2--${actionLetter}7`))
172
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
173
+ Logger.isErrorEnabled && Logger.error(err)
180
174
  return true
181
175
  }
182
- Logger.info(Util.breadcrumb(location, `callbackErrorGeneric--${actionLetter}8`))
183
- Logger.error(Util.breadcrumb(location, 'notImplemented'))
176
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorGeneric--${actionLetter}8`))
177
+ Logger.isErrorEnabled && Logger.error(Util.breadcrumb(location, 'notImplemented'))
184
178
  return true // TODO: store invalid bulk transfer to database and produce callback notification to payer
185
179
  }
186
180
  } catch (err) {
187
- Logger.error(`${Util.breadcrumb(location)}::${err.message}--BP0`)
181
+ Logger.isErrorEnabled && Logger.error(`${Util.breadcrumb(location)}::${err.message}--BP0`)
182
+ Logger.isErrorEnabled && Logger.error(err)
188
183
  histTimerEnd({ success: false, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
189
184
  throw err
190
185
  }
191
186
  }
192
187
 
188
+ /**
189
+ * @function sendIndividualTransfer
190
+ *
191
+ * @async
192
+ * @description sends individual transfers to the fulfil handler
193
+ */
194
+ const sendIndividualTransfer = async (message, messageId, kafkaTopic, headers, payload, state, params, individualTransferFulfil, histTimerEnd) => {
195
+ const transferId = individualTransferFulfil.transferId
196
+ delete individualTransferFulfil.transferId
197
+ const bulkTransferAssociationRecord = {
198
+ transferId,
199
+ bulkTransferId: payload.bulkTransferId,
200
+ bulkProcessingStateId: Enum.Transfers.BulkProcessingState.PROCESSING,
201
+ errorCode: payload.errorInformation ? payload.errorInformation.errorCode : undefined,
202
+ errorDescription: payload.errorInformation ? payload.errorInformation.errorDescription : undefined
203
+ }
204
+ await BulkTransferService.bulkTransferAssociationUpdate(transferId, payload.bulkTransferId, bulkTransferAssociationRecord)
205
+
206
+ let eventDetail
207
+ if (state === Enum.Transfers.BulkTransferState.INVALID ||
208
+ individualTransferFulfil.errorInformation ||
209
+ !individualTransferFulfil.fulfilment) {
210
+ individualTransferFulfil.transferState = Enum.Transfers.TransferState.ABORTED
211
+ eventDetail = { functionality: Enum.Events.Event.Type.FULFIL, action: Enum.Events.Event.Action.BULK_ABORT }
212
+ } else {
213
+ individualTransferFulfil.transferState = Enum.Transfers.TransferState.COMMITTED
214
+ eventDetail = { functionality: Enum.Events.Event.Type.FULFIL, action: Enum.Events.Event.Action.BULK_COMMIT }
215
+ }
216
+ const dataUri = encodePayload(JSON.stringify(individualTransferFulfil), headers[Enum.Http.Headers.GENERAL.CONTENT_TYPE.value])
217
+ const metadata = Util.StreamingProtocol.createMetadataWithCorrelatedEventState(message.value.metadata.event.id, Enum.Events.Event.Type.FULFIL, Enum.Events.Event.Action.COMMIT, Enum.Events.EventStatus.SUCCESS.status, Enum.Events.EventStatus.SUCCESS.code, Enum.Events.EventStatus.SUCCESS.description) // TODO: switch action to 'bulk-fulfil' flow
218
+ const msg = {
219
+ value: Util.StreamingProtocol.createMessage(messageId, headers[Enum.Http.Headers.FSPIOP.DESTINATION], headers[Enum.Http.Headers.FSPIOP.SOURCE], metadata, headers, dataUri, { id: transferId })
220
+ }
221
+ params = { message: msg, kafkaTopic, consumer: Consumer, producer: Producer }
222
+ await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, histTimerEnd, eventDetail })
223
+ histTimerEnd({ success: true, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
224
+ }
225
+
193
226
  /**
194
227
  * @function registerBulkFulfilHandler
195
228
  *
@@ -209,7 +242,7 @@ const registerBulkFulfilHandler = async () => {
209
242
  await Consumer.createHandler(bulkFulfilHandler.topicName, bulkFulfilHandler.config, bulkFulfilHandler.command)
210
243
  return true
211
244
  } catch (err) {
212
- Logger.error(err)
245
+ Logger.isErrorEnabled && Logger.error(err)
213
246
  throw err
214
247
  }
215
248
  }
@@ -227,7 +260,7 @@ const registerAllHandlers = async () => {
227
260
  await registerBulkFulfilHandler()
228
261
  return true
229
262
  } catch (err) {
230
- Logger.error(err)
263
+ Logger.isErrorEnabled && Logger.error(err)
231
264
  throw err
232
265
  }
233
266
  }
@@ -0,0 +1,203 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2017 Bill & Melinda Gates Foundation
5
+ The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Gates Foundation organization for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Gates Foundation
23
+ - Name Surname <name.surname@gatesfoundation.com>
24
+
25
+ * ModusBox
26
+ - Steven Oderayi <steven.oderayi@modusbox.com>
27
+ --------------
28
+ ******/
29
+ 'use strict'
30
+
31
+ const Logger = require('@mojaloop/central-services-logger')
32
+ const EventSdk = require('@mojaloop/event-sdk')
33
+ const Util = require('@mojaloop/central-services-shared').Util
34
+ const Kafka = require('@mojaloop/central-services-shared').Util.Kafka
35
+ const Producer = require('@mojaloop/central-services-stream').Util.Producer
36
+ const Consumer = require('@mojaloop/central-services-stream').Util.Consumer
37
+ const Enum = require('@mojaloop/central-services-shared').Enum
38
+ const Metrics = require('@mojaloop/central-services-metrics')
39
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
40
+ const BulkTransferService = require('../../../domain/bulkTransfer')
41
+ const BulkTransferModel = require('../../../models/bulkTransfer/bulkTransfer')
42
+ const Validator = require('../shared/validator')
43
+ const Config = require('../../../lib/config')
44
+ const { ERROR_HANDLING } = require('../../../lib/config')
45
+
46
+ const location = { module: 'BulkGetHandler', method: '', path: '' }
47
+ const consumerCommit = true
48
+ const fromSwitch = true
49
+
50
+ /**
51
+ * @function BulkGetHandler
52
+ *
53
+ * @async
54
+ * @description Gets a bulk transfer by id. Gets Kafka config from default.json
55
+ *
56
+ * Calls createHandler to register the handler against the Stream Processing API.
57
+ *
58
+ * @param {error} error - error thrown if something fails within Kafka
59
+ * @param {array} messages - a list of messages to consume for the relevant topic
60
+ *
61
+ * @returns {object} - Returns a boolean: true if successful, or throws an error if failed
62
+ */
63
+ const getBulkTransfer = async (error, messages) => {
64
+ const histTimerEnd = Metrics.getHistogram(
65
+ 'bulk_transfer_get',
66
+ 'Consume a get bulk transfer message from the kafka topic and process it accordingly',
67
+ ['success', 'fspId']
68
+ ).startTimer()
69
+ if (error) {
70
+ throw ErrorHandler.Factory.reformatFSPIOPError(error)
71
+ }
72
+ const message = Array.isArray(messages) ? messages[0] : messages
73
+ const contextFromMessage = EventSdk.Tracer.extractContextFromMessage(message.value)
74
+ const span = EventSdk.Tracer.createChildSpanFromContext('cl_bulk_transfer_get', contextFromMessage)
75
+ try {
76
+ await span.audit(message, EventSdk.AuditEventAction.start)
77
+ const metadata = message.value.metadata
78
+ const action = metadata.event.action
79
+ const bulkTransferId = message.value.content.uriParams.id
80
+ const kafkaTopic = message.topic
81
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, { method: `getBulkTransfer:${action}` }))
82
+
83
+ const actionLetter = Enum.Events.ActionLetter.get
84
+ const params = { message, kafkaTopic, span, consumer: Consumer, producer: Producer }
85
+ const eventDetail = { functionality: Enum.Events.Event.Type.NOTIFICATION, action: Enum.Events.Event.Action.BULK_GET }
86
+
87
+ Util.breadcrumb(location, { path: 'validationFailed' })
88
+
89
+ if (!(await Validator.validateParticipantByName(message.value.from)).isValid) {
90
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `breakParticipantDoesntExist--${actionLetter}1`))
91
+ await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, histTimerEnd })
92
+ histTimerEnd({ success: true, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
93
+ return true
94
+ }
95
+ // TODO: Validate this. Is this sufficient for checking existence of bulk transfer?
96
+ const bulkTransferLight = await BulkTransferModel.getById(bulkTransferId)
97
+ if (!bulkTransferLight) {
98
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorBulkTransferNotFound--${actionLetter}3`))
99
+ const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.BULK_TRANSFER_ID_NOT_FOUND, 'Provided Bulk Transfer ID was not found on the server.')
100
+ await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, fspiopError: fspiopError.toApiErrorObject(Config.ERROR_HANDLING), eventDetail, fromSwitch })
101
+ throw fspiopError
102
+ }
103
+ // The SD says this should be 404 response which I think will not be constent with single transfers
104
+ // which responds with CLIENT_ERROR instead
105
+ const participants = await BulkTransferService.getParticipantsById(bulkTransferId)
106
+ if (![participants.payeeFsp, participants.payerFsp].includes(message.value.from)) {
107
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackErrorNotBulkTransferParticipant--${actionLetter}2`))
108
+ const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.CLIENT_ERROR)
109
+ await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, fspiopError: fspiopError.toApiErrorObject(Config.ERROR_HANDLING), eventDetail, fromSwitch })
110
+ throw fspiopError
111
+ }
112
+ const isPayeeRequest = participants.payeeFsp === message.value.from
113
+ Util.breadcrumb(location, { path: 'validationPassed' })
114
+ Logger.isInfoEnabled && Logger.info(Util.breadcrumb(location, `callbackMessage--${actionLetter}4`))
115
+ const bulkTransferResult = await BulkTransferService.getBulkTransferById(bulkTransferId)
116
+ const bulkTransfer = isPayeeRequest ? bulkTransferResult.payeeBulkTransfer : bulkTransferResult.payerBulkTransfer
117
+ let payload = {
118
+ bulkTransferState: bulkTransfer.bulkTransferState
119
+ }
120
+ let fspiopError
121
+ if (bulkTransfer.bulkTransferState === Enum.Transfers.BulkTransferState.REJECTED) {
122
+ payload = {
123
+ errorInformation: bulkTransfer.individualTransferResults[0].errorInformation
124
+ }
125
+ fspiopError = ErrorHandler.Factory.createFSPIOPErrorFromErrorInformation(payload.errorInformation)
126
+ } else if (bulkTransfer.bulkTransferState !== Enum.Transfers.BulkTransferState.PROCESSING) {
127
+ payload = {
128
+ ...payload,
129
+ completedTimestamp: bulkTransfer.completedTimestamp,
130
+ individualTransferResults: bulkTransfer.individualTransferResults,
131
+ extensionList: bulkTransfer.extensionList
132
+ }
133
+ }
134
+ message.value.content.payload = payload
135
+ if (fspiopError) {
136
+ await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, fspiopError: fspiopError.toApiErrorObject(ERROR_HANDLING), eventDetail, fromSwitch })
137
+ } else {
138
+ await Kafka.proceed(Config.KAFKA_CONFIG, params, { consumerCommit, eventDetail, fromSwitch })
139
+ }
140
+ histTimerEnd({ success: true, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
141
+ return true
142
+ } catch (err) {
143
+ histTimerEnd({ success: false, fspId: Config.INSTRUMENTATION_METRICS_LABELS.fspId })
144
+ const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err)
145
+ Logger.isErrorEnabled && Logger.error(`${Util.breadcrumb(location)}::${err.message}--G0`)
146
+ const state = new EventSdk.EventStateMetadata(EventSdk.EventStatusType.failed, fspiopError.apiErrorCode.code, fspiopError.apiErrorCode.message)
147
+ await span.error(fspiopError, state)
148
+ await span.finish(fspiopError.message, state)
149
+ return true
150
+ } finally {
151
+ if (!span.isFinished) {
152
+ await span.finish()
153
+ }
154
+ }
155
+ }
156
+
157
+ /**
158
+ * @function registerBulkFulfilHandler
159
+ *
160
+ * @async
161
+ * @description Registers the handler for bulk-transfer topic. Gets Kafka config from default.json
162
+ *
163
+ * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
164
+ */
165
+ const registerGetBulkTransferHandler = async () => {
166
+ try {
167
+ const bulkGetHandler = {
168
+ command: getBulkTransfer,
169
+ topicName: Kafka.transformGeneralTopicName(Config.KAFKA_CONFIG.TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE, Enum.Events.Event.Type.BULK, Enum.Events.Event.Action.GET),
170
+ config: Kafka.getKafkaConfig(Config.KAFKA_CONFIG, Enum.Kafka.Config.CONSUMER, Enum.Events.Event.Type.BULK.toUpperCase(), Enum.Events.Event.Action.GET.toUpperCase())
171
+ }
172
+ bulkGetHandler.config.rdkafkaConf['client.id'] = bulkGetHandler.topicName
173
+ await Consumer.createHandler(bulkGetHandler.topicName, bulkGetHandler.config, bulkGetHandler.command)
174
+ return true
175
+ } catch (err) {
176
+ Logger.isErrorEnabled && Logger.error(err)
177
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
178
+ }
179
+ }
180
+
181
+ /**
182
+ * @function RegisterAllHandlers
183
+ *
184
+ * @async
185
+ * @description Registers all module handlers
186
+ *
187
+ * @returns {boolean} - Returns a boolean: true if successful, or throws and error if failed
188
+ */
189
+ const registerAllHandlers = async () => {
190
+ try {
191
+ await registerGetBulkTransferHandler()
192
+ return true
193
+ } catch (err) {
194
+ Logger.isErrorEnabled && Logger.error(err)
195
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
196
+ }
197
+ }
198
+
199
+ module.exports = {
200
+ getBulkTransfer,
201
+ registerGetBulkTransferHandler,
202
+ registerAllHandlers
203
+ }
@@ -34,6 +34,7 @@
34
34
  const BulkPrepareHandlers = require('./prepare/handler')
35
35
  const BulkFulfilHandlers = require('./fulfil/handler')
36
36
  const BulkProcessingHandlers = require('./processing/handler')
37
+ const GetBulkTransferHandlers = require('./get/handler')
37
38
  const Logger = require('@mojaloop/central-services-logger')
38
39
 
39
40
  /**
@@ -49,9 +50,10 @@ const registerAllHandlers = async () => {
49
50
  await BulkPrepareHandlers.registerAllHandlers()
50
51
  await BulkFulfilHandlers.registerAllHandlers()
51
52
  await BulkProcessingHandlers.registerAllHandlers()
53
+ await GetBulkTransferHandlers.registerAllHandlers()
52
54
  return true
53
55
  } catch (err) {
54
- Logger.error(err)
56
+ Logger.isErrorEnabled && Logger.error(err)
55
57
  throw err
56
58
  }
57
59
  }
@@ -60,5 +62,6 @@ module.exports = {
60
62
  registerBulkPrepareHandler: BulkPrepareHandlers.registerBulkPrepareHandler,
61
63
  registerBulkFulfilHandler: BulkFulfilHandlers.registerBulkFulfilHandler,
62
64
  registerBulkProcessingHandler: BulkProcessingHandlers.registerBulkProcessingHandler,
65
+ registerGetBulkTransferHandler: GetBulkTransferHandlers.registerGetBulkTransferHandler,
63
66
  registerAllHandlers
64
67
  }