@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.
- package/.circleci/config.yml +625 -204
- package/.env +3 -2
- package/.ncurc.yaml +9 -0
- package/.nvmrc +1 -1
- package/.versionrc +15 -0
- package/CHANGELOG.md +353 -0
- package/CODEOWNERS +31 -0
- package/Dockerfile +20 -14
- package/LICENSE.md +4 -4
- package/Onboarding.md +0 -7
- package/README.md +99 -22
- package/audit-resolve.json +136 -1
- package/config/default.json +82 -27
- package/docker/central-ledger/default.json +68 -21
- package/docker/ml-api-adapter/default.json +10 -1
- package/docker/wait-for/wait-for-objstore.sh +1 -6
- package/docker/wait-for/wait-for.env +1 -1
- package/docker-compose.integration.yml +8 -5
- package/docker-compose.yml +73 -16
- package/migrations/310203_transferParticipant-indexes.js +38 -0
- package/migrations/310503_participantLimit-indexes-composite.js +38 -0
- package/migrations/{400401_settlementWindowStateChange-indexes.js → 400401_settlmentWindowStateChange-indexes.js} +0 -0
- package/migrations/401301_settlementModel-indexes.js +2 -0
- package/migrations/500401_quote-hotfix-2719.js +58 -0
- package/migrations/500501_feature-fixSubIdRef.js +53 -0
- package/migrations/500601_party-2480.js +63 -0
- package/migrations/501001_quoteExtension-quote-service-174.js +46 -0
- package/migrations/501002_quoteExtension-2522.js +61 -0
- package/migrations/800101_feature-fixSubIdRef.js +90 -0
- package/migrations/910102_hotfix954.js +4 -1
- package/migrations/940100_quotePartyIdInfoExtension.js +52 -0
- package/migrations/940101_quotePartyIdInfoExtension-2522.js +64 -0
- package/migrations/950100_settlementContentAggregation-decimal184.js +40 -0
- package/migrations/950101_transferParticipantStateChange.js +46 -0
- package/migrations/950102_settlementModel-adjustPosition.js +42 -0
- package/migrations/950103_dropTransferParticipantStateChange.js +47 -0
- package/migrations/950104_settlementModel-settlementAccountTypeId.js +79 -0
- package/migrations/950106_unique_settlement_model_ledger_account_currency.js +38 -0
- package/migrations/950107_settlementWindowContent_foreign_settlementModel.js +60 -0
- package/package.json +99 -81
- package/scripts/_wait4_all.js +146 -0
- package/seeds/amountType.js +4 -6
- package/seeds/balanceOfPayments.js +4 -6
- package/seeds/bulkProcessingState.js +4 -6
- package/seeds/bulkTransferState.js +4 -6
- package/seeds/currency.js +4 -6
- package/seeds/endpointType.js +128 -7
- package/seeds/ledgerAccountType.js +11 -10
- package/seeds/ledgerEntryType.js +5 -7
- package/seeds/participant.js +4 -6
- package/seeds/participantLimitType.js +4 -6
- package/seeds/partyIdentifierType.js +4 -6
- package/seeds/partyType.js +4 -6
- package/seeds/settlementDelay.js +4 -6
- package/seeds/settlementGranularity.js +4 -6
- package/seeds/settlementInterchange.js +4 -6
- package/seeds/settlementState.js +4 -6
- package/seeds/settlementWindow1State.js +4 -6
- package/seeds/transactionInitiator.js +4 -6
- package/seeds/transactionInitiatorType.js +4 -6
- package/seeds/transactionScenario.js +4 -6
- package/seeds/transferParticipantRoleType.js +4 -6
- package/seeds/transferState.js +9 -6
- package/src/api/interface/swagger.json +728 -948
- package/src/api/ledgerAccountTypes/handler.js +55 -0
- package/src/api/ledgerAccountTypes/routes.js +63 -0
- package/src/api/metrics/handler.js +2 -2
- package/src/api/metrics/routes.js +1 -1
- package/src/api/participants/handler.js +43 -35
- package/src/api/participants/routes.js +13 -13
- package/src/api/root/routes.js +2 -2
- package/src/api/settlementModels/handler.js +9 -26
- package/src/api/settlementModels/routes.js +4 -4
- package/src/api/transactions/handler.js +46 -0
- package/src/api/transactions/routes.js +45 -0
- package/src/domain/bulkTransfer/index.js +6 -5
- package/src/domain/ledgerAccountTypes/index.js +58 -0
- package/src/domain/participant/index.js +55 -4
- package/src/domain/position/index.js +18 -2
- package/src/domain/settlement/index.js +39 -6
- package/src/domain/transactions/index.js +61 -0
- package/src/domain/transfer/index.js +22 -2
- package/src/domain/transfer/transform.js +3 -3
- package/src/handlers/admin/handler.js +24 -32
- package/src/handlers/bulk/fulfil/handler.js +89 -56
- package/src/handlers/bulk/get/handler.js +203 -0
- package/src/handlers/bulk/index.js +4 -1
- package/src/handlers/bulk/prepare/handler.js +30 -29
- package/src/handlers/bulk/processing/handler.js +61 -32
- package/src/handlers/bulk/shared/validator.js +13 -1
- package/src/handlers/index.js +18 -9
- package/src/handlers/positions/handler.js +67 -46
- package/src/handlers/register.js +7 -7
- package/src/handlers/timeouts/handler.js +9 -4
- package/src/handlers/transfers/handler.js +408 -182
- package/src/handlers/transfers/validator.js +41 -11
- package/src/lib/cache.js +8 -34
- package/src/lib/config.js +5 -7
- package/src/lib/enum.js +22 -22
- package/src/lib/enumCached.js +76 -0
- package/src/lib/healthCheck/subServiceHealth.js +2 -2
- package/src/lib/requestLogger.js +9 -9
- package/src/lib/urlParser.js +1 -1
- package/src/models/bulkTransfer/bulkTransfer.js +6 -6
- package/src/models/bulkTransfer/bulkTransferAssociation.js +3 -3
- package/src/models/bulkTransfer/bulkTransferDuplicateCheck.js +4 -4
- package/src/models/bulkTransfer/bulkTransferExtension.js +2 -2
- package/src/models/bulkTransfer/bulkTransferFulfilmentDuplicateCheck.js +4 -4
- package/src/models/bulkTransfer/bulkTransferStateChange.js +7 -7
- package/src/models/bulkTransfer/facade.js +54 -3
- package/src/models/bulkTransfer/individualTransfer.js +2 -2
- package/src/models/ilpPackets/ilpPacket.js +36 -0
- package/src/models/ledgerAccountType/ledgerAccountType.js +139 -3
- package/src/models/misc/migrationLock.js +1 -1
- package/src/models/misc/segment.js +1 -1
- package/src/models/participant/facade.js +226 -76
- package/src/models/participant/participant.js +6 -5
- package/src/models/participant/participantCached.js +8 -0
- package/src/models/participant/participantCurrency.js +7 -7
- package/src/models/participant/participantCurrencyCached.js +11 -1
- package/src/models/participant/participantLimit.js +13 -13
- package/src/models/participant/participantLimitCached.js +124 -0
- package/src/models/participant/participantPosition.js +34 -5
- package/src/models/participant/participantPositionChange.js +10 -2
- package/src/models/position/facade.js +112 -18
- package/src/models/position/participantPosition.js +6 -6
- package/src/models/settlement/settlementModel.js +92 -17
- package/src/models/settlement/settlementModelCached.js +139 -0
- package/src/models/transfer/facade.js +97 -32
- package/src/models/transfer/ilpPacket.js +4 -4
- package/src/models/transfer/transfer.js +7 -7
- package/src/models/transfer/transferDuplicateCheck.js +21 -5
- package/src/models/transfer/transferError.js +5 -5
- package/src/models/transfer/transferErrorDuplicateCheck.js +4 -4
- package/src/models/transfer/transferExtension.js +4 -4
- package/src/models/transfer/transferFulfilment.js +5 -5
- package/src/models/transfer/transferFulfilmentDuplicateCheck.js +4 -4
- package/src/models/transfer/transferParticipant.js +3 -3
- package/src/models/transfer/transferStateChange.js +11 -11
- package/src/models/transfer/transferTimeout.js +5 -5
- package/src/schema/bulkTransfer.js +4 -4
- package/src/shared/plugins.js +10 -9
- package/src/shared/setup.js +69 -46
- package/test/integration/domain/participant/index.test.js +2 -0
- package/test/integration/handlers/handlers.test.js +605 -166
- package/test/integration/handlers/root.test.js +1 -1
- package/test/integration/helpers/hubAccounts.js +62 -0
- package/test/integration/helpers/ilpPacket.js +1 -1
- package/test/integration/helpers/participantFundsInOut.js +80 -0
- package/test/integration/helpers/participantLimit.js +6 -1
- package/test/integration/helpers/settlementModels.js +88 -0
- package/test/integration/helpers/testConsumer.js +163 -0
- package/test/integration/helpers/testProducer.js +0 -1
- package/test/integration/helpers/transferDuplicateCheck.js +1 -1
- package/test/integration/helpers/transferStateChange.js +1 -1
- package/test/integration/helpers/transferTestHelper.js +3 -5
- package/test/integration/models/transfer/transferStateChange.test.js +6 -0
- package/test/unit/api/ledgerAccountTypes/handler.test.js +126 -0
- package/test/unit/api/ledgerAccountTypes/routes.test.js +52 -0
- package/test/unit/api/participants/handler.test.js +75 -33
- package/test/unit/api/root/handler.test.js +1 -1
- package/test/unit/api/root/routes.test.js +2 -2
- package/test/unit/api/settlementModels/handler.test.js +21 -57
- package/test/unit/api/transactions/handler.test.js +108 -0
- package/test/unit/api/transactions/routes.test.js +38 -0
- package/test/unit/domain/ledgerAccountTypes/index.test.js +197 -0
- package/test/unit/domain/participant/index.test.js +115 -2
- package/test/unit/domain/settlement/index.test.js +199 -29
- package/test/unit/domain/transactions/index.test.js +128 -0
- package/test/unit/domain/transfer/index.test.js +1 -0
- package/test/unit/domain/transfer/transform.test.js +2 -0
- package/test/unit/handlers/admin/handler.test.js +5 -5
- package/test/unit/handlers/bulk/get/handler.test.js +401 -0
- package/test/unit/handlers/index.test.js +6 -0
- package/test/unit/handlers/positions/handler.test.js +26 -0
- package/test/unit/handlers/register.test.js +2 -0
- package/test/unit/handlers/transfers/handler.test.js +491 -36
- package/test/unit/handlers/transfers/validator.test.js +31 -31
- package/test/unit/lib/cache.test.js +0 -64
- package/test/unit/lib/cachingOfEnums.test.js +121 -0
- package/test/unit/lib/config.test.js +34 -0
- package/test/unit/lib/enum.test.js +6 -1
- package/test/unit/lib/enumCached.test.js +82 -0
- package/test/unit/lib/healthCheck/subServiceHealth.test.js +2 -0
- package/test/unit/lib/requestLogger.test.js +14 -12
- package/test/unit/models/ilpPackets/ilpPacket.test.js +89 -0
- package/test/unit/models/ledgerAccountType/ledgerAccountType.test.js +255 -6
- package/test/unit/models/misc/migrationLock.test.js +4 -0
- package/test/unit/models/misc/segment.test.js +5 -0
- package/test/unit/models/participant/facade.test.js +493 -54
- package/test/unit/models/participant/participant.test.js +4 -0
- package/test/unit/models/participant/participantCurrency.test.js +22 -9
- package/test/unit/models/participant/participantCurrencyCached.test.js +1 -1
- package/test/unit/models/participant/participantLimit.test.js +97 -0
- package/test/unit/models/participant/participantLimitCached.test.js +232 -0
- package/test/unit/models/participant/participantPosition.test.js +217 -0
- package/test/unit/models/participant/participantPositionChange.test.js +3 -0
- package/test/unit/models/position/facade.test.js +318 -29
- package/test/unit/models/position/participantPosition.test.js +22 -7
- package/test/unit/models/settlement/settlementModel.test.js +18 -37
- package/test/unit/models/settlement/settlementModelCached.test.js +171 -0
- package/test/unit/models/transfer/facade.test.js +115 -0
- package/test/unit/models/transfer/ilpPacket.test.js +28 -11
- package/test/unit/models/transfer/transfer.test.js +13 -4
- package/test/unit/models/transfer/transferDuplicateCheck.test.js +4 -0
- package/test/unit/models/transfer/transferError.test.js +5 -1
- package/test/unit/models/transfer/transferErrorDuplicateCheck.test.js +4 -0
- package/test/unit/models/transfer/transferExtension.test.js +26 -9
- package/test/unit/models/transfer/transferFulfilment.test.js +14 -5
- package/test/unit/models/transfer/transferFulfilmentDuplicateCheck.test.js +4 -0
- package/test/unit/models/transfer/transferParticipant.test.js +14 -5
- package/test/unit/models/transfer/transferStateChange.test.js +3 -0
- package/test/unit/models/transfer/transferTimeout.test.js +6 -0
- package/test/unit/seeds/amountType.test.js +6 -22
- package/test/unit/seeds/balanceOfPayments.test.js +6 -22
- package/test/unit/seeds/bulkProcessingState.test.js +84 -0
- package/test/unit/{lib/sidecar/nullClient.test.js → seeds/bulkTransferState.test.js} +36 -39
- package/test/unit/seeds/currency.test.js +6 -22
- package/test/unit/seeds/endpointType.test.js +6 -22
- package/test/unit/seeds/ledgerAccountType.test.js +5 -22
- package/test/unit/seeds/ledgerEntryType.test.js +6 -22
- package/test/unit/seeds/participant.test.js +5 -22
- package/test/unit/seeds/participantLimitType.test.js +6 -22
- package/test/unit/seeds/partyIdentifierType.test.js +6 -22
- package/test/unit/seeds/partyType.test.js +6 -22
- package/test/unit/seeds/settlementState.test.js +5 -22
- package/test/unit/seeds/settlementWindow1State.test.js +5 -22
- package/test/unit/seeds/transactionInitiator.test.js +6 -22
- package/test/unit/seeds/transactionInitiatorType.test.js +6 -22
- package/test/unit/seeds/transactionScenario.test.js +6 -22
- package/test/unit/seeds/transferParticipantRoleType.test.js +6 -22
- package/test/unit/seeds/transferState.test.js +6 -22
- package/test/unit/shared/plugins.test.js +31 -1
- package/test/unit/shared/setup.test.js +25 -36
- package/test/util/helpers.js +37 -2
- package/test/util/randomTransfers.js +1 -1
- package/test/util/scripts/env.sh +6 -5
- package/test/util/scripts/populateTestData.sh +204 -181
- package/test/util/scripts/populateTestDataForLegacySimulator.sh +261 -0
- package/test/util/scripts/restartObjStore.sh +1 -1
- package/test-integration.Dockerfile +15 -15
- package/test.Dockerfile +12 -12
- package/.circleci/_set_up_deploy_envs.sh +0 -47
- package/.dockerignore +0 -17
- package/.ncurc.json +0 -3
- package/server.sh +0 -4
- package/sonar-project.properties +0 -17
- package/src/lib/sidecar/index.js +0 -47
- package/src/lib/sidecar/nullClient.js +0 -18
- package/test/.env +0 -8
- package/test/integration-config.json +0 -367
- package/test/integration-runner.env +0 -31
- package/test/integration-runner.sh +0 -264
- package/test/spec-runner.sh +0 -132
- package/test/unit/lib/sidecar/index.test.js +0 -148
- 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
|
|
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/
|
|
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
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
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
|
|
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
|
}
|