@mojaloop/central-ledger 19.14.0 → 20.1.0
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/.grype.yaml +3 -0
- package/.license-scanner.json +16 -0
- package/.ncurc.yaml +19 -13
- package/.nvmrc +1 -1
- package/.nycrc.yml +14 -2
- package/CHANGELOG.md +51 -0
- package/Dockerfile +13 -10
- package/README.md +39 -89
- package/audit-ci.jsonc +1 -1
- package/config/default.json +60 -3
- package/config/deprecated.default-settlement.json +160 -0
- package/docker/ml-api-adapter/default.json +28 -0
- package/docker-compose.yml +6 -0
- package/nodemon.json +6 -0
- package/package.json +128 -64
- package/{sbom-v19.13.2.csv → sbom-v20.0.0.csv} +886 -736
- package/scripts/_wait4_all.js +5 -5
- package/scripts/transferSettlementTemp/interchangeFeeCalculation.js +51 -0
- package/src/api/index.ts +30 -0
- package/src/api/interface/swagger.json +2249 -2054
- package/src/api/participants/routes.js +1 -1
- package/src/api/root/handler.int.ts +55 -0
- package/src/api/routes.js +7 -6
- package/src/api/server.ts +27 -0
- package/src/api/server.unit.ts +16 -0
- package/src/api/settlementModels/routes.js +4 -4
- package/src/domain/participant/index.d.ts +47 -0
- package/src/domain/participant/index.int.ts +724 -0
- package/src/domain/participant/index.js +4 -5
- package/src/domain/position/fx-prepare.js +1 -1
- package/src/domain/position/fx-timeout-reserved.js +6 -0
- package/src/domain/position/prepare.js +1 -1
- package/src/handlers/admin/handler.js +1 -1
- package/src/handlers/index.js +30 -0
- package/src/handlers/positions/handler.js +0 -2
- package/src/handlers/positions/handlerBatch.js +5 -5
- package/src/handlers/register.js +44 -29
- package/src/handlers/timeouts/handler.js +1 -4
- package/src/handlers/transfers/fx-abort.int.ts +209 -0
- package/src/handlers/transfers/fx-handlers.int.ts +275 -0
- package/src/handlers/transfers/fx-timeout.int.ts +284 -0
- package/src/handlers/transfers/handler.js +1 -3
- package/src/handlers/transfers/handlers.int.ts +538 -0
- package/src/handlers/transfers/prepare.int.ts +1283 -0
- package/src/handlers/transfers/prepare.js +2 -2
- package/src/knexfile.js +19 -0
- package/src/lib/cache.js +1 -1
- package/src/lib/config/index.ts +60 -0
- package/src/lib/config/resolver.ts +231 -0
- package/src/lib/config/resolver.unit.ts +72 -0
- package/src/lib/config/types.ts +372 -0
- package/src/lib/config/util.ts +523 -0
- package/src/lib/config/util.unit.ts +825 -0
- package/src/lib/migrator.js +3 -3
- package/src/lib/proxyCache.js +3 -3
- package/{migrations → src/migrations}/100100_event.js +1 -1
- package/{migrations → src/migrations}/110100_contactType.js +1 -1
- package/{migrations → src/migrations}/110200_currency.js +1 -1
- package/{migrations → src/migrations}/110201_currency-scale.js +1 -1
- package/{migrations → src/migrations}/110300_endpointType.js +1 -1
- package/{migrations → src/migrations}/110400_ledgerEntryType.js +1 -1
- package/{migrations → src/migrations}/110450_ledgerAccountType.js +1 -1
- package/{migrations → src/migrations}/110500_participantLimitType.js +1 -1
- package/{migrations → src/migrations}/110600_transferParticipantRoleType.js +1 -1
- package/{migrations → src/migrations}/110700_transferState.js +1 -1
- package/{migrations → src/migrations}/110900_settlementState.js +1 -1
- package/{migrations → src/migrations}/112000_bulkTransferState.js +1 -1
- package/{migrations → src/migrations}/112100_bulkProcessingState.js +1 -1
- package/{migrations → src/migrations}/200100_participant.js +1 -1
- package/{migrations → src/migrations}/200200_participantContact.js +1 -1
- package/{migrations → src/migrations}/200300_participantEndpoint.js +1 -1
- package/{migrations → src/migrations}/200400_participantParty.js +1 -1
- package/{migrations → src/migrations}/200600_token.js +1 -1
- package/{migrations → src/migrations}/200601_token-indexes.js +1 -1
- package/{migrations → src/migrations}/300100_transferDuplicateCheck.js +2 -2
- package/{migrations → src/migrations}/300150_bulkTransferDuplicateCheck.js +2 -2
- package/{migrations → src/migrations}/300200_transfer.js +2 -2
- package/{migrations → src/migrations}/300202_transfer-decimal184.js +1 -1
- package/{migrations → src/migrations}/300250_bulkTransfer.js +2 -3
- package/{migrations → src/migrations}/300275_bulkTransferAssociation.js +2 -3
- package/{migrations → src/migrations}/300300_ilpPacket.js +1 -1
- package/{migrations → src/migrations}/300400_transferStateChange.js +1 -1
- package/{migrations → src/migrations}/300450_bulkTransferStateChange.js +1 -1
- package/{migrations → src/migrations}/300500_segment.js +1 -1
- package/{migrations → src/migrations}/310100_participantCurrency.js +1 -1
- package/{migrations → src/migrations}/310200_transferParticipant.js +1 -1
- package/{migrations → src/migrations}/310202_transferParticipant-decimal184.js +1 -1
- package/{migrations → src/migrations}/310204_transferParticipant-participantId.js +2 -2
- package/{migrations → src/migrations}/310300_participantPosition.js +1 -1
- package/{migrations → src/migrations}/310302_participantPosition-decimal184.js +1 -1
- package/{migrations → src/migrations}/310400_participantPositionChange.js +1 -1
- package/{migrations → src/migrations}/310402_participantPositionChange-decimal184.js +1 -1
- package/{migrations → src/migrations}/310403_participantPositionChange-participantCurrencyId.js +2 -2
- package/{migrations → src/migrations}/310404_participantPositionChange-change.js +2 -2
- package/{migrations → src/migrations}/310500_participantLimit.js +1 -1
- package/{migrations → src/migrations}/310502_participantLimit-decimal184.js +1 -1
- package/{migrations → src/migrations}/400100_settlementWindow.js +1 -1
- package/{migrations → src/migrations}/400200_settlement.js +1 -1
- package/{migrations → src/migrations}/400300_settlementSettlementWindow.js +1 -1
- package/{migrations → src/migrations}/400301_settlementSettlementWindow-indexes.js +0 -1
- package/{migrations → src/migrations}/400400_settlementWindowStateChange.js +1 -1
- package/{migrations → src/migrations}/400500_settlementTransferParticipant.js +1 -1
- package/{migrations → src/migrations}/400502_settlementTransferParticipant-decimal184.js +1 -1
- package/{migrations → src/migrations}/400600_settlementParticipantCurrency.js +1 -1
- package/{migrations → src/migrations}/400602_settlementParticipantCurrency-decimal184.js +1 -1
- package/{migrations → src/migrations}/400700_settlementParticipantCurrencyStateChange.js +1 -1
- package/{migrations → src/migrations}/400800_settlementStateChange.js +1 -1
- package/{migrations → src/migrations}/400900_settlementWindowContent.js +1 -1
- package/{migrations → src/migrations}/401000_settlementWindowContentStateChange.js +1 -1
- package/{migrations → src/migrations}/401001_settlementWindowContentStateChange-indexes.js +6 -6
- package/{migrations → src/migrations}/401200_settlementContentAggregation.js +1 -1
- package/{migrations → src/migrations}/401300_settlementModel.js +1 -1
- package/{migrations → src/migrations}/410100_transferFulfilmentDuplicateCheck.js +1 -1
- package/{migrations → src/migrations}/410102_transferFulfilmentDuplicateCheck-dropForeignTransferId.js +1 -1
- package/{migrations → src/migrations}/410103_transferFulfilmentDuplicateCheck-hashNullable.js +1 -1
- package/{migrations → src/migrations}/410200_transferFulfilment.js +1 -1
- package/{migrations → src/migrations}/410202_transferFulfilment-ilpFulfilment.js +1 -1
- package/{migrations → src/migrations}/410203_transferFulfilment-foreignTransferFulfilmentId.js +1 -1
- package/{migrations → src/migrations}/410240_bulkTransferFulfilmentDuplicateCheck.js +1 -1
- package/{migrations → src/migrations}/410250_bulkTransferFulfilment.js +1 -1
- package/{migrations → src/migrations}/410300_transferExtension.js +1 -1
- package/{migrations → src/migrations}/410302_transferExtension-transferErrorId.js +1 -1
- package/{migrations → src/migrations}/410350_bulkTransferExtension.js +1 -1
- package/{migrations → src/migrations}/410400_transferTimeout.js +1 -1
- package/{migrations → src/migrations}/410450_transferErrorDuplicateCheck.js +1 -1
- package/{migrations → src/migrations}/410500_transferError.js +1 -1
- package/{migrations → src/migrations}/410502_transferError-foreignTransferErrorDuplicateCheckId.js +1 -1
- package/{migrations → src/migrations}/410550_bulkTransferError.js +1 -1
- package/{migrations → src/migrations}/410600_expiringTransfer.js +1 -1
- package/{migrations → src/migrations}/500401_quote-hotfix-2719.js +8 -8
- package/{migrations → src/migrations}/500501_feature-fixSubIdRef.js +12 -12
- package/{migrations → src/migrations}/500601_party-2480.js +3 -3
- package/{migrations → src/migrations}/501001_quoteExtension-quote-service-174.js +1 -2
- package/{migrations → src/migrations}/501002_quoteExtension-2522.js +3 -3
- package/{migrations → src/migrations}/600010_fxTransferType.js +1 -1
- package/{migrations → src/migrations}/600012_fxParticipantCurrencyType.js +1 -1
- package/{migrations → src/migrations}/600100_fxTransferDuplicateCheck.js +2 -2
- package/{migrations → src/migrations}/600110_fxTransferErrorDuplicateCheck.js.js +1 -1
- package/{migrations → src/migrations}/600200_fxTransfer.js +2 -2
- package/{migrations → src/migrations}/600400_fxTransferStateChange.js +1 -1
- package/{migrations → src/migrations}/600501_fxWatchList.js +2 -2
- package/{migrations → src/migrations}/600600_fxTransferFulfilmentDuplicateCheck.js +1 -1
- package/{migrations → src/migrations}/600700_fxTransferFulfilment.js +1 -1
- package/{migrations → src/migrations}/600800_fxTransferExtension.js +1 -1
- package/{migrations → src/migrations}/601400_fxTransferTimeout.js +1 -1
- package/{migrations → src/migrations}/601500_fxTransferError.js +1 -1
- package/{migrations → src/migrations}/610200_fxTransferParticipant.js +1 -1
- package/{migrations → src/migrations}/610202_fxTransferParticipant-participantId.js +2 -2
- package/{migrations → src/migrations}/610403_participantPositionChange-fxTransfer.js +1 -1
- package/{migrations → src/migrations}/800100_quotePartyView.js +1 -1
- package/{migrations → src/migrations}/800101_feature-fixSubIdRef.js +1 -1
- package/{migrations → src/migrations}/800200_quoteView.js +1 -1
- package/{migrations → src/migrations}/800300_quoteResponseView.js +1 -1
- package/{migrations → src/migrations}/900100_foreign-keys.js +18 -18
- package/{migrations → src/migrations}/900101_foreign-keys.js +6 -6
- package/{migrations → src/migrations}/910100_feature904DDL.js +7 -7
- package/{migrations → src/migrations}/910101_feature904DataMigration.js +1 -1
- package/{migrations → src/migrations}/910102_feature949DataMigration.js +1 -1
- package/{migrations → src/migrations}/910103_feature1093SettlementByCurrency.js +3 -3
- package/{migrations → src/migrations}/940101_quotePartyIdInfoExtension-2522.js +25 -25
- package/{migrations → src/migrations}/950101_transferParticipantStateChange.js +2 -2
- package/{migrations → src/migrations}/950102_settlementModel-adjustPosition.js +2 -2
- package/{migrations → src/migrations}/950103_dropTransferParticipantStateChange.js +3 -3
- package/{migrations → src/migrations}/950104_settlementModel-settlementAccountTypeId.js +3 -3
- package/src/migrations/950107_settlementWindowContent_foreign_settlementModel.js +63 -0
- package/{migrations → src/migrations}/950108_participantProxy.js +1 -2
- package/{migrations → src/migrations}/950120_fxQuoteConversionTerms_sourceAmount_nullable.js +1 -1
- package/{migrations → src/migrations}/960100_create_externalParticipant.js +2 -2
- package/{migrations → src/migrations}/960110_alter_transferParticipant__addFiled_externalParticipantId.js +2 -2
- package/{migrations → src/migrations}/961001_transferForwarded.js +1 -1
- package/{migrations → src/migrations}/961002_fxTransferForwarded.js +1 -1
- package/src/models/participant/externalParticipant.int.ts +85 -0
- package/src/models/participant/facade.js +4 -2
- package/src/models/participant/participantCurrencyCached.js +1 -1
- package/src/models/position/facade.js +8 -2
- package/src/models/transfer/facade.int.ts +139 -0
- package/src/models/transfer/facade.js +8 -3
- package/src/models/transfer/transferDuplicateCheck.js +2 -2
- package/src/models/transfer/transferError.int.ts +112 -0
- package/src/models/transfer/transferExtension.int.ts +137 -0
- package/src/models/transfer/transferStateChange.int.ts +117 -0
- package/{seeds → src/seeds}/participant.js +1 -1
- package/{seeds → src/seeds}/settlementInterchange.js +1 -0
- package/src/settlement/api/handlerRoutes.js +71 -0
- package/src/settlement/api/handlers/health.js +10 -0
- package/src/settlement/api/handlers/index.js +57 -0
- package/src/settlement/api/handlers/settlementWindows/{id}.js +103 -0
- package/src/settlement/api/handlers/settlementWindows.js +77 -0
- package/src/settlement/api/handlers/settlements/{id}.js +133 -0
- package/src/settlement/api/handlers/settlements/{sid}/participants/{pid}/accounts/{aid}.js +127 -0
- package/src/settlement/api/handlers/settlements/{sid}/participants/{pid}.js +127 -0
- package/src/settlement/api/handlers/settlements.js +114 -0
- package/src/settlement/api/openapiRouting.js +87 -0
- package/src/settlement/api/routes.js +176 -0
- package/src/settlement/domain/rules/index.js +46 -0
- package/src/settlement/domain/settlement/index.js +405 -0
- package/src/settlement/domain/settlementWindow/index.js +117 -0
- package/src/settlement/domain/transactions/index.js +83 -0
- package/src/settlement/domain/transferSettlement/index.js +57 -0
- package/src/settlement/handlers/deferredSettlement/handler.js +180 -0
- package/src/settlement/handlers/grossSettlement/handler.js +180 -0
- package/src/settlement/handlers/index.js +101 -0
- package/src/settlement/handlers/register.js +92 -0
- package/src/settlement/handlers/rules/handler.js +164 -0
- package/src/settlement/interface/swagger-handler.json +34 -0
- package/src/settlement/interface/swagger.json +1560 -0
- package/src/settlement/lib/db.js +32 -0
- package/src/settlement/lib/kafka/index.js +41 -0
- package/src/settlement/lib/kafka/producer.js +142 -0
- package/src/settlement/lib/scriptEngine.js +99 -0
- package/src/settlement/lib/scriptsLoader.js +175 -0
- package/src/settlement/lib/utility.js +243 -0
- package/src/settlement/models/ilpPackets/ilpPacket.js +42 -0
- package/src/settlement/models/lib/enums.js +192 -0
- package/src/settlement/models/misc/migrationLock.js +53 -0
- package/src/settlement/models/settlement/facade.js +1652 -0
- package/src/settlement/models/settlement/index.js +55 -0
- package/src/settlement/models/settlement/participantCurrency.js +48 -0
- package/src/settlement/models/settlement/settlement.js +49 -0
- package/src/settlement/models/settlement/settlementModel.js +44 -0
- package/src/settlement/models/settlement/settlementParticipantCurrency.js +61 -0
- package/src/settlement/models/settlement/settlementStateChange.js +44 -0
- package/src/settlement/models/settlement/settlementTransferParticipant.js +46 -0
- package/src/settlement/models/settlementWindow/facade.js +345 -0
- package/src/settlement/models/settlementWindow/index.js +47 -0
- package/src/settlement/models/settlementWindow/settlementWindowStateChange.js +55 -0
- package/src/settlement/models/settlementWindowContent/facade.js +79 -0
- package/src/settlement/models/settlementWindowContent/index.js +40 -0
- package/src/settlement/models/settlementWindowContent/settlementWindowContentStateChange.js +53 -0
- package/src/settlement/models/transferSettlement/facade.js +363 -0
- package/src/settlement/models/transferSettlement/index.js +42 -0
- package/src/settlement/shared/logger/index.js +7 -0
- package/src/settlement/shared/plugins.js +88 -0
- package/src/settlement/shared/setup.js +224 -0
- package/src/settlement/utils/truthyProperty.js +37 -0
- package/src/shared/legacyUtilShim.js +20 -0
- package/src/shared/plugins.js +3 -3
- package/src/shared/results.ts +22 -0
- package/src/shared/results.unit.ts +38 -0
- package/src/shared/setup.js +14 -1
- package/src/testing/api-helpers.ts +1222 -0
- package/src/testing/exec-async.ts +67 -0
- package/src/testing/harness.snapshot.sql +3895 -0
- package/src/testing/harness.test.ts +15 -0
- package/src/testing/harness.ts +1160 -0
- package/src/testing/kafka.ts +221 -0
- package/src/testing/prng.ts +82 -0
- package/src/testing/rdkafka.test.ts +263 -0
- package/src/testing/run.ts +559 -0
- package/src/testing/snapshot.test.ts +92 -0
- package/src/testing/snapshot.ts +549 -0
- package/src/testing/tap-stream.ts +164 -0
- package/src/testing/types.ts +95 -0
- package/src/testing/util.ts +333 -0
- package/src/types/central-services-error-handling.d.ts +72 -0
- package/src/types/central-services-stream.d.ts +148 -0
- package/test-integration.Dockerfile +0 -2
- package/test.Dockerfile +0 -2
- package/tsconfig.json +40 -0
- package/config/knexfile.js +0 -19
- package/migrations/950107_settlementWindowContent_foreign_settlementModel.js +0 -63
- package/src/api/index.js +0 -16
- package/src/lib/config.js +0 -81
- /package/{migrations → src/migrations}/110101_contactType-indexes.js +0 -0
- /package/{migrations → src/migrations}/110301_endpointType-indexes.js +0 -0
- /package/{migrations → src/migrations}/110401_ledgerEntryType-indexes.js +0 -0
- /package/{migrations → src/migrations}/110451_ledgerAccountType-indexes.js +0 -0
- /package/{migrations → src/migrations}/110501_participantLimitType-indexes.js +0 -0
- /package/{migrations → src/migrations}/110601_transferParticipantRoleType-indexes.js +0 -0
- /package/{migrations → src/migrations}/110800_settlementWindowState.js +0 -0
- /package/{migrations → src/migrations}/111000_amountType.js +0 -0
- /package/{migrations → src/migrations}/111001_amountType-indexes.js +0 -0
- /package/{migrations → src/migrations}/111100_balanceOfPayments.js +0 -0
- /package/{migrations → src/migrations}/111101_balanceOfPayments-indexes.js +0 -0
- /package/{migrations → src/migrations}/111200_partyIdentifierType.js +0 -0
- /package/{migrations → src/migrations}/111201_partyIdentifierType-indexes.js +0 -0
- /package/{migrations → src/migrations}/111300_partyType.js +0 -0
- /package/{migrations → src/migrations}/111301_partyType-indexes.js +0 -0
- /package/{migrations → src/migrations}/111400_quoteDuplicateCheck.js +0 -0
- /package/{migrations → src/migrations}/111500_transactionInitiator.js +0 -0
- /package/{migrations → src/migrations}/111501_transactionInitiator-indexes.js +0 -0
- /package/{migrations → src/migrations}/111600_transactionInitiatorType.js +0 -0
- /package/{migrations → src/migrations}/111601_transactionInitiatorType-indexes.js +0 -0
- /package/{migrations → src/migrations}/111700_settlementDelay.js +0 -0
- /package/{migrations → src/migrations}/111701_settlementDelay-indexes.js +0 -0
- /package/{migrations → src/migrations}/111800_settlementInterchange.js +0 -0
- /package/{migrations → src/migrations}/111801_settlementInterchange-indexes.js +0 -0
- /package/{migrations → src/migrations}/111900_settlementGranularity.js +0 -0
- /package/{migrations → src/migrations}/111901_settlementGranularity-indexes.js +0 -0
- /package/{migrations → src/migrations}/112101_bulkProcessingState-indexes.js +0 -0
- /package/{migrations → src/migrations}/200101_participant-indexes.js +0 -0
- /package/{migrations → src/migrations}/200201_participantContact-indexes.js +0 -0
- /package/{migrations → src/migrations}/200301_participantEndpoint-indexes.js +0 -0
- /package/{migrations → src/migrations}/200401_participantParty-indexes.js +0 -0
- /package/{migrations → src/migrations}/300201_transfer-indexes.js +0 -0
- /package/{migrations → src/migrations}/300251_bulkTransfer-indexes.js +0 -0
- /package/{migrations → src/migrations}/300276_bulkTransferAssociation-indexes.js +0 -0
- /package/{migrations → src/migrations}/300401_transferStateChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/300451_bulkTransferStateChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/300501_segment-indexes.js +0 -0
- /package/{migrations → src/migrations}/310101_participantCurrency-indexes.js +0 -0
- /package/{migrations → src/migrations}/310201_transferParticipant-indexes.js +0 -0
- /package/{migrations → src/migrations}/310203_transferParticipant-indexes.js +0 -0
- /package/{migrations → src/migrations}/310301_participantPosition-indexes.js +0 -0
- /package/{migrations → src/migrations}/310401_participantPositionChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/310405_participantPositionChange-positionChange.js +0 -0
- /package/{migrations → src/migrations}/310406_participantPositionChange-positionChange-revert.js +0 -0
- /package/{migrations → src/migrations}/310501_participantLimit-indexes.js +0 -0
- /package/{migrations → src/migrations}/310503_participantLimit-indexes-composite.js +0 -0
- /package/{migrations → src/migrations}/400401_settlmentWindowStateChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/400501_settlementTransferParticipant-indexes.js +0 -0
- /package/{migrations → src/migrations}/400601_settlementParticipantCurrency-indexes.js +0 -0
- /package/{migrations → src/migrations}/400701_settlementParticipantCurrencyStateChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/400801_settlementStateChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/401002_settlementWindowContent-indexes.js +0 -0
- /package/{migrations → src/migrations}/401201_settlementContentAggregation-indexes.js +0 -0
- /package/{migrations → src/migrations}/401301_settlementModel-indexes.js +0 -0
- /package/{migrations → src/migrations}/410101_transferFulfilmentDuplicateCheck-indexes.js +0 -0
- /package/{migrations → src/migrations}/410201_transferFulfilment-indexes.js +0 -0
- /package/{migrations → src/migrations}/410301_transferExtension-indexes.js +0 -0
- /package/{migrations → src/migrations}/410351_bulkTransferExtension-indexes.js +0 -0
- /package/{migrations → src/migrations}/410401_transferTimeout-indexes.js +0 -0
- /package/{migrations → src/migrations}/410501_transferError-indexes.js +0 -0
- /package/{migrations → src/migrations}/410551_bulkTransferError-indexes.js +0 -0
- /package/{migrations → src/migrations}/410601_expiringTransfer-indexes.js +0 -0
- /package/{migrations → src/migrations}/500100_transactionReference.js +0 -0
- /package/{migrations → src/migrations}/500101_transactionReference-indexes.js +0 -0
- /package/{migrations → src/migrations}/500200_transactionScenario.js +0 -0
- /package/{migrations → src/migrations}/500201_transactionScenario-indexes.js +0 -0
- /package/{migrations → src/migrations}/500300_transactionSubScenario.js +0 -0
- /package/{migrations → src/migrations}/500400_quote.js +0 -0
- /package/{migrations → src/migrations}/500500_quoteParty.js +0 -0
- /package/{migrations → src/migrations}/500600_party.js +0 -0
- /package/{migrations → src/migrations}/500700_quoteResponse.js +0 -0
- /package/{migrations → src/migrations}/500800_quoteResponseIlpPacket.js +0 -0
- /package/{migrations → src/migrations}/500900_geoCode.js +0 -0
- /package/{migrations → src/migrations}/501000_quoteExtension.js +0 -0
- /package/{migrations → src/migrations}/501100_quoteResponseDuplicateCheck.js +0 -0
- /package/{migrations → src/migrations}/501200_quoteError.js +0 -0
- /package/{migrations → src/migrations}/501300_transferRules.js +0 -0
- /package/{migrations → src/migrations}/600011_fxTransferType-indexes.js +0 -0
- /package/{migrations → src/migrations}/600013_fxParticipantCurrencyType-indexes.js +0 -0
- /package/{migrations → src/migrations}/600201_fxTransfer-indexes.js +0 -0
- /package/{migrations → src/migrations}/600401_fxTransferStateChange-indexes.js +0 -0
- /package/{migrations → src/migrations}/600502_fxWatchList-indexes.js +0 -0
- /package/{migrations → src/migrations}/600601_fxTransferFulfilmentDuplicateCheck-indexes.js +0 -0
- /package/{migrations → src/migrations}/600701_fxTransferFulfilment-indexes.js +0 -0
- /package/{migrations → src/migrations}/601401_fxTransferTimeout-indexes.js +0 -0
- /package/{migrations → src/migrations}/601501_fxTransferError-indexes.js +0 -0
- /package/{migrations → src/migrations}/610201_fxTransferParticipant-indexes.js +0 -0
- /package/{migrations → src/migrations}/910102_hotfix954.js +0 -0
- /package/{migrations → src/migrations}/940100_quotePartyIdInfoExtension.js +0 -0
- /package/{migrations → src/migrations}/950100_settlementContentAggregation-decimal184.js +0 -0
- /package/{migrations → src/migrations}/950106_unique_settlement_model_ledger_account_currency.js +0 -0
- /package/{migrations → src/migrations}/950109_fxQuote.js +0 -0
- /package/{migrations → src/migrations}/950110_fxQuoteResponse.js +0 -0
- /package/{migrations → src/migrations}/950111_fxQuoteError.js +0 -0
- /package/{migrations → src/migrations}/950113_fxQuoteDuplicateCheck.js +0 -0
- /package/{migrations → src/migrations}/950114_fxQuoteResponseDuplicateCheck.js +0 -0
- /package/{migrations → src/migrations}/950115_fxQuoteConversionTerms.js +0 -0
- /package/{migrations → src/migrations}/950116_fxQuoteConversionTermsExtension.js +0 -0
- /package/{migrations → src/migrations}/950117_fxQuoteResponseConversionTerms.js +0 -0
- /package/{migrations → src/migrations}/950118_fxQuoteResponseConversionTermsExtension.js +0 -0
- /package/{migrations → src/migrations}/950119_fxCharge.js +0 -0
- /package/{migrations → src/migrations}/960111_alter_fxTransferParticipant__addFiled_externalParticipantId.js +0 -0
- /package/{migrations → src/migrations}/960112_fxTransfer-indexes2.js +0 -0
- /package/{migrations → src/migrations}/960113_fxTransferExtension-indexes.js +0 -0
- /package/{migrations → src/migrations}/960114_fxTransferTimeout-indexes2.js +0 -0
- /package/{migrations → src/migrations}/961000_participantEndpoint_unique.js +0 -0
- /package/{migrations → src/migrations}/migration.template +0 -0
- /package/{seeds → src/seeds}/amountType.js +0 -0
- /package/{seeds → src/seeds}/balanceOfPayments.js +0 -0
- /package/{seeds → src/seeds}/bulkProcessingState.js +0 -0
- /package/{seeds → src/seeds}/bulkTransferState.js +0 -0
- /package/{seeds → src/seeds}/currency.js +0 -0
- /package/{seeds → src/seeds}/endpointType.js +0 -0
- /package/{seeds → src/seeds}/fxParticipantCurrencyType.js +0 -0
- /package/{seeds → src/seeds}/fxTransferType.js +0 -0
- /package/{seeds → src/seeds}/ledgerAccountType.js +0 -0
- /package/{seeds → src/seeds}/ledgerEntryType.js +0 -0
- /package/{seeds → src/seeds}/participantLimitType.js +0 -0
- /package/{seeds → src/seeds}/partyIdentifierType.js +0 -0
- /package/{seeds → src/seeds}/partyType.js +0 -0
- /package/{seeds → src/seeds}/settlementDelay.js +0 -0
- /package/{seeds → src/seeds}/settlementGranularity.js +0 -0
- /package/{seeds → src/seeds}/settlementState.js +0 -0
- /package/{seeds → src/seeds}/settlementWindow1State.js +0 -0
- /package/{seeds → src/seeds}/settlementWindow2Open.js +0 -0
- /package/{seeds → src/seeds}/transactionInitiator.js +0 -0
- /package/{seeds → src/seeds}/transactionInitiatorType.js +0 -0
- /package/{seeds → src/seeds}/transactionScenario.js +0 -0
- /package/{seeds → src/seeds}/transferParticipantRoleType.js +0 -0
- /package/{seeds → src/seeds}/transferState.js +0 -0
- /package/{seeds → src/seeds}/z1000_settlementModel-deprecated.js- +0 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
|
23
|
+
- Name Surname <name.surname@mojaloop.io>
|
|
24
|
+
- Shashikant Hirugade <shashi.mojaloop@gmail.com>
|
|
25
|
+
* ModusBox
|
|
26
|
+
- Deon Botha <deon.botha@modusbox.com>
|
|
27
|
+
- Georgi Georgiev <georgi.georgiev@modusbox.com>
|
|
28
|
+
- Miguel de Barros <miguel.debarros@modusbox.com>
|
|
29
|
+
- Rajiv Mothilal <rajiv.mothilal@modusbox.com>
|
|
30
|
+
- Valentin Genev <valentin.genev@modusbox.com>
|
|
31
|
+
--------------
|
|
32
|
+
******/
|
|
33
|
+
'use strict'
|
|
34
|
+
|
|
35
|
+
const arrayDiff = require('lodash').difference
|
|
36
|
+
const SettlementModel = require('../../models/settlement')
|
|
37
|
+
const SettlementModelModel = require('../../models/settlement/settlementModel')
|
|
38
|
+
const SettlementWindowContentModel = require('../../models/settlementWindowContent')
|
|
39
|
+
const SettlementWindowModel = require('../../models/settlementWindow')
|
|
40
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
41
|
+
const { logger } = require('../../shared/logger')
|
|
42
|
+
const MLNumber = require('@mojaloop/ml-number')
|
|
43
|
+
|
|
44
|
+
const prepareParticipantsResult = (participantCurrenciesList) => {
|
|
45
|
+
const participantAccounts = {}
|
|
46
|
+
for (const account of participantCurrenciesList) {
|
|
47
|
+
const { id } = account
|
|
48
|
+
const formattedAccount = {
|
|
49
|
+
id: account.participantCurrencyId,
|
|
50
|
+
state: account.state,
|
|
51
|
+
reason: account.reason,
|
|
52
|
+
netSettlementAmount: {
|
|
53
|
+
amount: new MLNumber(account.netAmount).toNumber(),
|
|
54
|
+
currency: account.currency
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (id in participantAccounts) {
|
|
58
|
+
const accountList = participantAccounts[id].accounts
|
|
59
|
+
accountList.push(formattedAccount)
|
|
60
|
+
participantAccounts[id] = {
|
|
61
|
+
id,
|
|
62
|
+
accounts: accountList
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
participantAccounts[id] = {
|
|
66
|
+
id,
|
|
67
|
+
accounts: [formattedAccount]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return Array.from(Object.keys(participantAccounts).map(participantId => participantAccounts[participantId]))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const groupSettlementWindowContentBySettlementWindow = (records) => {
|
|
75
|
+
const settlementWindows = {}
|
|
76
|
+
for (const record of records) {
|
|
77
|
+
const id = record.settlementWindowId
|
|
78
|
+
delete record.settlementWindowId
|
|
79
|
+
if (id in settlementWindows) {
|
|
80
|
+
settlementWindows[id].push(record)
|
|
81
|
+
} else {
|
|
82
|
+
settlementWindows[id] = [record]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return settlementWindows
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
getById: async function ({ settlementId }, enums) {
|
|
90
|
+
const settlement = await SettlementModel.getById({ settlementId }, enums)
|
|
91
|
+
if (settlement) {
|
|
92
|
+
const settlementWindowsList = await SettlementWindowModel.getBySettlementId({ settlementId }, enums)
|
|
93
|
+
const participantCurrenciesList = await SettlementModel.settlementParticipantCurrency.getParticipantCurrencyBySettlementId({ settlementId }, enums)
|
|
94
|
+
const participants = prepareParticipantsResult(participantCurrenciesList)
|
|
95
|
+
|
|
96
|
+
// Build settlement window content array and insert into settlement window list object
|
|
97
|
+
const windowContentRecords = []
|
|
98
|
+
let windowContentResponseData = {}
|
|
99
|
+
|
|
100
|
+
for (const key of Object.keys(settlementWindowsList)) {
|
|
101
|
+
const windowContentRecord = await SettlementWindowContentModel.getBySettlementAndWindowId(settlementId, settlementWindowsList[key].id)
|
|
102
|
+
windowContentResponseData = {
|
|
103
|
+
id: windowContentRecord[0].id,
|
|
104
|
+
state: windowContentRecord[0].state,
|
|
105
|
+
ledgerAccountType: windowContentRecord[0].ledgerAccountType,
|
|
106
|
+
currencyId: windowContentRecord[0].currencyId,
|
|
107
|
+
createdDate: windowContentRecord[0].createdDate,
|
|
108
|
+
changedDate: windowContentRecord[0].changedDate
|
|
109
|
+
}
|
|
110
|
+
windowContentRecords.push(windowContentResponseData)
|
|
111
|
+
settlementWindowsList[key].content = windowContentRecords
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
id: settlement.settlementId,
|
|
116
|
+
state: settlement.state,
|
|
117
|
+
reason: settlement.reason,
|
|
118
|
+
createdDate: settlement.createdDate,
|
|
119
|
+
changedDate: settlement.changedDate,
|
|
120
|
+
settlementWindows: settlementWindowsList,
|
|
121
|
+
participants
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
125
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
126
|
+
`Settlement with ID '${settlementId}' not found`
|
|
127
|
+
)
|
|
128
|
+
logger.error(error)
|
|
129
|
+
throw error
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
putById: SettlementModel.putById,
|
|
134
|
+
abortById: async function (settlementId, payload, enums) {
|
|
135
|
+
// seq-settlement-6.2.6, step 3
|
|
136
|
+
const settlementData = await SettlementModel.getById({ settlementId })
|
|
137
|
+
|
|
138
|
+
if (!settlementData) {
|
|
139
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
140
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
141
|
+
`Settlement with ID '${settlementId}' not found`
|
|
142
|
+
)
|
|
143
|
+
logger.error(error)
|
|
144
|
+
throw error
|
|
145
|
+
}
|
|
146
|
+
if (settlementData.state === enums.settlementStates.PS_TRANSFERS_COMMITTED ||
|
|
147
|
+
settlementData.state === enums.settlementStates.SETTLING ||
|
|
148
|
+
settlementData.state === enums.settlementStates.SETTLED) {
|
|
149
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
150
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
151
|
+
`State change is not allowed for settlement '${settlementId}' in state '${settlementData.state}'`
|
|
152
|
+
)
|
|
153
|
+
logger.error(error)
|
|
154
|
+
throw error
|
|
155
|
+
} else if (settlementData.state === enums.settlementStates.ABORTED) {
|
|
156
|
+
return SettlementModel.abortByIdStateAborted(settlementId, payload, enums)
|
|
157
|
+
} else if (settlementData.state === enums.settlementStates.PS_TRANSFERS_RESERVED) {
|
|
158
|
+
const transferCommittedAccount = await SettlementModel.getTransferCommitedAccount(settlementId, enums)
|
|
159
|
+
if (transferCommittedAccount !== undefined) {
|
|
160
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
161
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
162
|
+
`At least one settlement transfer is committed for settlement '${settlementId}'. Aborting is not allowed.`
|
|
163
|
+
)
|
|
164
|
+
logger.error(error)
|
|
165
|
+
throw error
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
getSettlementsByParams: async function (params, enums) {
|
|
171
|
+
// 7 filters - at least one should be used
|
|
172
|
+
Object.keys(params.query).forEach(key => params.query[key] === undefined && delete params.query[key])
|
|
173
|
+
if (Object.keys(params.query).length && Object.keys(params.query).length < 10) {
|
|
174
|
+
const settlements = {}
|
|
175
|
+
let settlement
|
|
176
|
+
let participant
|
|
177
|
+
const settlementsData = await SettlementModel.getByParams(params.query, enums)
|
|
178
|
+
if (settlementsData && settlementsData.length > 0) {
|
|
179
|
+
for (const s of settlementsData) {
|
|
180
|
+
if (!settlements[s.settlementId]) {
|
|
181
|
+
const settlementId = s.settlementId
|
|
182
|
+
const settlementWindowsList = await SettlementWindowModel.getBySettlementId({ settlementId })
|
|
183
|
+
for (const key of Object.keys(settlementWindowsList)) {
|
|
184
|
+
settlementWindowsList[key].content = await SettlementWindowContentModel.getBySettlementAndWindowId(s.settlementId, settlementWindowsList[key].id)
|
|
185
|
+
}
|
|
186
|
+
settlements[s.settlementId] = {
|
|
187
|
+
id: s.settlementId,
|
|
188
|
+
state: s.settlementStateId,
|
|
189
|
+
reason: s.settlementWindowReason,
|
|
190
|
+
createdDate: s.createdDate,
|
|
191
|
+
changedDate: s.changedDate,
|
|
192
|
+
settlementWindows: settlementWindowsList
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
settlement = settlements[s.settlementId]
|
|
196
|
+
if (!settlement.settlementWindows) {
|
|
197
|
+
settlement.settlementWindows = {}
|
|
198
|
+
}
|
|
199
|
+
if (!settlement.participants) {
|
|
200
|
+
settlement.participants = {}
|
|
201
|
+
}
|
|
202
|
+
if (!settlement.participants[s.participantId]) {
|
|
203
|
+
settlement.participants[s.participantId] = {
|
|
204
|
+
id: s.participantId
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
participant = settlement.participants[s.participantId]
|
|
208
|
+
if (!participant.accounts) {
|
|
209
|
+
participant.accounts = {}
|
|
210
|
+
}
|
|
211
|
+
participant.accounts[s.participantCurrencyId] = {
|
|
212
|
+
id: s.participantCurrencyId,
|
|
213
|
+
state: s.accountState,
|
|
214
|
+
reason: s.accountReason,
|
|
215
|
+
netSettlementAmount: {
|
|
216
|
+
amount: new MLNumber(s.accountAmount).toNumber(),
|
|
217
|
+
currency: s.accountCurrency
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// transform settlements map to result array
|
|
222
|
+
const result = Object.keys(settlements).map((i) => {
|
|
223
|
+
let settlementWindows = settlements[i].settlementWindows
|
|
224
|
+
settlementWindows = Object.keys(settlementWindows).map((j) => {
|
|
225
|
+
return settlementWindows[j]
|
|
226
|
+
})
|
|
227
|
+
settlements[i].settlementWindows = settlementWindows
|
|
228
|
+
let participants = settlements[i].participants
|
|
229
|
+
participants = Object.keys(participants).map((j) => {
|
|
230
|
+
let accounts = participants[j].accounts
|
|
231
|
+
accounts = Object.keys(accounts).map((k) => {
|
|
232
|
+
return accounts[k]
|
|
233
|
+
})
|
|
234
|
+
participants[j].accounts = accounts
|
|
235
|
+
return participants[j]
|
|
236
|
+
})
|
|
237
|
+
settlements[i].participants = participants
|
|
238
|
+
return settlements[i]
|
|
239
|
+
})
|
|
240
|
+
return result
|
|
241
|
+
} else {
|
|
242
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
243
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
244
|
+
`No settlements found matching the provided parameters: ${JSON.stringify(params.query)}`
|
|
245
|
+
)
|
|
246
|
+
logger.error(error)
|
|
247
|
+
throw error
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, 'Use at least one parameter: state, fromDateTime, toDateTime, currency, settlementWindowId, fromSettlementWindowDateTime, toSettlementWindowDateTime, participantId, accountId')
|
|
251
|
+
logger.error(error)
|
|
252
|
+
throw error
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
settlementEventTrigger: async function (params, enums) {
|
|
257
|
+
// validate settlement model
|
|
258
|
+
const { settlementModel, reason, settlementWindows } = params
|
|
259
|
+
const settlementModelData = await SettlementModelModel.getByName(settlementModel)
|
|
260
|
+
if (!settlementModelData) {
|
|
261
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
262
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
263
|
+
`Settlement model not found: ${settlementModel}`
|
|
264
|
+
)
|
|
265
|
+
logger.error(error)
|
|
266
|
+
throw error
|
|
267
|
+
} else if (settlementModelData.settlementGranularityId === enums.settlementGranularity.GROSS ||
|
|
268
|
+
settlementModelData.settlementDelayId === enums.settlementDelay.IMMEDIATE) {
|
|
269
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, 'Settlement can not be created for GROSS or IMMEDIATE models')
|
|
270
|
+
logger.error(error)
|
|
271
|
+
throw error
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// validate windows content
|
|
275
|
+
const idList = settlementWindows.map(v => v.id)
|
|
276
|
+
const applicableWindows = await SettlementWindowModel.getByListOfIds(idList, settlementModelData, enums.settlementWindowStates)
|
|
277
|
+
const applicableIdList = applicableWindows.map(v => v.settlementWindowId)
|
|
278
|
+
const nonApplicableIdList = arrayDiff(idList, applicableIdList)
|
|
279
|
+
if (nonApplicableIdList.length) {
|
|
280
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, `Inapplicable windows ${nonApplicableIdList.join(', ')}`)
|
|
281
|
+
logger.error(error)
|
|
282
|
+
throw error
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// settlement event trigger
|
|
286
|
+
const settlementId = await SettlementModel.triggerSettlementEvent({ idList, reason }, settlementModelData, enums)
|
|
287
|
+
|
|
288
|
+
// retrieve resulting data for response
|
|
289
|
+
const settlement = await SettlementModel.getById({ settlementId })
|
|
290
|
+
const settlementWindowsList = await SettlementWindowModel.getBySettlementId({ settlementId })
|
|
291
|
+
const settlementWindowContentAll = await SettlementWindowContentModel.getBySettlementId(settlementId)
|
|
292
|
+
const settlementWindowsContent = groupSettlementWindowContentBySettlementWindow(settlementWindowContentAll)
|
|
293
|
+
const settlementWindowsWithContent = settlementWindowsList.map(record => {
|
|
294
|
+
record.content = settlementWindowsContent[record.id]
|
|
295
|
+
return record
|
|
296
|
+
})
|
|
297
|
+
const participantCurrenciesList = await SettlementModel.settlementParticipantCurrency.getParticipantCurrencyBySettlementId({ settlementId })
|
|
298
|
+
const participants = prepareParticipantsResult(participantCurrenciesList)
|
|
299
|
+
return {
|
|
300
|
+
id: settlement.settlementId,
|
|
301
|
+
settlementModel,
|
|
302
|
+
state: settlement.state,
|
|
303
|
+
reason: settlement.reason,
|
|
304
|
+
createdDate: settlement.createdDate,
|
|
305
|
+
changedDate: settlement.changedDate,
|
|
306
|
+
settlementWindows: settlementWindowsWithContent,
|
|
307
|
+
participants
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
getByIdParticipantAccount: async function ({ settlementId, participantId, accountId = null }, enums) {
|
|
312
|
+
let participantFoundInSettlement = false
|
|
313
|
+
const accountProvided = accountId > 0
|
|
314
|
+
let participantAndAccountMatched = !accountProvided
|
|
315
|
+
let accountFoundInSettlement = !accountProvided
|
|
316
|
+
|
|
317
|
+
const settlement = await SettlementModel.getById({ settlementId }, enums) // 3
|
|
318
|
+
const settlementFound = !!settlement
|
|
319
|
+
|
|
320
|
+
let settlementParticipantCurrencyIdList, account, settlementAccount
|
|
321
|
+
|
|
322
|
+
if (settlementFound) {
|
|
323
|
+
settlementParticipantCurrencyIdList = await SettlementModel.settlementParticipantCurrency.getAccountsInSettlementByIds({
|
|
324
|
+
settlementId,
|
|
325
|
+
participantId
|
|
326
|
+
}, enums) // 6
|
|
327
|
+
participantFoundInSettlement = settlementParticipantCurrencyIdList.length > 0
|
|
328
|
+
|
|
329
|
+
if (participantFoundInSettlement && accountProvided) {
|
|
330
|
+
account = await SettlementModel.checkParticipantAccountExists({
|
|
331
|
+
participantId,
|
|
332
|
+
accountId
|
|
333
|
+
}, enums) // 9
|
|
334
|
+
participantAndAccountMatched = !!account
|
|
335
|
+
|
|
336
|
+
if (participantAndAccountMatched) {
|
|
337
|
+
settlementAccount = await SettlementModel.getAccountInSettlement({
|
|
338
|
+
settlementId,
|
|
339
|
+
accountId
|
|
340
|
+
}, enums) // 12
|
|
341
|
+
accountFoundInSettlement = !!settlementAccount
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
let settlementWindows
|
|
347
|
+
let accounts
|
|
348
|
+
let participants
|
|
349
|
+
if (settlementFound && participantFoundInSettlement && participantAndAccountMatched && accountFoundInSettlement) {
|
|
350
|
+
if (accountProvided) { // 16
|
|
351
|
+
settlementWindows = await SettlementModel.settlementSettlementWindow.getWindowsBySettlementIdAndAccountId({
|
|
352
|
+
settlementId,
|
|
353
|
+
accountId
|
|
354
|
+
}, enums)
|
|
355
|
+
accounts = await SettlementModel.settlementParticipantCurrency.getSettlementAccountById(settlementAccount.settlementParticipantCurrencyId, enums)
|
|
356
|
+
participants = prepareParticipantsResult(accounts)
|
|
357
|
+
} else {
|
|
358
|
+
settlementWindows = await SettlementModel.settlementSettlementWindow.getWindowsBySettlementIdAndParticipantId({
|
|
359
|
+
settlementId,
|
|
360
|
+
participantId
|
|
361
|
+
}, enums)
|
|
362
|
+
const ids = settlementParticipantCurrencyIdList.map(record => record.settlementParticipantCurrencyId)
|
|
363
|
+
accounts = await SettlementModel.settlementParticipantCurrency.getSettlementAccountsByListOfIds(ids, enums)
|
|
364
|
+
participants = prepareParticipantsResult(accounts)
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
if (!settlementFound) {
|
|
368
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
369
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
370
|
+
`Settlement with ID '${settlementId}' not found`
|
|
371
|
+
)
|
|
372
|
+
logger.error(error)
|
|
373
|
+
throw error
|
|
374
|
+
} else if (!participantFoundInSettlement) {
|
|
375
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
376
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
377
|
+
`Participant with ID '${participantId}' is not part of settlement '${settlementId}'`
|
|
378
|
+
)
|
|
379
|
+
logger.error(error)
|
|
380
|
+
throw error
|
|
381
|
+
} else if (!participantAndAccountMatched) {
|
|
382
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
383
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
384
|
+
`Provided account ID '${accountId}' does not match any position account for participant '${participantId}' in settlement '${settlementId}'`
|
|
385
|
+
)
|
|
386
|
+
logger.error(error)
|
|
387
|
+
throw error
|
|
388
|
+
} else {
|
|
389
|
+
const error = ErrorHandler.Factory.createFSPIOPError(
|
|
390
|
+
ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR,
|
|
391
|
+
`Account ID '${accountId}' is not part of settlement '${settlementId}'`
|
|
392
|
+
)
|
|
393
|
+
logger.error(error)
|
|
394
|
+
throw error
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
id: settlement.settlementId,
|
|
400
|
+
state: settlement.state,
|
|
401
|
+
settlementWindows,
|
|
402
|
+
participants
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
|
23
|
+
- Name Surname <name.surname@mojaloop.io>
|
|
24
|
+
|
|
25
|
+
* ModusBox
|
|
26
|
+
- Deon Botha <deon.botha@modusbox.com>
|
|
27
|
+
- Georgi Georgiev <georgi.georgiev@modusbox.com>
|
|
28
|
+
- Miguel de Barros <miguel.debarros@modusbox.com>
|
|
29
|
+
- Rajiv Mothilal <rajiv.mothilal@modusbox.com>
|
|
30
|
+
- Valentin Genev <valentin.genev@modusbox.com>
|
|
31
|
+
- Lazola Lucas <lazola.lucas@modusbox.com>
|
|
32
|
+
--------------
|
|
33
|
+
******/
|
|
34
|
+
|
|
35
|
+
const Config = require('../../../lib/config')
|
|
36
|
+
const Enum = require('@mojaloop/central-services-shared').Enum
|
|
37
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
38
|
+
const hasFilters = require('./../../utils/truthyProperty')
|
|
39
|
+
const Producer = require('@mojaloop/central-services-stream').Util.Producer
|
|
40
|
+
const KafkaUtil = require('@mojaloop/central-services-shared').Util.Kafka
|
|
41
|
+
const SettlementWindowModel = require('../../models/settlementWindow')
|
|
42
|
+
const SettlementWindowContentModel = require('../../models/settlementWindowContent')
|
|
43
|
+
const StreamingProtocol = require('@mojaloop/central-services-shared').Util.StreamingProtocol
|
|
44
|
+
const { logger } = require('../../shared/logger')
|
|
45
|
+
const idGenerator = require('@mojaloop/central-services-shared').Util.id
|
|
46
|
+
const generateULID = idGenerator({ type: 'ulid' })
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
getById: async function (params, enums, options) {
|
|
50
|
+
const settlementWindow = await SettlementWindowModel.getById(params)
|
|
51
|
+
|
|
52
|
+
if (settlementWindow) {
|
|
53
|
+
const settlementWindowContent = await SettlementWindowContentModel.getBySettlementWindowId(settlementWindow.settlementWindowId)
|
|
54
|
+
|
|
55
|
+
if (settlementWindowContent) {
|
|
56
|
+
settlementWindow.content = settlementWindowContent
|
|
57
|
+
return settlementWindow
|
|
58
|
+
} else {
|
|
59
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `No records for settlementWidowContentId : ${params.settlementWindowId} found`)
|
|
60
|
+
logger.error(error)
|
|
61
|
+
throw error
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `No record for settlementWindowId: ${params.settlementWindowId} found`)
|
|
65
|
+
logger.error(error)
|
|
66
|
+
throw error
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
getByParams: async function (params, enums) {
|
|
71
|
+
// 4 filters - at least one should be used
|
|
72
|
+
if (hasFilters(params.query) && Object.keys(params.query).length < 6) {
|
|
73
|
+
const settlementWindows = await SettlementWindowModel.getByParams(params, enums)
|
|
74
|
+
if (settlementWindows && settlementWindows.length > 0) {
|
|
75
|
+
for (const settlementWindow of settlementWindows) {
|
|
76
|
+
const settlementWindowContent = await SettlementWindowContentModel.getBySettlementWindowId(settlementWindow.settlementWindowId)
|
|
77
|
+
if (settlementWindowContent) {
|
|
78
|
+
settlementWindow.content = settlementWindowContent
|
|
79
|
+
} else {
|
|
80
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.INTERNAL_SERVER_ERROR, `No records for settlementWidowContentId : ${settlementWindow.settlementWindowId} found`)
|
|
81
|
+
logger.error(error)
|
|
82
|
+
throw error
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return settlementWindows
|
|
86
|
+
} else {
|
|
87
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, `settlementWindow by filters: ${JSON.stringify(params.query).replace(/"/g, '')} not found`)
|
|
88
|
+
logger.error(error)
|
|
89
|
+
throw error
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
const error = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.VALIDATION_ERROR, 'Use at least one parameter: participantId, state, fromDateTime, toDateTime, currency')
|
|
93
|
+
logger.error(error)
|
|
94
|
+
throw error
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
process: async function (params, enums) {
|
|
99
|
+
const settlementWindowId = await SettlementWindowModel.process(params, enums)
|
|
100
|
+
const messageId = generateULID()
|
|
101
|
+
const eventId = generateULID()
|
|
102
|
+
const state = StreamingProtocol.createEventState(Enum.Events.EventStatus.SUCCESS.status, Enum.Events.EventStatus.SUCCESS.code, Enum.Events.EventStatus.SUCCESS.description)
|
|
103
|
+
const event = StreamingProtocol.createEventMetadata(Enum.Events.Event.Type.DEFERRED_SETTLEMENT, Enum.Events.Event.Action.CLOSE, state)
|
|
104
|
+
const metadata = StreamingProtocol.createMetadata(eventId, event)
|
|
105
|
+
const messageProtocol = StreamingProtocol.createMessage(messageId, Config.HUB_NAME, Config.HUB_NAME, metadata, params.headers, params)
|
|
106
|
+
const topicConfig = KafkaUtil.createGeneralTopicConf(Config.KAFKA_CONFIG.TOPIC_TEMPLATES.GENERAL_TOPIC_TEMPLATE.TEMPLATE, Enum.Events.Event.Type.DEFERRED_SETTLEMENT, Enum.Events.Event.Action.CLOSE)
|
|
107
|
+
const kafkaConfig = KafkaUtil.getKafkaConfig(Config.KAFKA_CONFIG, Enum.Kafka.Config.PRODUCER, Enum.Events.Event.Type.DEFERRED_SETTLEMENT.toUpperCase(), Enum.Events.Event.Action.CLOSE.toUpperCase())
|
|
108
|
+
await Producer.produceMessage(messageProtocol, topicConfig, kafkaConfig)
|
|
109
|
+
|
|
110
|
+
return SettlementWindowModel.getById({ settlementWindowId }, enums)
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
close: async function (settlementWindowId, reason) {
|
|
114
|
+
await SettlementWindowModel.close(settlementWindowId, reason)
|
|
115
|
+
return SettlementWindowModel.getById({ settlementWindowId })
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
|
23
|
+
- Name Surname <name.surname@mojaloop.io>
|
|
24
|
+
|
|
25
|
+
* ModusBox
|
|
26
|
+
- Lazola Lucas <lazola.lucas@modusbox.com>
|
|
27
|
+
--------------
|
|
28
|
+
******/
|
|
29
|
+
'use strict'
|
|
30
|
+
|
|
31
|
+
const IlpPacket = require('../../models/ilpPackets/ilpPacket')
|
|
32
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
33
|
+
|
|
34
|
+
const ilpPacket = require('ilp-packet')
|
|
35
|
+
const base64url = require('base64url')
|
|
36
|
+
const { logger } = require('../../shared/logger')
|
|
37
|
+
|
|
38
|
+
const getById = async (id) => {
|
|
39
|
+
try {
|
|
40
|
+
return await IlpPacket.getById(id)
|
|
41
|
+
} catch (err) {
|
|
42
|
+
logger.error(err)
|
|
43
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const decodeIlpPacket = async (inputIlpPacket) => {
|
|
48
|
+
const binaryPacket = Buffer.from(inputIlpPacket, 'base64')
|
|
49
|
+
|
|
50
|
+
// Try ILPv4 first
|
|
51
|
+
try {
|
|
52
|
+
return ilpPacket.deserializeIlpPrepare(binaryPacket)
|
|
53
|
+
} catch (v4Error) {
|
|
54
|
+
logger.debug('Failed to decode as ILPv4, attempting ILPv1')
|
|
55
|
+
// Fall back to ILPv1
|
|
56
|
+
try {
|
|
57
|
+
return ilpPacket.deserializeIlpPayment(binaryPacket)
|
|
58
|
+
} catch (v1Error) {
|
|
59
|
+
logger.error('Failed to decode ILP packet as both v4 and v1', { v4Error, v1Error })
|
|
60
|
+
throw v1Error
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the transaction object in the data field of an Ilp packet
|
|
67
|
+
*
|
|
68
|
+
* @returns {object} - Transaction Object
|
|
69
|
+
*/
|
|
70
|
+
const getTransactionObject = async function (inputIlpPacket) {
|
|
71
|
+
try {
|
|
72
|
+
const jsonPacket = await decodeIlpPacket(inputIlpPacket)
|
|
73
|
+
const decodedData = base64url.decode(jsonPacket.data.toString())
|
|
74
|
+
return JSON.parse(decodedData)
|
|
75
|
+
} catch (err) {
|
|
76
|
+
logger.error(err)
|
|
77
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
module.exports = {
|
|
81
|
+
getById,
|
|
82
|
+
getTransactionObject
|
|
83
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
|
5
|
+
The Mojaloop files are made available by the Mojaloop 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
|
+
Mojaloop Foundation 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
|
+
* Mojaloop Foundation
|
|
23
|
+
- Name Surname <name.surname@mojaloop.io>
|
|
24
|
+
|
|
25
|
+
* ModusBox
|
|
26
|
+
- Deon Botha <deon.botha@modusbox.com>
|
|
27
|
+
- Lazola Lucas <lazola.lucas@modusbox.com>
|
|
28
|
+
- Claudio Viola <claudio.viola@modusbox.com>
|
|
29
|
+
--------------
|
|
30
|
+
******/
|
|
31
|
+
|
|
32
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
33
|
+
const TransferSettlementModel = require('../../models/transferSettlement')
|
|
34
|
+
const { logger } = require('../../shared/logger')
|
|
35
|
+
const Enum = require('@mojaloop/central-services-shared').Enum.Settlements
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
processMsgFulfil: async function (transferEventId, transferEventStateStatus, trx) {
|
|
39
|
+
logger.debug(`transferSettlement::processMsgFulfil(transferEventId=${transferEventId}, transferEventStateStatus=${transferEventStateStatus}) - start`)
|
|
40
|
+
try {
|
|
41
|
+
// Get the 'GROSS' settlement model by transfer
|
|
42
|
+
const grossSettlementModel = await TransferSettlementModel.getSettlementModelByTransferId(transferEventId, Enum.settlementGranularityName.GROSS)
|
|
43
|
+
logger.debug(`transferSettlement::processMsgFulfil - result grossSettlementModel=${JSON.stringify(grossSettlementModel)}`)
|
|
44
|
+
logger.debug(`transferSettlement::processMsgFulfil - grossSettlementModel.length=${grossSettlementModel.length}`)
|
|
45
|
+
if (grossSettlementModel.length > 0) {
|
|
46
|
+
logger.debug(`transferSettlement::processMsgFulfil - updateStateChange(transferEventId=${transferEventId}, transferEventStateStatus=${transferEventStateStatus}) - start`)
|
|
47
|
+
await TransferSettlementModel.updateStateChange(transferEventId, transferEventStateStatus, trx)
|
|
48
|
+
logger.debug('transferSettlement::processMsgFulfil - updateStateChange - end')
|
|
49
|
+
}
|
|
50
|
+
logger.debug('transferSettlement::processMsgFulfil - end')
|
|
51
|
+
return true
|
|
52
|
+
} catch (err) {
|
|
53
|
+
logger.error('transferSettlement::processMsgFulfil - error!', err)
|
|
54
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|