@mojaloop/central-ledger 17.7.8 → 17.8.0-orb.1
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/.ncurc.yaml +3 -1
- package/.nvmrc +1 -1
- package/.nycrc.yml +16 -1
- package/Dockerfile +9 -10
- package/README.md +39 -9
- package/audit-ci.jsonc +15 -2
- package/config/default.json +17 -1
- package/docker/central-ledger/default.json +9 -0
- package/docker/config-modifier/configs/central-ledger.js +25 -0
- package/docker/env.sh +15 -0
- package/docker/kafka/scripts/provision.sh +4 -1
- package/docker/ml-api-adapter/default.json +4 -1
- package/docker-compose.yml +90 -2
- package/documentation/db/erd-transfer-timeout.png +0 -0
- package/documentation/db/erd-transfer-timeout.txt +81 -0
- package/documentation/fx-implementation/README.md +48 -0
- package/documentation/fx-implementation/assets/fx-position-movements.drawio.svg +4 -0
- package/documentation/fx-implementation/assets/test-scenario.drawio.svg +4 -0
- package/documentation/sequence-diagrams/Handler - FX timeout.plantuml +123 -0
- package/documentation/sequence-diagrams/Handler - FX timeout.png +0 -0
- package/documentation/sequence-diagrams/Handler - timeout.plantuml +81 -0
- package/documentation/sequence-diagrams/Handler - timeout.png +0 -0
- package/documentation/state-diagrams/transfer-ML-spec-states-diagram.png +0 -0
- package/documentation/state-diagrams/transfer-internal-states-diagram.png +0 -0
- package/documentation/state-diagrams/transfer-internal-states.plantuml +75 -0
- package/documentation/state-diagrams/transfer-states.plantuml +13 -0
- package/migrations/310204_transferParticipant-participantId.js +52 -0
- package/migrations/310403_participantPositionChange-participantCurrencyId.js +47 -0
- package/migrations/310404_participantPositionChange-change.js +46 -0
- package/migrations/600010_fxTransferType.js +43 -0
- package/migrations/600011_fxTransferType-indexes.js +38 -0
- package/migrations/600012_fxParticipantCurrencyType.js +43 -0
- package/migrations/600013_fxParticipantCurrencyType-indexes.js +38 -0
- package/migrations/600100_fxTransferDuplicateCheck.js +42 -0
- package/migrations/600110_fxTransferErrorDuplicateCheck.js.js +17 -0
- package/migrations/600200_fxTransfer.js +51 -0
- package/migrations/600201_fxTransfer-indexes.js +40 -0
- package/migrations/600400_fxTransferStateChange.js +46 -0
- package/migrations/600401_fxTransferStateChange-indexes.js +40 -0
- package/migrations/600501_fxWatchList.js +46 -0
- package/migrations/600502_fxWatchList-indexes.js +40 -0
- package/migrations/600600_fxTransferFulfilmentDuplicateCheck.js +43 -0
- package/migrations/600601_fxTransferFulfilmentDuplicateCheck-indexes.js +38 -0
- package/migrations/600700_fxTransferFulfilment.js +47 -0
- package/migrations/600701_fxTransferFulfilment-indexes.js +43 -0
- package/migrations/600800_fxTransferExtension.js +47 -0
- package/migrations/601400_fxTransferTimeout.js +43 -0
- package/migrations/601401_fxTransferTimeout-indexes.js +37 -0
- package/migrations/601500_fxTransferError.js +44 -0
- package/migrations/601501_fxTransferError-indexes.js +37 -0
- package/migrations/610200_fxTransferParticipant.js +52 -0
- package/migrations/610201_fxTransferParticipant-indexes.js +44 -0
- package/migrations/610202_fxTransferParticipant-participantId.js +52 -0
- package/migrations/610403_participantPositionChange-fxTransfer.js +46 -0
- package/migrations/910101_feature904DataMigration.js +46 -52
- package/migrations/910102_feature949DataMigration.js +219 -225
- package/migrations/950104_settlementModel-settlementAccountTypeId.js +15 -20
- package/migrations/950108_participantProxy.js +18 -0
- package/migrations/950109_fxQuote.js +19 -0
- package/migrations/950110_fxQuoteResponse.js +25 -0
- package/migrations/950111_fxQuoteError.js +23 -0
- package/migrations/950113_fxQuoteDuplicateCheck.js +18 -0
- package/migrations/950114_fxQuoteResponseDuplicateCheck.js +21 -0
- package/migrations/950115_fxQuoteConversionTerms.js +36 -0
- package/migrations/950116_fxQuoteConversionTermsExtension.js +21 -0
- package/migrations/950117_fxQuoteResponseConversionTerms.js +39 -0
- package/migrations/950118_fxQuoteResponseConversionTermsExtension.js +21 -0
- package/migrations/950119_fxCharge.js +27 -0
- package/migrations/960100_create_externalParticipant.js +47 -0
- package/migrations/960110_alter_transferParticipant__addFiled_externalParticipantId.js +50 -0
- package/migrations/960111_alter_fxTransferParticipant__addFiled_externalParticipantId.js +50 -0
- package/package.json +27 -20
- package/seeds/endpointType.js +18 -0
- package/seeds/fxParticipantCurrencyType.js +45 -0
- package/seeds/fxTransferType.js +45 -0
- package/seeds/participant.js +2 -1
- package/seeds/transferParticipantRoleType.js +9 -0
- package/seeds/transferState.js +10 -0
- package/src/api/interface/swagger.json +23 -30
- package/src/api/participants/handler.js +6 -2
- package/src/api/participants/routes.js +8 -7
- package/src/api/root/handler.js +15 -5
- package/src/domain/fx/cyril.js +466 -0
- package/src/domain/fx/index.js +107 -0
- package/src/domain/participant/index.js +108 -1
- package/src/domain/position/abort.js +215 -0
- package/src/domain/position/binProcessor.js +361 -99
- package/src/domain/position/fulfil.js +252 -111
- package/src/domain/position/fx-fulfil.js +138 -0
- package/src/domain/position/fx-prepare.js +280 -0
- package/src/domain/position/fx-timeout-reserved.js +159 -0
- package/src/domain/position/index.js +1 -0
- package/src/domain/position/prepare.js +69 -49
- package/src/domain/position/timeout-reserved.js +162 -0
- package/src/domain/timeout/index.js +26 -2
- package/src/domain/transfer/index.js +22 -5
- package/src/domain/transfer/transform.js +19 -6
- package/src/handlers/admin/handler.js +0 -2
- package/src/handlers/bulk/fulfil/handler.js +5 -5
- package/src/handlers/bulk/get/handler.js +5 -5
- package/src/handlers/bulk/prepare/handler.js +9 -9
- package/src/handlers/bulk/processing/handler.js +8 -7
- package/src/handlers/bulk/shared/validator.js +1 -1
- package/src/handlers/positions/handler.js +23 -10
- package/src/handlers/positions/handlerBatch.js +54 -26
- package/src/handlers/register.js +2 -1
- package/src/handlers/timeouts/handler.js +212 -68
- package/src/handlers/transfers/FxFulfilService.js +387 -0
- package/src/handlers/transfers/createRemittanceEntity.js +106 -0
- package/src/handlers/transfers/dto.js +53 -0
- package/src/handlers/transfers/handler.js +609 -571
- package/src/handlers/transfers/prepare.js +572 -0
- package/src/handlers/transfers/validator.js +75 -14
- package/src/lib/cache.js +1 -1
- package/src/lib/config.js +6 -3
- package/src/lib/healthCheck/subServiceHealth.js +12 -2
- package/src/lib/proxyCache.js +131 -0
- package/src/models/bulkTransfer/facade.js +58 -82
- package/src/models/fxTransfer/duplicateCheck.js +153 -0
- package/src/models/fxTransfer/fxTransfer.js +578 -0
- package/src/models/fxTransfer/fxTransferError.js +53 -0
- package/src/models/fxTransfer/fxTransferExtension.js +41 -0
- package/src/models/fxTransfer/fxTransferTimeout.js +68 -0
- package/src/models/fxTransfer/index.js +15 -0
- package/src/models/fxTransfer/stateChange.js +47 -0
- package/src/models/fxTransfer/watchList.js +49 -0
- package/src/models/ledgerAccountType/ledgerAccountType.js +8 -32
- package/src/models/misc/segment.js +0 -1
- package/src/models/participant/externalParticipant.js +96 -0
- package/src/models/participant/externalParticipantCached.js +148 -0
- package/src/models/participant/facade.js +192 -123
- package/src/models/participant/participant.js +2 -1
- package/src/models/participant/participantCurrency.js +1 -1
- package/src/models/participant/participantPosition.js +2 -8
- package/src/models/position/batch.js +90 -1
- package/src/models/position/facade.js +5 -5
- package/src/models/position/participantPositionChanges.js +68 -0
- package/src/models/settlement/settlementModel.js +5 -23
- package/src/models/transfer/facade.js +806 -447
- package/src/shared/constants.js +52 -0
- package/src/shared/fspiopErrorFactory.js +131 -0
- package/src/shared/logger/index.js +8 -0
- package/src/shared/loggingPlugin.js +43 -0
- package/src/shared/plugins.js +6 -0
- package/src/shared/setup.js +10 -0
- package/test-integration.Dockerfile +1 -1
- package/test.Dockerfile +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
|
20
|
+
|
|
21
|
+
* Vijaya Kumar Guthi <vijaya.guthi@infitx.com>
|
|
22
|
+
--------------
|
|
23
|
+
******/
|
|
24
|
+
|
|
25
|
+
'use strict'
|
|
26
|
+
|
|
27
|
+
const Db = require('../../lib/db')
|
|
28
|
+
const Logger = require('@mojaloop/central-services-logger')
|
|
29
|
+
const Enum = require('@mojaloop/central-services-shared').Enum
|
|
30
|
+
const TS = Enum.Transfers.TransferInternalState
|
|
31
|
+
|
|
32
|
+
const cleanup = async () => {
|
|
33
|
+
Logger.isDebugEnabled && Logger.debug('cleanup fxTransferTimeout')
|
|
34
|
+
try {
|
|
35
|
+
const knex = await Db.getKnex()
|
|
36
|
+
|
|
37
|
+
const ttIdList = await Db.from('fxTransferTimeout').query(async (builder) => {
|
|
38
|
+
const b = await builder
|
|
39
|
+
.whereIn('tsc.transferStateId', [`${TS.RECEIVED_FULFIL}`, `${TS.COMMITTED}`, `${TS.FAILED}`, `${TS.RESERVED_TIMEOUT}`,
|
|
40
|
+
`${TS.RECEIVED_REJECT}`, `${TS.EXPIRED_PREPARED}`, `${TS.EXPIRED_RESERVED}`, `${TS.ABORTED_REJECTED}`, `${TS.ABORTED_ERROR}`])
|
|
41
|
+
.innerJoin(
|
|
42
|
+
knex('fxTransferTimeout AS tt1')
|
|
43
|
+
.select('tsc1.commitRequestId')
|
|
44
|
+
.max('tsc1.fxTransferStateChangeId AS maxFxTransferStateChangeId')
|
|
45
|
+
.innerJoin('fxTransferStateChange AS tsc1', 'tsc1.commitRequestId', 'tt1.commitRequestId')
|
|
46
|
+
.groupBy('tsc1.commitRequestId').as('ts'), 'ts.commitRequestId', 'fxTransferTimeout.commitRequestId'
|
|
47
|
+
)
|
|
48
|
+
.innerJoin('fxTransferStateChange AS tsc', 'tsc.fxTransferStateChangeId', 'ts.maxFxTransferStateChangeId')
|
|
49
|
+
.select('fxTransferTimeout.fxTransferTimeoutId')
|
|
50
|
+
return b
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
await Db.from('fxTransferTimeout').query(async (builder) => {
|
|
54
|
+
const b = await builder
|
|
55
|
+
.whereIn('fxTransferTimeoutId', ttIdList.map(elem => elem.fxTransferTimeoutId))
|
|
56
|
+
.del()
|
|
57
|
+
return b
|
|
58
|
+
})
|
|
59
|
+
return ttIdList
|
|
60
|
+
} catch (err) {
|
|
61
|
+
Logger.isErrorEnabled && Logger.error(err)
|
|
62
|
+
throw err
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = {
|
|
67
|
+
cleanup
|
|
68
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const duplicateCheck = require('./duplicateCheck')
|
|
2
|
+
const fxTransfer = require('./fxTransfer')
|
|
3
|
+
const stateChange = require('./stateChange')
|
|
4
|
+
const watchList = require('./watchList')
|
|
5
|
+
const fxTransferTimeout = require('./fxTransferTimeout')
|
|
6
|
+
const fxTransferError = require('./fxTransferError')
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
duplicateCheck,
|
|
10
|
+
fxTransfer,
|
|
11
|
+
stateChange,
|
|
12
|
+
watchList,
|
|
13
|
+
fxTransferTimeout,
|
|
14
|
+
fxTransferError
|
|
15
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
2
|
+
const TransferError = require('../../models/transfer/transferError')
|
|
3
|
+
const Db = require('../../lib/db')
|
|
4
|
+
const { TABLE_NAMES } = require('../../shared/constants')
|
|
5
|
+
const { logger } = require('../../shared/logger')
|
|
6
|
+
|
|
7
|
+
const table = TABLE_NAMES.fxTransferStateChange
|
|
8
|
+
|
|
9
|
+
const getByCommitRequestId = async (id) => {
|
|
10
|
+
return await Db.from(table).query(async (builder) => {
|
|
11
|
+
return builder
|
|
12
|
+
.where({ 'fxTransferStateChange.commitRequestId': id })
|
|
13
|
+
.select('fxTransferStateChange.*')
|
|
14
|
+
.orderBy('fxTransferStateChangeId', 'desc')
|
|
15
|
+
.first()
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const logTransferError = async (id, errorCode, errorDescription) => {
|
|
20
|
+
try {
|
|
21
|
+
const stateChange = await getByCommitRequestId(id)
|
|
22
|
+
// todo: check if stateChange is not null
|
|
23
|
+
return TransferError.insert(id, stateChange.fxTransferStateChangeId, errorCode, errorDescription)
|
|
24
|
+
} catch (err) {
|
|
25
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const getLatest = async () => {
|
|
30
|
+
try {
|
|
31
|
+
return await Db.from('fxTransferStateChange').query(async (builder) => {
|
|
32
|
+
return builder
|
|
33
|
+
.select('fxTransferStateChangeId')
|
|
34
|
+
.orderBy('fxTransferStateChangeId', 'desc')
|
|
35
|
+
.first()
|
|
36
|
+
})
|
|
37
|
+
} catch (err) {
|
|
38
|
+
logger.error('getLatest::fxTransferStateChange', err)
|
|
39
|
+
throw err
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
getByCommitRequestId,
|
|
45
|
+
logTransferError,
|
|
46
|
+
getLatest
|
|
47
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
8
|
+
Contributors
|
|
9
|
+
--------------
|
|
10
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
11
|
+
Names of the original copyright holders (individuals or organizations)
|
|
12
|
+
should be listed with a '*' in the first column. People who have
|
|
13
|
+
contributed from an organization can be listed under the organization
|
|
14
|
+
that actually holds the copyright for their contributions (see the
|
|
15
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
16
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
17
|
+
optionally within square brackets <email>.
|
|
18
|
+
* Gates Foundation
|
|
19
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
|
20
|
+
* Vijay Kumar Guthi <vijaya.guthi@infitx.com>
|
|
21
|
+
--------------
|
|
22
|
+
******/
|
|
23
|
+
|
|
24
|
+
'use strict'
|
|
25
|
+
|
|
26
|
+
const Db = require('../../lib/db')
|
|
27
|
+
const { TABLE_NAMES } = require('../../shared/constants')
|
|
28
|
+
const { logger } = require('../../shared/logger')
|
|
29
|
+
|
|
30
|
+
const getItemInWatchListByCommitRequestId = async (commitRequestId) => {
|
|
31
|
+
logger.debug(`get item in watch list (commitRequestId=${commitRequestId})`)
|
|
32
|
+
return Db.from(TABLE_NAMES.fxWatchList).findOne({ commitRequestId })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const getItemsInWatchListByDeterminingTransferId = async (determiningTransferId) => {
|
|
36
|
+
logger.debug(`get item in watch list (determiningTransferId=${determiningTransferId})`)
|
|
37
|
+
return Db.from(TABLE_NAMES.fxWatchList).find({ determiningTransferId })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const addToWatchList = async (record) => {
|
|
41
|
+
logger.debug('add to fx watch list', record)
|
|
42
|
+
return Db.from(TABLE_NAMES.fxWatchList).insert(record)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = {
|
|
46
|
+
getItemInWatchListByCommitRequestId,
|
|
47
|
+
getItemsInWatchListByDeterminingTransferId,
|
|
48
|
+
addToWatchList
|
|
49
|
+
}
|
|
@@ -35,25 +35,19 @@ const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
|
35
35
|
exports.getLedgerAccountByName = async (name, trx = null) => {
|
|
36
36
|
try {
|
|
37
37
|
const knex = Db.getKnex()
|
|
38
|
-
const trxFunction = async (trx
|
|
38
|
+
const trxFunction = async (trx) => {
|
|
39
39
|
try {
|
|
40
40
|
const ledgerAccountType = await knex('ledgerAccountType')
|
|
41
41
|
.select()
|
|
42
42
|
.where('name', name)
|
|
43
43
|
.transacting(trx)
|
|
44
|
-
if (doCommit) {
|
|
45
|
-
await trx.commit
|
|
46
|
-
}
|
|
47
44
|
return ledgerAccountType.length > 0 ? ledgerAccountType[0] : null
|
|
48
45
|
} catch (err) {
|
|
49
|
-
if (doCommit) {
|
|
50
|
-
await trx.rollback
|
|
51
|
-
}
|
|
52
46
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
53
47
|
}
|
|
54
48
|
}
|
|
55
49
|
if (trx) {
|
|
56
|
-
return trxFunction(trx
|
|
50
|
+
return trxFunction(trx)
|
|
57
51
|
} else {
|
|
58
52
|
return knex.transaction(trxFunction)
|
|
59
53
|
}
|
|
@@ -66,25 +60,19 @@ exports.getLedgerAccountByName = async (name, trx = null) => {
|
|
|
66
60
|
exports.getLedgerAccountsByName = async (names, trx = null) => {
|
|
67
61
|
try {
|
|
68
62
|
const knex = Db.getKnex()
|
|
69
|
-
const trxFunction = async (trx
|
|
63
|
+
const trxFunction = async (trx) => {
|
|
70
64
|
try {
|
|
71
65
|
const ledgerAccountTypes = await knex('ledgerAccountType')
|
|
72
66
|
.select('name')
|
|
73
67
|
.whereIn('name', names)
|
|
74
68
|
.transacting(trx)
|
|
75
|
-
if (doCommit) {
|
|
76
|
-
await trx.commit
|
|
77
|
-
}
|
|
78
69
|
return ledgerAccountTypes
|
|
79
70
|
} catch (err) {
|
|
80
|
-
if (doCommit) {
|
|
81
|
-
await trx.rollback
|
|
82
|
-
}
|
|
83
71
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
84
72
|
}
|
|
85
73
|
}
|
|
86
74
|
if (trx) {
|
|
87
|
-
return trxFunction(trx
|
|
75
|
+
return trxFunction(trx)
|
|
88
76
|
} else {
|
|
89
77
|
return knex.transaction(trxFunction)
|
|
90
78
|
}
|
|
@@ -97,7 +85,7 @@ exports.getLedgerAccountsByName = async (names, trx = null) => {
|
|
|
97
85
|
exports.bulkInsert = async (records, trx = null) => {
|
|
98
86
|
try {
|
|
99
87
|
const knex = Db.getKnex()
|
|
100
|
-
const trxFunction = async (trx
|
|
88
|
+
const trxFunction = async (trx) => {
|
|
101
89
|
try {
|
|
102
90
|
await knex('ledgerAccountType')
|
|
103
91
|
.insert(records)
|
|
@@ -107,19 +95,13 @@ exports.bulkInsert = async (records, trx = null) => {
|
|
|
107
95
|
.from('ledgerAccountType')
|
|
108
96
|
.whereIn('name', recordsNames)
|
|
109
97
|
.transacting(trx)
|
|
110
|
-
if (doCommit) {
|
|
111
|
-
await trx.commit
|
|
112
|
-
}
|
|
113
98
|
return createdIds.map(record => record.ledgerAccountTypeId)
|
|
114
99
|
} catch (err) {
|
|
115
|
-
if (doCommit) {
|
|
116
|
-
await trx.rollback
|
|
117
|
-
}
|
|
118
100
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
119
101
|
}
|
|
120
102
|
}
|
|
121
103
|
if (trx) {
|
|
122
|
-
return trxFunction(trx
|
|
104
|
+
return trxFunction(trx)
|
|
123
105
|
} else {
|
|
124
106
|
return knex.transaction(trxFunction)
|
|
125
107
|
}
|
|
@@ -131,7 +113,7 @@ exports.bulkInsert = async (records, trx = null) => {
|
|
|
131
113
|
exports.create = async (name, description, isActive, isSettleable, trx = null) => {
|
|
132
114
|
try {
|
|
133
115
|
const knex = Db.getKnex()
|
|
134
|
-
const trxFunction = async (trx
|
|
116
|
+
const trxFunction = async (trx) => {
|
|
135
117
|
try {
|
|
136
118
|
await knex('ledgerAccountType')
|
|
137
119
|
.insert({
|
|
@@ -145,19 +127,13 @@ exports.create = async (name, description, isActive, isSettleable, trx = null) =
|
|
|
145
127
|
.from('ledgerAccountType')
|
|
146
128
|
.where('name', name)
|
|
147
129
|
.transacting(trx)
|
|
148
|
-
if (doCommit) {
|
|
149
|
-
await trx.commit
|
|
150
|
-
}
|
|
151
130
|
return createdId[0].ledgerAccountTypeId
|
|
152
131
|
} catch (err) {
|
|
153
|
-
if (doCommit) {
|
|
154
|
-
await trx.rollback()
|
|
155
|
-
}
|
|
156
132
|
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
157
133
|
}
|
|
158
134
|
}
|
|
159
135
|
if (trx) {
|
|
160
|
-
return trxFunction(trx
|
|
136
|
+
return trxFunction(trx)
|
|
161
137
|
} else {
|
|
162
138
|
return knex.transaction(trxFunction)
|
|
163
139
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
8
|
+
|
|
9
|
+
Contributors
|
|
10
|
+
--------------
|
|
11
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
12
|
+
Names of the original copyright holders (individuals or organizations)
|
|
13
|
+
should be listed with a '*' in the first column. People who have
|
|
14
|
+
contributed from an organization can be listed under the organization
|
|
15
|
+
that actually holds the copyright for their contributions (see the
|
|
16
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
17
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
18
|
+
optionally within square brackets <email>.
|
|
19
|
+
* Gates Foundation
|
|
20
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
|
21
|
+
|
|
22
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
|
23
|
+
--------------
|
|
24
|
+
**********/
|
|
25
|
+
|
|
26
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
27
|
+
const Db = require('../../lib/db')
|
|
28
|
+
const { logger } = require('../../shared/logger')
|
|
29
|
+
const { TABLE_NAMES, DB_ERROR_CODES } = require('../../shared/constants')
|
|
30
|
+
|
|
31
|
+
const TABLE = TABLE_NAMES.externalParticipant
|
|
32
|
+
const ID_FIELD = 'externalParticipantId'
|
|
33
|
+
|
|
34
|
+
const log = logger.child(`DB#${TABLE}`)
|
|
35
|
+
|
|
36
|
+
const create = async ({ name, proxyId }) => {
|
|
37
|
+
try {
|
|
38
|
+
const result = await Db.from(TABLE).insert({ name, proxyId })
|
|
39
|
+
log.debug('create result:', { result })
|
|
40
|
+
return result
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (err.code === DB_ERROR_CODES.duplicateEntry) {
|
|
43
|
+
log.warn('duplicate entry for externalParticipant. Skip inserting', { name, proxyId })
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
log.error('error in create', err)
|
|
47
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const getAll = async (options = {}) => {
|
|
52
|
+
try {
|
|
53
|
+
const result = await Db.from(TABLE).find({}, options)
|
|
54
|
+
log.debug('getAll result:', { result })
|
|
55
|
+
return result
|
|
56
|
+
} catch (err) /* istanbul ignore next */ {
|
|
57
|
+
log.error('error in getAll:', err)
|
|
58
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const getOneBy = async (criteria, options) => {
|
|
63
|
+
try {
|
|
64
|
+
const result = await Db.from(TABLE).findOne(criteria, options)
|
|
65
|
+
log.debug('getOneBy result:', { criteria, result })
|
|
66
|
+
return result
|
|
67
|
+
} catch (err) /* istanbul ignore next */ {
|
|
68
|
+
log.error('error in getOneBy:', err)
|
|
69
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const getById = async (id, options = {}) => getOneBy({ [ID_FIELD]: id }, options)
|
|
73
|
+
const getByName = async (name, options = {}) => getOneBy({ name }, options)
|
|
74
|
+
|
|
75
|
+
const destroyBy = async (criteria) => {
|
|
76
|
+
try {
|
|
77
|
+
const result = await Db.from(TABLE).destroy(criteria)
|
|
78
|
+
log.debug('destroyBy result:', { criteria, result })
|
|
79
|
+
return result
|
|
80
|
+
} catch (err) /* istanbul ignore next */ {
|
|
81
|
+
log.error('error in destroyBy', err)
|
|
82
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const destroyById = async (id) => destroyBy({ [ID_FIELD]: id })
|
|
86
|
+
const destroyByName = async (name) => destroyBy({ name })
|
|
87
|
+
|
|
88
|
+
// todo: think, if we need update method
|
|
89
|
+
module.exports = {
|
|
90
|
+
create,
|
|
91
|
+
getAll,
|
|
92
|
+
getById,
|
|
93
|
+
getByName,
|
|
94
|
+
destroyById,
|
|
95
|
+
destroyByName
|
|
96
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*****
|
|
2
|
+
License
|
|
3
|
+
--------------
|
|
4
|
+
Copyright © 2017 Bill & Melinda Gates Foundation
|
|
5
|
+
The Mojaloop files are made available by the Bill & Melinda Gates Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
|
8
|
+
|
|
9
|
+
Contributors
|
|
10
|
+
--------------
|
|
11
|
+
This is the official list of the Mojaloop project contributors for this file.
|
|
12
|
+
Names of the original copyright holders (individuals or organizations)
|
|
13
|
+
should be listed with a '*' in the first column. People who have
|
|
14
|
+
contributed from an organization can be listed under the organization
|
|
15
|
+
that actually holds the copyright for their contributions (see the
|
|
16
|
+
Gates Foundation organization for an example). Those individuals should have
|
|
17
|
+
their names indented and be marked with a '-'. Email address can be added
|
|
18
|
+
optionally within square brackets <email>.
|
|
19
|
+
* Gates Foundation
|
|
20
|
+
- Name Surname <name.surname@gatesfoundation.com>
|
|
21
|
+
|
|
22
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
|
23
|
+
--------------
|
|
24
|
+
**********/
|
|
25
|
+
|
|
26
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
|
27
|
+
const Metrics = require('@mojaloop/central-services-metrics')
|
|
28
|
+
const cache = require('../../lib/cache')
|
|
29
|
+
const externalParticipantModel = require('./externalParticipant')
|
|
30
|
+
|
|
31
|
+
let cacheClient
|
|
32
|
+
let epAllCacheKey
|
|
33
|
+
|
|
34
|
+
const buildUnifiedCachedData = (allExternalParticipants) => {
|
|
35
|
+
// build indexes - optimization for byId and byName access
|
|
36
|
+
const indexById = {}
|
|
37
|
+
const indexByName = {}
|
|
38
|
+
|
|
39
|
+
allExternalParticipants.forEach(({ createdDate, ...ep }) => {
|
|
40
|
+
indexById[ep.externalParticipantId] = ep
|
|
41
|
+
indexByName[ep.name] = ep
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// build unified structure - indexes + data
|
|
45
|
+
return {
|
|
46
|
+
indexById,
|
|
47
|
+
indexByName,
|
|
48
|
+
allExternalParticipants
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const getExternalParticipantsCached = async () => {
|
|
53
|
+
const queryName = 'model_getExternalParticipantsCached'
|
|
54
|
+
const histTimer = Metrics.getHistogram(
|
|
55
|
+
'model_externalParticipant',
|
|
56
|
+
`${queryName} - Metrics for externalParticipant model`,
|
|
57
|
+
['success', 'queryName', 'hit']
|
|
58
|
+
).startTimer()
|
|
59
|
+
|
|
60
|
+
let cachedParticipants = cacheClient.get(epAllCacheKey)
|
|
61
|
+
const hit = !!cachedParticipants
|
|
62
|
+
|
|
63
|
+
if (!cachedParticipants) {
|
|
64
|
+
const allParticipants = await externalParticipantModel.getAll()
|
|
65
|
+
cachedParticipants = buildUnifiedCachedData(allParticipants)
|
|
66
|
+
cacheClient.set(epAllCacheKey, cachedParticipants)
|
|
67
|
+
} else {
|
|
68
|
+
// unwrap participants list from catbox structure
|
|
69
|
+
cachedParticipants = cachedParticipants.item
|
|
70
|
+
}
|
|
71
|
+
histTimer({ success: true, queryName, hit })
|
|
72
|
+
|
|
73
|
+
return cachedParticipants
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
Public API
|
|
78
|
+
*/
|
|
79
|
+
const initialize = () => {
|
|
80
|
+
/* Register as cache client */
|
|
81
|
+
const cacheClientMeta = {
|
|
82
|
+
id: 'externalParticipants',
|
|
83
|
+
preloadCache: getExternalParticipantsCached
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
cacheClient = cache.registerCacheClient(cacheClientMeta)
|
|
87
|
+
epAllCacheKey = cacheClient.createKey('all')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const invalidateCache = async () => {
|
|
91
|
+
cacheClient.drop(epAllCacheKey)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const getById = async (id) => {
|
|
95
|
+
try {
|
|
96
|
+
const cachedParticipants = await getExternalParticipantsCached()
|
|
97
|
+
return cachedParticipants.indexById[id]
|
|
98
|
+
} catch (err) /* istanbul ignore next */ {
|
|
99
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const getByName = async (name) => {
|
|
104
|
+
try {
|
|
105
|
+
const cachedParticipants = await getExternalParticipantsCached()
|
|
106
|
+
return cachedParticipants.indexByName[name]
|
|
107
|
+
} catch (err) /* istanbul ignore next */ {
|
|
108
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const getAll = async () => {
|
|
113
|
+
try {
|
|
114
|
+
const cachedParticipants = await getExternalParticipantsCached()
|
|
115
|
+
return cachedParticipants.allExternalParticipants
|
|
116
|
+
} catch (err) /* istanbul ignore next */ {
|
|
117
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const withInvalidate = (theFunctionName) => {
|
|
122
|
+
return async (...args) => {
|
|
123
|
+
try {
|
|
124
|
+
const result = await externalParticipantModel[theFunctionName](...args)
|
|
125
|
+
await invalidateCache()
|
|
126
|
+
return result
|
|
127
|
+
} catch (err) /* istanbul ignore next */ {
|
|
128
|
+
throw ErrorHandler.Factory.reformatFSPIOPError(err)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const create = withInvalidate('create')
|
|
134
|
+
const destroyById = withInvalidate('destroyById')
|
|
135
|
+
const destroyByName = withInvalidate('destroyByName')
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
initialize,
|
|
139
|
+
invalidateCache,
|
|
140
|
+
|
|
141
|
+
getAll,
|
|
142
|
+
getById,
|
|
143
|
+
getByName,
|
|
144
|
+
|
|
145
|
+
create,
|
|
146
|
+
destroyById,
|
|
147
|
+
destroyByName
|
|
148
|
+
}
|