@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
@@ -0,0 +1,46 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ 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.
8
+ Contributors
9
+ --------------
10
+ This is the official list of the Mojaloop project contributors for this file.
11
+ Names of the original copyright holders (individuals or organizations)
12
+ should be listed with a '*' in the first column. People who have
13
+ contributed from an organization can be listed under the organization
14
+ that actually holds the copyright for their contributions (see the
15
+ Gates Foundation organization for an example). Those individuals should have
16
+ their names indented and be marked with a '-'. Email address can be added
17
+ optionally within square brackets <email>.
18
+ * Gates Foundation
19
+ - Name Surname <name.surname@gatesfoundation.com>
20
+
21
+ * ModusBox
22
+ - Lazola Lucas <lazola.lucas@modusbox.com>
23
+ --------------
24
+ ******/
25
+ 'use strict'
26
+
27
+ const Transaction = require('../../domain/transactions')
28
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
+ const Logger = require('@mojaloop/central-services-logger')
30
+
31
+ const getById = async function (request) {
32
+ try {
33
+ const entity = await Transaction.getById(request.params.id)
34
+ if (entity) {
35
+ return await Transaction.getTransactionObject(entity[0].value)
36
+ }
37
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, 'The requested resource could not be found.')
38
+ } catch (err) {
39
+ Logger.isErrorEnabled && Logger.error(err)
40
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
41
+ }
42
+ }
43
+
44
+ module.exports = {
45
+ getById
46
+ }
@@ -0,0 +1,45 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ 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.
8
+ Contributors
9
+ --------------
10
+ This is the official list of the Mojaloop project contributors for this file.
11
+ Names of the original copyright holders (individuals or organizations)
12
+ should be listed with a '*' in the first column. People who have
13
+ contributed from an organization can be listed under the organization
14
+ that actually holds the copyright for their contributions (see the
15
+ Gates Foundation organization for an example). Those individuals should have
16
+ their names indented and be marked with a '-'. Email address can be added
17
+ optionally within square brackets <email>.
18
+ * Gates Foundation
19
+ - Name Surname <name.surname@gatesfoundation.com>
20
+
21
+ * ModusBox
22
+ - Lazola Lucas <lazola.lucas@modusbox.com>
23
+ --------------
24
+ ******/
25
+ 'use strict'
26
+
27
+ const Handler = require('./handler')
28
+ const Joi = require('joi')
29
+ const tags = ['api', 'transaction']
30
+
31
+ module.exports = [
32
+ {
33
+ method: 'GET',
34
+ path: '/transactions/{id}',
35
+ handler: Handler.getById,
36
+ options: {
37
+ tags,
38
+ validate: {
39
+ params: Joi.object({
40
+ id: Joi.string().required().description('Transfer id')
41
+ })
42
+ }
43
+ }
44
+ }
45
+ ]
@@ -24,7 +24,7 @@
24
24
  'use strict'
25
25
 
26
26
  /**
27
- * @module src/domain/transfer/
27
+ * @module src/domain/bulkTransfer/
28
28
  */
29
29
 
30
30
  const Enum = require('@mojaloop/central-services-shared').Enum
@@ -54,7 +54,7 @@ const getBulkTransferById = async (id) => {
54
54
  }
55
55
  if (transfer.errorCode) {
56
56
  result.errorInformation = {
57
- errorCode: transfer.errorCode,
57
+ errorCode: transfer.errorCode.toString(),
58
58
  errorDescription: transfer.errorDescription
59
59
  }
60
60
  } else {
@@ -124,12 +124,12 @@ const getBulkTransferById = async (id) => {
124
124
  payerFsp: bulkTransfer.payerFsp,
125
125
  payeeFsp: bulkTransfer.payeeFsp,
126
126
  expiration: bulkTransfer.expirationDate,
127
- completedDate: bulkTransfer.completedDate,
127
+ completedDate: bulkTransfer.completedTimestamp,
128
128
  payerBulkTransfer,
129
129
  payeeBulkTransfer
130
130
  }
131
131
  } catch (err) {
132
- Logger.error(err)
132
+ Logger.isErrorEnabled && Logger.error(err)
133
133
  throw err
134
134
  }
135
135
  }
@@ -157,7 +157,7 @@ const getBulkTransferExtensionListById = async (id, completedTimestamp) => {
157
157
  }
158
158
  return extensionList
159
159
  } catch (err) {
160
- Logger.error(err)
160
+ Logger.isErrorEnabled && Logger.error(err)
161
161
  throw err
162
162
  }
163
163
  }
@@ -169,6 +169,7 @@ const BulkTransferService = {
169
169
  getParticipantsById: BulkTransferModel.getParticipantsById,
170
170
  bulkPrepare: BulkTransferFacade.saveBulkTransferReceived,
171
171
  bulkFulfil: BulkTransferFacade.saveBulkTransferProcessing,
172
+ bulkFulfilError: BulkTransferFacade.saveBulkTransferErrorProcessing,
172
173
  bulkTransferAssociationCreate: BulkTransferAssociationModel.create,
173
174
  bulkTransferAssociationUpdate: BulkTransferAssociationModel.update,
174
175
  bulkTransferAssociationExists: BulkTransferAssociationModel.exists,
@@ -0,0 +1,58 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ 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.
8
+ Contributors
9
+ --------------
10
+ This is the official list of the Mojaloop project contributors for this file.
11
+ Names of the original copyright holders (individuals or organizations)
12
+ should be listed with a '*' in the first column. People who have
13
+ contributed from an organization can be listed under the organization
14
+ that actually holds the copyright for their contributions (see the
15
+ Gates Foundation organization for an example). Those individuals should have
16
+ their names indented and be marked with a '-'. Email address can be added
17
+ optionally within square brackets <email>.
18
+ * Gates Foundation
19
+ - Name Surname <name.surname@gatesfoundation.com>
20
+
21
+ * ModusBox
22
+ - Claudio Viola <claudio.viola@modusbox.com>
23
+ --------------
24
+ ******/
25
+ 'use strict'
26
+
27
+ const LedgerAccountTypeModel = require('../../models/ledgerAccountType/ledgerAccountType')
28
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
+
30
+ async function create (name, description, isActive = false, isSettleable = false) {
31
+ try {
32
+ await LedgerAccountTypeModel.create(name, description, isActive, isSettleable)
33
+ return true
34
+ } catch (err) {
35
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
36
+ }
37
+ }
38
+
39
+ async function getAll () {
40
+ try {
41
+ return await LedgerAccountTypeModel.getAll()
42
+ } catch (err) {
43
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
44
+ }
45
+ }
46
+ async function getByName (name) {
47
+ try {
48
+ return await LedgerAccountTypeModel.getLedgerAccountByName(name)
49
+ } catch (err) {
50
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
51
+ }
52
+ }
53
+
54
+ module.exports = {
55
+ getByName,
56
+ create,
57
+ getAll
58
+ }
@@ -41,6 +41,7 @@ const Kafka = require('@mojaloop/central-services-shared').Util.Kafka
41
41
  const KafkaProducer = require('@mojaloop/central-services-stream').Util.Producer
42
42
  const Uuid = require('uuid4')
43
43
  const Enum = require('@mojaloop/central-services-shared').Enum
44
+ const Enums = require('../../lib/enumCached')
44
45
 
45
46
  // Alphabetically ordered list of error texts used below
46
47
  const AccountInactiveErrorText = 'Account is currently set inactive'
@@ -54,6 +55,7 @@ const ParticipantInactiveText = 'Participant is currently set inactive'
54
55
  const ParticipantInitialPositionExistsText = 'Participant Limit or Initial Position already set'
55
56
  const ParticipantNotFoundText = 'Participant does not exist'
56
57
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
58
+ const { destroyParticipantEndpointByParticipantId } = require('../../models/participant/participant')
57
59
 
58
60
  const create = async (payload) => {
59
61
  try {
@@ -146,6 +148,7 @@ const destroyByName = async (name) => {
146
148
  await ParticipantLimitModel.destroyByParticipantId(participant.participantId)
147
149
  await ParticipantPositionModel.destroyByParticipantId(participant.participantId)
148
150
  await ParticipantCurrencyModel.destroyByParticipantId(participant.participantId)
151
+ await destroyParticipantEndpointByParticipantId(participant.participantId)
149
152
  return await ParticipantModel.destroyByName(name)
150
153
  } catch (err) {
151
154
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
@@ -285,7 +288,7 @@ const addLimitAndInitialPosition = async (participantName, limitAndInitialPositi
285
288
  if (existingLimit || existingPosition || existingSettlementPosition) {
286
289
  throw ErrorHandler.Factory.createInternalServerFSPIOPError(ParticipantInitialPositionExistsText)
287
290
  }
288
- const limitAndInitialPosition = limitAndInitialPositionObj
291
+ const limitAndInitialPosition = Object.assign({}, limitAndInitialPositionObj, { name: participantName })
289
292
  if (!limitAndInitialPosition.initialPosition) {
290
293
  limitAndInitialPosition.initialPosition = Config.PARTICIPANT_INITIAL_POSITION
291
294
  }
@@ -706,8 +709,8 @@ const recordFundsInOut = async (payload, params, enums) => {
706
709
  transferId && (payload.transferId = transferId)
707
710
  const messageProtocol = createRecordFundsMessageProtocol(setPayerPayeeFundsInOut(name, payload, enums))
708
711
  messageProtocol.metadata.request = {
709
- params: params,
710
- enums: enums
712
+ params,
713
+ enums
711
714
  }
712
715
  return await Kafka.produceGeneralMessage(Config.KAFKA_CONFIG, KafkaProducer, Enum.Events.Event.Type.ADMIN, Enum.Events.Event.Action.TRANSFER, messageProtocol, Enum.Events.EventStatus.SUCCESS)
713
716
  } catch (err) {
@@ -715,6 +718,52 @@ const recordFundsInOut = async (payload, params, enums) => {
715
718
  }
716
719
  }
717
720
 
721
+ const validateHubAccounts = async (currency) => {
722
+ const ledgerAccountTypes = await Enums.getEnums('ledgerAccountType')
723
+ const hubReconciliationAccountExists = await ParticipantCurrencyModel.hubAccountExists(currency, ledgerAccountTypes.HUB_RECONCILIATION)
724
+ if (!hubReconciliationAccountExists) {
725
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Hub reconciliation account for the specified currency does not exist')
726
+ }
727
+ const hubMlnsAccountExists = await ParticipantCurrencyModel.hubAccountExists(currency, ledgerAccountTypes.HUB_MULTILATERAL_SETTLEMENT)
728
+ if (!hubMlnsAccountExists) {
729
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Hub multilateral net settlement account for the specified currency does not exist')
730
+ }
731
+ return true
732
+ }
733
+
734
+ const createAssociatedParticipantAccounts = async (currency, ledgerAccountTypeId, trx) => {
735
+ try {
736
+ const nonHubParticipantWithCurrencies = await ParticipantFacade.getAllNonHubParticipantsWithCurrencies(trx)
737
+
738
+ const participantCurrencies = nonHubParticipantWithCurrencies.map(item => ({
739
+ participantId: item.participantId,
740
+ currencyId: currency,
741
+ ledgerAccountTypeId,
742
+ isActive: true
743
+ }))
744
+
745
+ const participantPositionRecords = []
746
+ for (const participantCurrency of participantCurrencies) {
747
+ // create account only if it doesn't exist
748
+ const existingParticipant = await getById(participantCurrency.participantId)
749
+ const currencyExists = existingParticipant.currencyList.find(curr => {
750
+ return curr.currencyId === currency && curr.ledgerAccountTypeId === ledgerAccountTypeId
751
+ })
752
+ if (!currencyExists) {
753
+ const participantCurrencyId = await createParticipantCurrency(participantCurrency.participantId, participantCurrency.currencyId, participantCurrency.ledgerAccountTypeId, participantCurrency.isActive)
754
+ participantPositionRecords.push({
755
+ participantCurrencyId,
756
+ value: 0.0000,
757
+ reservedValue: 0.0000
758
+ })
759
+ }
760
+ }
761
+ await ParticipantPositionModel.createParticipantPositionRecords(participantPositionRecords, trx)
762
+ } catch (err) {
763
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
764
+ }
765
+ }
766
+
718
767
  module.exports = {
719
768
  create,
720
769
  getAll,
@@ -744,5 +793,7 @@ module.exports = {
744
793
  recordFundsInOut,
745
794
  getAccountByNameAndCurrency: ParticipantFacade.getByNameAndCurrency,
746
795
  hubAccountExists: ParticipantCurrencyModel.hubAccountExists,
747
- getLimitsForAllParticipants
796
+ getLimitsForAllParticipants,
797
+ validateHubAccounts,
798
+ createAssociatedParticipantAccounts
748
799
  }
@@ -31,12 +31,28 @@
31
31
 
32
32
  const PositionFacade = require('../../models/position/facade')
33
33
 
34
+ const Metrics = require('@mojaloop/central-services-metrics')
35
+
34
36
  const changeParticipantPosition = (participantCurrencyId, isReversal, amount, transferStateChange) => {
35
- return PositionFacade.changeParticipantPositionTransaction(participantCurrencyId, isReversal, amount, transferStateChange)
37
+ const histTimerChangeParticipantPositionEnd = Metrics.getHistogram(
38
+ 'domain_position',
39
+ 'changeParticipantPosition - Metrics for transfer domain',
40
+ ['success', 'funcName']
41
+ ).startTimer()
42
+ const result = PositionFacade.changeParticipantPositionTransaction(participantCurrencyId, isReversal, amount, transferStateChange)
43
+ histTimerChangeParticipantPositionEnd({ success: true, funcName: 'changeParticipantPosition' })
44
+ return result
36
45
  }
37
46
 
38
47
  const calculatePreparePositionsBatch = async (transferList) => {
39
- return PositionFacade.prepareChangeParticipantPositionTransaction(transferList)
48
+ const histTimerPositionBatchDomainEnd = Metrics.getHistogram(
49
+ 'domain_position',
50
+ 'calculatePreparePositionsBatch - Metrics for transfer domain',
51
+ ['success', 'funcName']
52
+ ).startTimer()
53
+ const result = PositionFacade.prepareChangeParticipantPositionTransaction(transferList)
54
+ histTimerPositionBatchDomainEnd({ success: true, funcName: 'calculatePreparePositionsBatch' })
55
+ return result
40
56
  }
41
57
 
42
58
  module.exports = {
@@ -27,21 +27,32 @@
27
27
 
28
28
  const SettlementModelModel = require('../../models/settlement/settlementModel')
29
29
  const LedgerAccountTypeModel = require('../../models/ledgerAccountType/ledgerAccountType')
30
-
30
+ const Enum = require('@mojaloop/central-services-shared').Enum.Settlements
31
31
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
32
+ const Util = require('@mojaloop/central-services-shared').Util
32
33
 
33
- const createSettlementModel = async (name, isActive = true, settlementGranularityId, settlementInterchangeId, settlementDelayId, currencyId = null, requireLiquidityCheck = true, ledgerAccountTypeId, autoPositionReset = false) => {
34
+ const createSettlementModel = async (settlementModel, trx = null) => {
34
35
  try {
35
- await SettlementModelModel.create(name, isActive, settlementGranularityId, settlementInterchangeId, settlementDelayId, currencyId, requireLiquidityCheck, ledgerAccountTypeId, autoPositionReset)
36
+ const settlementGranularityId = Enum.SettlementGranularity[settlementModel.settlementGranularity]
37
+ const settlementInterchangeId = Enum.SettlementInterchange[settlementModel.settlementInterchange]
38
+ const settlementDelayId = Enum.SettlementDelay[settlementModel.settlementDelay]
39
+
40
+ const [ledgerAccountType, settlementAccountType] = await validateSettlementModel(settlementModel, settlementModel.settlementDelay, settlementModel.settlementGranularity, settlementModel.settlementInterchange, trx)
41
+ await SettlementModelModel.create(settlementModel.name, true, settlementGranularityId,
42
+ settlementInterchangeId, settlementDelayId, settlementModel.currency,
43
+ settlementModel.requireLiquidityCheck,
44
+ ledgerAccountType.ledgerAccountTypeId, settlementAccountType.ledgerAccountTypeId, settlementModel.autoPositionReset, trx)
36
45
  return true
37
46
  } catch (err) {
38
47
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
39
48
  }
40
49
  }
41
- const getByName = async (name) => {
50
+ /* istanbul ignore next */
51
+ const getByName = async (name, trx = null) => {
42
52
  try {
43
- return await SettlementModelModel.getByName(name)
53
+ return await SettlementModelModel.getByName(name, trx)
44
54
  } catch (err) {
55
+ /* istanbul ignore next */
45
56
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
46
57
  }
47
58
  }
@@ -78,10 +89,32 @@ const settlementModeExists = (settlementModel) => {
78
89
  }
79
90
  throw ErrorHandler.Factory.createInternalServerFSPIOPError('Settlement Model does not exist')
80
91
  }
92
+ /* istanbul ignore next */
93
+ const validateSettlementModel = async function (settlementModel, settlementDelay, settlementGranularity, settlementInterchange, trx = null) {
94
+ const { isValid, reasons } = Util.Settlement.validateSettlementModel(settlementDelay, settlementGranularity, settlementInterchange)
95
+ if (!isValid) {
96
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.CLIENT_ERROR, reasons.join('. '))
97
+ }
98
+ const ledgerAccountType = await LedgerAccountTypeModel.getLedgerAccountByName(settlementModel.ledgerAccountType, trx)
99
+ if (!ledgerAccountType) {
100
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Ledger account type was not found')
101
+ }
102
+ const settlementAccountType = await LedgerAccountTypeModel.getLedgerAccountByName(settlementModel.settlementAccountType, trx)
103
+ if (!settlementAccountType) {
104
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ADD_PARTY_INFO_ERROR, 'Settlement account type was not found')
105
+ }
106
+ const settlementModelExist = await getByName(settlementModel.name, trx)
107
+ if (settlementModelExist) {
108
+ throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.CLIENT_ERROR, 'Settlement Model already exists')
109
+ }
110
+ return [ledgerAccountType, settlementAccountType]
111
+ }
112
+
81
113
  module.exports = {
82
114
  createSettlementModel,
83
115
  getLedgerAccountTypeName,
84
116
  getByName,
85
117
  getAll,
86
- update
118
+ update,
119
+ validateSettlementModel
87
120
  }
@@ -0,0 +1,61 @@
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
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ 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.
8
+ Contributors
9
+ --------------
10
+ This is the official list of the Mojaloop project contributors for this file.
11
+ Names of the original copyright holders (individuals or organizations)
12
+ should be listed with a '*' in the first column. People who have
13
+ contributed from an organization can be listed under the organization
14
+ that actually holds the copyright for their contributions (see the
15
+ Gates Foundation organization for an example). Those individuals should have
16
+ their names indented and be marked with a '-'. Email address can be added
17
+ optionally within square brackets <email>.
18
+ * Gates Foundation
19
+ - Name Surname <name.surname@gatesfoundation.com>
20
+
21
+ * ModusBox
22
+ - Lazola Lucas <lazola.lucas@modusbox.com>
23
+ --------------
24
+ ******/
25
+ 'use strict'
26
+
27
+ const IlpPacket = require('../../models/ilpPackets/ilpPacket')
28
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
+
30
+ const ilpPacket = require('ilp-packet')
31
+ const base64url = require('base64url')
32
+
33
+ const getById = async (id) => {
34
+ try {
35
+ return await IlpPacket.getById(id)
36
+ } catch (err) {
37
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
38
+ }
39
+ }
40
+ const decodeIlpPacket = async (inputIlpPacket) => {
41
+ const binaryPacket = Buffer.from(inputIlpPacket, 'base64')
42
+ return ilpPacket.deserializeIlpPayment(binaryPacket)
43
+ }
44
+ /**
45
+ * Get the transaction object in the data field of an Ilp packet
46
+ *
47
+ * @returns {object} - Transaction Object
48
+ */
49
+ const getTransactionObject = async function (inputIlpPacket) {
50
+ try {
51
+ const jsonPacket = await decodeIlpPacket(inputIlpPacket)
52
+ const decodedData = base64url.decode(jsonPacket.data.toString())
53
+ return JSON.parse(decodedData)
54
+ } catch (err) {
55
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
56
+ }
57
+ }
58
+ module.exports = {
59
+ getById,
60
+ getTransactionObject
61
+ }
@@ -39,19 +39,38 @@ const TransferErrorDuplicateCheckModel = require('../../models/transfer/transfer
39
39
  const TransferObjectTransform = require('./transform')
40
40
  const TransferError = require('../../models/transfer/transferError')
41
41
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
42
+ const Metrics = require('@mojaloop/central-services-metrics')
42
43
 
43
44
  const prepare = async (payload, stateReason = null, hasPassedValidation = true) => {
45
+ const histTimerTransferServicePrepareEnd = Metrics.getHistogram(
46
+ 'domain_transfer',
47
+ 'prepare - Metrics for transfer domain',
48
+ ['success', 'funcName']
49
+ ).startTimer()
44
50
  try {
45
- return await TransferFacade.saveTransferPrepared(payload, stateReason, hasPassedValidation)
51
+ const result = await TransferFacade.saveTransferPrepared(payload, stateReason, hasPassedValidation)
52
+ histTimerTransferServicePrepareEnd({ success: true, funcName: 'prepare' })
53
+ return result
46
54
  } catch (err) {
55
+ histTimerTransferServicePrepareEnd({ success: false, funcName: 'prepare' })
47
56
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
48
57
  }
49
58
  }
59
+
50
60
  const handlePayeeResponse = async (transferId, payload, action, fspiopError) => {
61
+ const histTimerTransferServiceHandlePayeeResponseEnd = Metrics.getHistogram(
62
+ 'domain_transfer',
63
+ 'prepare - Metrics for transfer domain',
64
+ ['success', 'funcName']
65
+ ).startTimer()
66
+
51
67
  try {
52
68
  const transfer = await TransferFacade.savePayeeTransferResponse(transferId, payload, action, fspiopError)
53
- return TransferObjectTransform.toTransfer(transfer)
69
+ const result = TransferObjectTransform.toTransfer(transfer)
70
+ histTimerTransferServiceHandlePayeeResponseEnd({ success: true, funcName: 'handlePayeeResponse' })
71
+ return result
54
72
  } catch (err) {
73
+ histTimerTransferServiceHandlePayeeResponseEnd({ success: false, funcName: 'handlePayeeResponse' })
55
74
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
56
75
  }
57
76
  }
@@ -98,6 +117,7 @@ const TransferService = {
98
117
  reconciliationTransferReserve: TransferFacade.reconciliationTransferReserve,
99
118
  reconciliationTransferCommit: TransferFacade.reconciliationTransferCommit,
100
119
  reconciliationTransferAbort: TransferFacade.reconciliationTransferAbort,
120
+ recordFundsIn: TransferFacade.recordFundsIn,
101
121
  getTransferParticipant: TransferFacade.getTransferParticipant,
102
122
  getTransferDuplicateCheck: TransferDuplicateCheckModel.getTransferDuplicateCheck,
103
123
  saveTransferDuplicateCheck: TransferDuplicateCheckModel.saveTransferDuplicateCheck,
@@ -130,13 +130,13 @@ const transformTransferToFulfil = (transfer) => {
130
130
  const toTransfer = (t) => {
131
131
  // TODO: Validate 't' to confirm if its from the DB transferReadModel or from the saveTransferPrepare
132
132
  if (t.isTransferReadModel) {
133
- Logger.debug('In aggregate transfer transform for isTransferReadModel')
133
+ Logger.isDebugEnabled && Logger.debug('In aggregate transfer transform for isTransferReadModel')
134
134
  return Util.omitNil(fromTransferReadModel(t)) // TODO: Remove this once the DB validation is done for 't'
135
135
  } else if (t.isSaveTransferPrepared) {
136
- Logger.debug('In aggregate transfer transform for isSaveTransferPrepared')
136
+ Logger.isDebugEnabled && Logger.debug('In aggregate transfer transform for isSaveTransferPrepared')
137
137
  return Util.omitNil(fromSaveTransferPrepared(t)) // TODO: Remove this once the DB validation is done for 't'
138
138
  } else if (t.savePayeeTransferResponseExecuted) {
139
- Logger.debug('In aggregate transfer transform for isSavePayeeTransferResponseExecuted')
139
+ Logger.isDebugEnabled && Logger.debug('In aggregate transfer transform for isSavePayeeTransferResponseExecuted')
140
140
  return Util.omitNil(fromSavePayeeTransferResponseExecuted(t)) // TODO: Remove this once the DB validation is done for 't'
141
141
  } else throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `Unable to transform to transfer: ${t}`)
142
142
  }