@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
@@ -28,41 +28,116 @@
28
28
  const Db = require('../../lib/db')
29
29
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
30
30
 
31
- exports.create = async (name, isActive, settlementGranularityId, settlementInterchangeId, settlementDelayId, currencyId, requireLiquidityCheck, ledgerAccountTypeId, autoPositionReset) => {
31
+ /* istanbul ignore next */
32
+ exports.create = async (name, isActive, settlementGranularityId, settlementInterchangeId, settlementDelayId, currencyId, requireLiquidityCheck, ledgerAccountTypeId, settlementAccountTypeId, autoPositionReset, trx = null) => {
32
33
  try {
33
- return await Db.settlementModel.insert({
34
- name,
35
- isActive,
36
- settlementGranularityId,
37
- settlementInterchangeId,
38
- settlementDelayId,
39
- currencyId,
40
- requireLiquidityCheck,
41
- ledgerAccountTypeId,
42
- autoPositionReset
43
- })
34
+ const knex = Db.getKnex()
35
+ const trxFunction = async (trx, doCommit = true) => {
36
+ try {
37
+ await knex('settlementModel')
38
+ .insert({
39
+ name,
40
+ isActive,
41
+ settlementGranularityId,
42
+ settlementInterchangeId,
43
+ settlementDelayId,
44
+ currencyId,
45
+ requireLiquidityCheck,
46
+ ledgerAccountTypeId,
47
+ settlementAccountTypeId,
48
+ autoPositionReset
49
+ })
50
+ .transacting(trx)
51
+ if (doCommit) {
52
+ await trx.commit
53
+ }
54
+ } catch (err) {
55
+ if (doCommit) {
56
+ await trx.rollback
57
+ }
58
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
59
+ }
60
+ }
61
+ if (trx) {
62
+ return trxFunction(trx, false)
63
+ } else {
64
+ return knex.transaction(trxFunction)
65
+ }
44
66
  } catch (err) {
45
67
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
46
68
  }
47
69
  }
48
- exports.getByName = async (name) => {
70
+ /* istanbul ignore next */
71
+ exports.getByName = async (name, trx = null) => {
49
72
  try {
50
- const result = await Db.settlementModel.find({ name: name })
51
- return result[0]
73
+ const knex = Db.getKnex()
74
+ const trxFunction = async (trx, doCommit = true) => {
75
+ try {
76
+ const result = await knex('settlementModel')
77
+ .select()
78
+ .where('name', name)
79
+ .transacting(trx)
80
+ if (doCommit) {
81
+ await trx.commit
82
+ }
83
+ return result.length > 0 ? result[0] : null
84
+ } catch (err) {
85
+ if (doCommit) {
86
+ await trx.rollback
87
+ }
88
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
89
+ }
90
+ }
91
+ if (trx) {
92
+ return trxFunction(trx, false)
93
+ } else {
94
+ return knex.transaction(trxFunction)
95
+ }
52
96
  } catch (err) {
53
97
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
54
98
  }
55
99
  }
56
100
  exports.getAll = async () => {
57
101
  try {
58
- return await Db.settlementModel.find()
102
+ return await Db.from('settlementModel').find({ isActive: 1 })
59
103
  } catch (err) {
60
104
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
61
105
  }
62
106
  }
63
107
  exports.update = async (settlementModel, isActive) => {
64
108
  try {
65
- return await Db.settlementModel.update({ settlementModelId: settlementModel.settlementModelId }, { isActive })
109
+ return await Db.from('settlementModel').update({ settlementModelId: settlementModel.settlementModelId }, { isActive })
110
+ } catch (err) {
111
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
112
+ }
113
+ }
114
+
115
+ /* istanbul ignore next */
116
+ exports.getSettlementModelsByName = async (names, trx = null) => {
117
+ try {
118
+ const knex = Db.getKnex()
119
+ const trxFunction = async (trx, doCommit = true) => {
120
+ try {
121
+ const settlementModelNames = knex('settlementModel')
122
+ .select('name')
123
+ .whereIn('name', names)
124
+ .transacting(trx)
125
+ if (doCommit) {
126
+ await trx.commit
127
+ }
128
+ return settlementModelNames
129
+ } catch (err) {
130
+ if (doCommit) {
131
+ await trx.rollback
132
+ }
133
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
134
+ }
135
+ }
136
+ if (trx) {
137
+ return trxFunction(trx, false)
138
+ } else {
139
+ return knex.transaction(trxFunction)
140
+ }
66
141
  } catch (err) {
67
142
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
68
143
  }
@@ -0,0 +1,139 @@
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
+ * Neal Donnan <neal.donnan@modusbox.com>
22
+ --------------
23
+ ******/
24
+
25
+ 'use strict'
26
+
27
+ const ErrorHandler = require('@mojaloop/central-services-error-handling')
28
+ const Cache = require('../../lib/cache')
29
+ const SettlementModel = require('../../models/settlement/settlementModel')
30
+ const Metrics = require('@mojaloop/central-services-metrics')
31
+
32
+ let cacheClient
33
+ let settlementModelsAllCacheKey
34
+
35
+ /*
36
+ Private API
37
+ */
38
+
39
+ const buildUnifiedSettlementModelsData = (allSettlementModels) => {
40
+ // build indexes (or indices?) - optimization for byId and byName access
41
+ const indexById = {}
42
+ const indexByName = {}
43
+ const indexByLedgerAccountTypeId = {}
44
+
45
+ allSettlementModels.forEach((oneSettlementModel) => {
46
+ // Add to indexes
47
+ indexById[oneSettlementModel.settlementModelId] = oneSettlementModel
48
+ indexByName[oneSettlementModel.name] = oneSettlementModel
49
+ indexByLedgerAccountTypeId[oneSettlementModel.ledgerAccountTypeId] = oneSettlementModel
50
+ })
51
+
52
+ // build unified structure - indexes + data
53
+ const unifiedSettlementModels = {
54
+ indexById,
55
+ indexByName,
56
+ indexByLedgerAccountTypeId,
57
+ allSettlementModels
58
+ }
59
+
60
+ return unifiedSettlementModels
61
+ }
62
+
63
+ const getSettlementModelsCached = async () => {
64
+ const histTimer = Metrics.getHistogram(
65
+ 'model_settlementModel',
66
+ 'model_getSettlementModelsCached - Metrics for settlementModel model',
67
+ ['success', 'queryName', 'hit']
68
+ ).startTimer()
69
+ // Do we have valid settlement models list in the cache ?
70
+ let cachedSettlementModels = cacheClient.get(settlementModelsAllCacheKey)
71
+ if (!cachedSettlementModels) {
72
+ // No settlement models in the cache, so fetch from participant API
73
+ const allSettlementModels = await SettlementModel.getAll()
74
+ cachedSettlementModels = buildUnifiedSettlementModelsData(allSettlementModels)
75
+
76
+ // store in cache
77
+ cacheClient.set(settlementModelsAllCacheKey, cachedSettlementModels)
78
+ histTimer({ success: true, queryName: 'model_getSettlementModelsCached', hit: false })
79
+ } else {
80
+ // unwrap settlement models list from catbox structure
81
+ cachedSettlementModels = cachedSettlementModels.item
82
+ histTimer({ success: true, queryName: 'model_getSettlementModelsCached', hit: true })
83
+ }
84
+ return cachedSettlementModels
85
+ }
86
+
87
+ /*
88
+ Public API
89
+ */
90
+ exports.initialize = async () => {
91
+ /* Register as cache client */
92
+ const settlementModelCacheClientMeta = {
93
+ id: 'settlementModels',
94
+ preloadCache: getSettlementModelsCached
95
+ }
96
+
97
+ cacheClient = Cache.registerCacheClient(settlementModelCacheClientMeta)
98
+ settlementModelsAllCacheKey = cacheClient.createKey('all')
99
+ }
100
+
101
+ exports.invalidateSettlementModelsCache = async () => {
102
+ cacheClient.drop(settlementModelsAllCacheKey)
103
+ }
104
+
105
+ exports.getById = async (id) => {
106
+ try {
107
+ const cachedSettlementModels = await getSettlementModelsCached()
108
+ return cachedSettlementModels.indexById[id]
109
+ } catch (err) {
110
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
111
+ }
112
+ }
113
+
114
+ exports.getByName = async (name) => {
115
+ try {
116
+ const cachedSettlementModels = await getSettlementModelsCached()
117
+ return cachedSettlementModels.indexByName[name]
118
+ } catch (err) {
119
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
120
+ }
121
+ }
122
+
123
+ exports.getByLedgerAccountTypeId = async (ledgerAccountTypeId) => {
124
+ try {
125
+ const cachedSettlementModels = await getSettlementModelsCached()
126
+ return cachedSettlementModels.indexByLedgerAccountTypeId[ledgerAccountTypeId]
127
+ } catch (err) {
128
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
129
+ }
130
+ }
131
+
132
+ exports.getAll = async () => {
133
+ try {
134
+ const cachedSettlementModels = await getSettlementModelsCached()
135
+ return cachedSettlementModels.allSettlementModels
136
+ } catch (err) {
137
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
138
+ }
139
+ }
@@ -44,6 +44,7 @@ const Config = require('../../lib/config')
44
44
  const _ = require('lodash')
45
45
  const ErrorHandler = require('@mojaloop/central-services-error-handling')
46
46
  const Logger = require('@mojaloop/central-services-logger')
47
+ const Metrics = require('@mojaloop/central-services-metrics')
47
48
 
48
49
  // Alphabetically ordered list of error texts used below
49
50
  const UnsupportedActionText = 'Unsupported action'
@@ -51,7 +52,7 @@ const UnsupportedActionText = 'Unsupported action'
51
52
  const getById = async (id) => {
52
53
  try {
53
54
  /** @namespace Db.transfer **/
54
- return await Db.transfer.query(async (builder) => {
55
+ return await Db.from('transfer').query(async (builder) => {
55
56
  const transferResult = await builder
56
57
  .where({
57
58
  'transfer.transferId': id,
@@ -122,7 +123,7 @@ const getById = async (id) => {
122
123
  const getByIdLight = async (id) => {
123
124
  try {
124
125
  /** @namespace Db.transfer **/
125
- return await Db.transfer.query(async (builder) => {
126
+ return await Db.from('transfer').query(async (builder) => {
126
127
  const transferResult = await builder
127
128
  .where({ 'transfer.transferId': id })
128
129
  .leftJoin('ilpPacket AS ilpp', 'ilpp.transferId', 'transfer.transferId')
@@ -173,7 +174,7 @@ const getByIdLight = async (id) => {
173
174
 
174
175
  const getAll = async () => {
175
176
  try {
176
- return await Db.transfer.query(async (builder) => {
177
+ return await Db.from('transfer').query(async (builder) => {
177
178
  const transferResultList = await builder
178
179
  .where({
179
180
  'tprt1.name': 'PAYER_DFSP', // TODO: refactor to use transferParticipantRoleTypeId
@@ -228,7 +229,7 @@ const getAll = async () => {
228
229
  const getTransferInfoToChangePosition = async (id, transferParticipantRoleTypeId, ledgerEntryTypeId) => {
229
230
  try {
230
231
  /** @namespace Db.transferParticipant **/
231
- return await Db.transferParticipant.query(async builder => {
232
+ return await Db.from('transferParticipant').query(async builder => {
232
233
  return builder
233
234
  .where({
234
235
  'transferParticipant.transferId': id,
@@ -250,6 +251,12 @@ const getTransferInfoToChangePosition = async (id, transferParticipantRoleTypeId
250
251
  }
251
252
 
252
253
  const savePayeeTransferResponse = async (transferId, payload, action, fspiopError) => {
254
+ const histTimerSavePayeeTranferResponsedEnd = Metrics.getHistogram(
255
+ 'model_transfer',
256
+ 'facade_savePayeeTransferResponse - Metrics for transfer model',
257
+ ['success', 'queryName']
258
+ ).startTimer()
259
+
253
260
  let state
254
261
  let isFulfilment = false
255
262
  let isError = false
@@ -259,18 +266,22 @@ const savePayeeTransferResponse = async (transferId, payload, action, fspiopErro
259
266
  switch (action) {
260
267
  case TransferEventAction.COMMIT:
261
268
  case TransferEventAction.BULK_COMMIT:
269
+ case TransferEventAction.RESERVE:
262
270
  state = TransferInternalState.RECEIVED_FULFIL
263
- extensionList = payload.extensionList
271
+ extensionList = payload && payload.extensionList
264
272
  isFulfilment = true
265
273
  break
266
274
  case TransferEventAction.REJECT:
267
275
  state = TransferInternalState.RECEIVED_REJECT
276
+ extensionList = payload && payload.extensionList
268
277
  extensionList = payload.extensionList
269
278
  isFulfilment = true
270
279
  break
280
+ case TransferEventAction.BULK_ABORT:
281
+ case TransferEventAction.ABORT_VALIDATION:
271
282
  case TransferEventAction.ABORT:
272
283
  state = TransferInternalState.RECEIVED_ERROR
273
- extensionList = payload.errorInformation.extensionList
284
+ extensionList = payload && payload.errorInformation && payload.errorInformation.extensionList
274
285
  isError = true
275
286
  break
276
287
  default:
@@ -319,10 +330,16 @@ const savePayeeTransferResponse = async (transferId, payload, action, fspiopErro
319
330
  try {
320
331
  /** @namespace Db.getKnex **/
321
332
  const knex = await Db.getKnex()
333
+ const histTPayeeResponseValidationPassedEnd = Metrics.getHistogram(
334
+ 'model_transfer',
335
+ 'facade_saveTransferPrepared_transaction - Metrics for transfer model',
336
+ ['success', 'queryName']
337
+ ).startTimer()
338
+
322
339
  await knex.transaction(async (trx) => {
323
340
  try {
324
- if (!fspiopError && [TransferEventAction.COMMIT, TransferEventAction.BULK_COMMIT].includes(action)) {
325
- const res = await Db.settlementWindow.query(builder => {
341
+ if (!fspiopError && [TransferEventAction.COMMIT, TransferEventAction.BULK_COMMIT, TransferEventAction.RESERVE].includes(action)) {
342
+ const res = await Db.from('settlementWindow').query(builder => {
326
343
  return builder
327
344
  .leftJoin('settlementWindowStateChange AS swsc', 'swsc.settlementWindowStateChangeId', 'settlementWindow.currentStateChangeId')
328
345
  .select(
@@ -336,23 +353,25 @@ const savePayeeTransferResponse = async (transferId, payload, action, fspiopErro
336
353
  .orderBy('changedDate', 'desc')
337
354
  })
338
355
  transferFulfilmentRecord.settlementWindowId = res[0].settlementWindowId
339
- Logger.debug('savePayeeTransferResponse::settlementWindowId')
356
+ Logger.isDebugEnabled && Logger.debug('savePayeeTransferResponse::settlementWindowId')
340
357
  }
341
358
  if (isFulfilment) {
342
359
  await knex('transferFulfilment').transacting(trx).insert(transferFulfilmentRecord)
343
360
  result.transferFulfilmentRecord = transferFulfilmentRecord
344
- Logger.debug('savePayeeTransferResponse::transferFulfilment')
361
+ Logger.isDebugEnabled && Logger.debug('savePayeeTransferResponse::transferFulfilment')
345
362
  }
346
363
  if (transferExtensionRecordsList.length > 0) {
364
+ // ###! CAN BE DONE THROUGH A BATCH
347
365
  for (const transferExtension of transferExtensionRecordsList) {
348
366
  await knex('transferExtension').transacting(trx).insert(transferExtension)
349
367
  }
368
+ // ###!
350
369
  result.transferExtensionRecordsList = transferExtensionRecordsList
351
- Logger.debug('savePayeeTransferResponse::transferExtensionRecordsList')
370
+ Logger.isDebugEnabled && Logger.debug('savePayeeTransferResponse::transferExtensionRecordsList')
352
371
  }
353
372
  await knex('transferStateChange').transacting(trx).insert(transferStateChangeRecord)
354
373
  result.transferStateChangeRecord = transferStateChangeRecord
355
- Logger.debug('savePayeeTransferResponse::transferStateChange')
374
+ Logger.isDebugEnabled && Logger.debug('savePayeeTransferResponse::transferStateChange')
356
375
  if (fspiopError) {
357
376
  const insertedTransferStateChange = await knex('transferStateChange').transacting(trx)
358
377
  .where({ transferId })
@@ -361,24 +380,32 @@ const savePayeeTransferResponse = async (transferId, payload, action, fspiopErro
361
380
  transferErrorRecord.transferStateChangeId = insertedTransferStateChange.transferStateChangeId
362
381
  await knex('transferError').transacting(trx).insert(transferErrorRecord)
363
382
  result.transferErrorRecord = transferErrorRecord
364
- Logger.debug('savePayeeTransferResponse::transferError')
383
+ Logger.isDebugEnabled && Logger.debug('savePayeeTransferResponse::transferError')
365
384
  }
366
- await trx.commit
385
+ histTPayeeResponseValidationPassedEnd({ success: true, queryName: 'facade_saveTransferPrepared_transaction' })
367
386
  result.savePayeeTransferResponseExecuted = true
368
- Logger.debug('savePayeeTransferResponse::success')
387
+ Logger.isDebugEnabled && Logger.debug('savePayeeTransferResponse::success')
369
388
  } catch (err) {
370
- await trx.rollback
371
- Logger.error('savePayeeTransferResponse::failure')
389
+ await trx.rollback()
390
+ histTPayeeResponseValidationPassedEnd({ success: false, queryName: 'facade_saveTransferPrepared_transaction' })
391
+ Logger.isErrorEnabled && Logger.error('savePayeeTransferResponse::failure')
372
392
  throw err
373
393
  }
374
394
  })
395
+ histTimerSavePayeeTranferResponsedEnd({ success: true, queryName: 'facade_savePayeeTransferResponse' })
375
396
  return result
376
397
  } catch (err) {
398
+ histTimerSavePayeeTranferResponsedEnd({ success: false, queryName: 'facade_savePayeeTransferResponse' })
377
399
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
378
400
  }
379
401
  }
380
402
 
381
403
  const saveTransferPrepared = async (payload, stateReason = null, hasPassedValidation = true) => {
404
+ const histTimerSaveTransferPreparedEnd = Metrics.getHistogram(
405
+ 'model_transfer',
406
+ 'facade_saveTransferPrepared - Metrics for transfer model',
407
+ ['success', 'queryName']
408
+ ).startTimer()
382
409
  try {
383
410
  const participants = []
384
411
  const names = [payload.payeeFsp, payload.payerFsp]
@@ -433,6 +460,11 @@ const saveTransferPrepared = async (payload, stateReason = null, hasPassedValida
433
460
 
434
461
  const knex = await Db.getKnex()
435
462
  if (hasPassedValidation) {
463
+ const histTimerSaveTranferTransactionValidationPassedEnd = Metrics.getHistogram(
464
+ 'model_transfer',
465
+ 'facade_saveTransferPrepared_transaction - Metrics for transfer model',
466
+ ['success', 'queryName']
467
+ ).startTimer()
436
468
  return await knex.transaction(async (trx) => {
437
469
  try {
438
470
  await knex('transfer').transacting(trx).insert(transferRecord)
@@ -453,23 +485,32 @@ const saveTransferPrepared = async (payload, stateReason = null, hasPassedValida
453
485
  }
454
486
  await knex('ilpPacket').transacting(trx).insert(ilpPacketRecord)
455
487
  await knex('transferStateChange').transacting(trx).insert(transferStateChangeRecord)
456
- await trx.commit
488
+ await trx.commit()
489
+ histTimerSaveTranferTransactionValidationPassedEnd({ success: true, queryName: 'facade_saveTransferPrepared_transaction' })
457
490
  } catch (err) {
458
- await trx.rollback
491
+ await trx.rollback()
492
+ histTimerSaveTranferTransactionValidationPassedEnd({ success: false, queryName: 'facade_saveTransferPrepared_transaction' })
459
493
  throw err
460
494
  }
461
495
  })
462
496
  } else {
497
+ const histTimerSaveTranferNoValidationEnd = Metrics.getHistogram(
498
+ 'model_transfer',
499
+ 'facade_saveTransferPrepared_no_validation - Metrics for transfer model',
500
+ ['success', 'queryName']
501
+ ).startTimer()
463
502
  await knex('transfer').insert(transferRecord)
464
503
  try {
465
504
  await knex('transferParticipant').insert(payerTransferParticipantRecord)
466
505
  } catch (err) {
467
- Logger.warn(`Payer transferParticipant insert error: ${err.message}`)
506
+ Logger.isWarnEnabled && Logger.warn(`Payer transferParticipant insert error: ${err.message}`)
507
+ histTimerSaveTranferNoValidationEnd({ success: false, queryName: 'facade_saveTransferPrepared_no_validation' })
468
508
  }
469
509
  try {
470
510
  await knex('transferParticipant').insert(payeeTransferParticipantRecord)
471
511
  } catch (err) {
472
- Logger.warn(`Payee transferParticipant insert error: ${err.message}`)
512
+ histTimerSaveTranferNoValidationEnd({ success: false, queryName: 'facade_saveTransferPrepared_no_validation' })
513
+ Logger.isWarnEnabled && Logger.warn(`Payee transferParticipant insert error: ${err.message}`)
473
514
  }
474
515
  payerTransferParticipantRecord.name = payload.payerFsp
475
516
  payeeTransferParticipantRecord.name = payload.payeeFsp
@@ -485,21 +526,27 @@ const saveTransferPrepared = async (payload, stateReason = null, hasPassedValida
485
526
  try {
486
527
  await knex.batchInsert('transferExtension', transferExtensionsRecordList)
487
528
  } catch (err) {
488
- Logger.warn(`batchInsert transferExtension error: ${err.message}`)
529
+ Logger.isWarnEnabled && Logger.warn(`batchInsert transferExtension error: ${err.message}`)
530
+ histTimerSaveTranferNoValidationEnd({ success: false, queryName: 'facade_saveTransferPrepared_no_validation' })
489
531
  }
490
532
  }
491
533
  try {
492
534
  await knex('ilpPacket').insert(ilpPacketRecord)
493
535
  } catch (err) {
494
- Logger.warn(`ilpPacket insert error: ${err.message}`)
536
+ Logger.isWarnEnabled && Logger.warn(`ilpPacket insert error: ${err.message}`)
537
+ histTimerSaveTranferNoValidationEnd({ success: false, queryName: 'facade_saveTransferPrepared_no_validation' })
495
538
  }
496
539
  try {
497
540
  await knex('transferStateChange').insert(transferStateChangeRecord)
541
+ histTimerSaveTranferNoValidationEnd({ success: true, queryName: 'facade_saveTransferPrepared_no_validation' })
498
542
  } catch (err) {
499
- Logger.warn(`transferStateChange insert error: ${err.message}`)
543
+ Logger.isWarnEnabled && Logger.warn(`transferStateChange insert error: ${err.message}`)
544
+ histTimerSaveTranferNoValidationEnd({ success: false, queryName: 'facade_saveTransferPrepared_no_validation' })
500
545
  }
501
546
  }
547
+ histTimerSaveTransferPreparedEnd({ success: true, queryName: 'transfer_model_facade_saveTransferPrepared' })
502
548
  } catch (err) {
549
+ histTimerSaveTransferPreparedEnd({ success: false, queryName: 'transfer_model_facade_saveTransferPrepared' })
503
550
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
504
551
  }
505
552
  }
@@ -529,7 +576,7 @@ const saveTransferPrepared = async (payload, stateReason = null, hasPassedValida
529
576
  const getTransferStateByTransferId = async (id) => {
530
577
  try {
531
578
  /** @namespace Db.transferStateChange **/
532
- return await Db.transferStateChange.query(async (builder) => {
579
+ return await Db.from('transferStateChange').query(async (builder) => {
533
580
  return builder
534
581
  .innerJoin('transferState AS ts', 'ts.transferStateId', 'transferStateChange.transferStateId')
535
582
  .where({
@@ -734,7 +781,7 @@ const transferStateAndPositionUpdate = async function (param1, enums, trx = null
734
781
  await knex('participantPositionChange')
735
782
  .insert({
736
783
  participantPositionId: info.drPositionId,
737
- transferStateChangeId: transferStateChangeId,
784
+ transferStateChangeId,
738
785
  value: new MLNumber(info.drPositionValue).add(info.drAmount).toFixed(Config.AMOUNT.SCALE),
739
786
  reservedValue: info.drReservedValue,
740
787
  createdDate: param1.createdDate
@@ -757,7 +804,7 @@ const transferStateAndPositionUpdate = async function (param1, enums, trx = null
757
804
  await knex('participantPositionChange')
758
805
  .insert({
759
806
  participantPositionId: info.crPositionId,
760
- transferStateChangeId: transferStateChangeId,
807
+ transferStateChangeId,
761
808
  value: new MLNumber(info.crPositionValue).add(info.crAmount).toFixed(Config.AMOUNT.SCALE),
762
809
  reservedValue: info.crReservedValue,
763
810
  createdDate: param1.createdDate
@@ -838,8 +885,8 @@ const reconciliationTransferPrepare = async function (payload, transactionTimest
838
885
  transferId: payload.transferId,
839
886
  participantCurrencyId: reconciliationAccountId,
840
887
  transferParticipantRoleTypeId: enums.transferParticipantRoleType.HUB,
841
- ledgerEntryTypeId: ledgerEntryTypeId,
842
- amount: amount,
888
+ ledgerEntryTypeId,
889
+ amount,
843
890
  createdDate: transactionTimestamp
844
891
  })
845
892
  .transacting(trx)
@@ -848,7 +895,7 @@ const reconciliationTransferPrepare = async function (payload, transactionTimest
848
895
  transferId: payload.transferId,
849
896
  participantCurrencyId: payload.participantCurrencyId,
850
897
  transferParticipantRoleTypeId: enums.transferParticipantRoleType.DFSP_SETTLEMENT,
851
- ledgerEntryTypeId: ledgerEntryTypeId,
898
+ ledgerEntryTypeId,
852
899
  amount: -amount,
853
900
  createdDate: transactionTimestamp
854
901
  })
@@ -1079,7 +1126,7 @@ const reconciliationTransferAbort = async function (payload, transactionTimestam
1079
1126
 
1080
1127
  const getTransferParticipant = async (participantName, transferId) => {
1081
1128
  try {
1082
- return Db.participant.query(async (builder) => {
1129
+ return Db.from('participant').query(async (builder) => {
1083
1130
  return builder
1084
1131
  .where({
1085
1132
  'participant.name': participantName,
@@ -1098,6 +1145,23 @@ const getTransferParticipant = async (participantName, transferId) => {
1098
1145
  }
1099
1146
  }
1100
1147
 
1148
+ const recordFundsIn = async (payload, transactionTimestamp, enums) => {
1149
+ const knex = Db.getKnex()
1150
+ // Save the valid transfer into the database
1151
+ return knex.transaction(async trx => {
1152
+ try {
1153
+ await TransferFacade.reconciliationTransferPrepare(payload, transactionTimestamp, enums, trx)
1154
+ await TransferFacade.reconciliationTransferReserve(payload, transactionTimestamp, enums, trx)
1155
+ await TransferFacade.reconciliationTransferCommit(payload, transactionTimestamp, enums, trx)
1156
+ await trx.commit
1157
+ } catch (err) {
1158
+ Logger.isErrorEnabled && Logger.error(err)
1159
+ await trx.rollback
1160
+ throw ErrorHandler.Factory.reformatFSPIOPError(err)
1161
+ }
1162
+ })
1163
+ }
1164
+
1101
1165
  const TransferFacade = {
1102
1166
  getById,
1103
1167
  getByIdLight,
@@ -1112,7 +1176,8 @@ const TransferFacade = {
1112
1176
  reconciliationTransferReserve,
1113
1177
  reconciliationTransferCommit,
1114
1178
  reconciliationTransferAbort,
1115
- getTransferParticipant
1179
+ getTransferParticipant,
1180
+ recordFundsIn
1116
1181
  }
1117
1182
 
1118
1183
  module.exports = TransferFacade
@@ -33,7 +33,7 @@ const ErrorHandler = require('@mojaloop/central-services-error-handling')
33
33
 
34
34
  exports.saveIlpPacket = async (record) => {
35
35
  try {
36
- return await Db.ilpPacket.insert({
36
+ return await Db.from('ilpPacket').insert({
37
37
  transferId: record.transferId,
38
38
  value: record.value
39
39
  })
@@ -44,7 +44,7 @@ exports.saveIlpPacket = async (record) => {
44
44
 
45
45
  exports.getByTransferId = async (transferId) => {
46
46
  try {
47
- return await Db.ilpPacket.findOne({ transferId: transferId })
47
+ return await Db.from('ilpPacket').findOne({ transferId })
48
48
  } catch (err) {
49
49
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
50
50
  }
@@ -56,7 +56,7 @@ exports.update = async (record) => {
56
56
  value: record.value
57
57
  }
58
58
  try {
59
- return await Db.ilpPacket.update({ transferId: record.transferId }, Util.omitNil(fields))
59
+ return await Db.from('ilpPacket').update({ transferId: record.transferId }, Util.omitNil(fields))
60
60
  } catch (err) {
61
61
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
62
62
  }
@@ -64,7 +64,7 @@ exports.update = async (record) => {
64
64
 
65
65
  exports.destroyByTransferId = async (record) => {
66
66
  try {
67
- return await Db.ilpPacket.destroy({ transferId: record.transferId })
67
+ return await Db.from('ilpPacket').destroy({ transferId: record.transferId })
68
68
  } catch (err) {
69
69
  throw ErrorHandler.Factory.reformatFSPIOPError(err)
70
70
  }