Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1325: Bulk transfers and bulk quotes support #49

Merged
merged 27 commits into from
Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c6df243
Add support for bulk transfers
oderayi May 13, 2020
3300f32
Add bulkTransfers call from backend to outbound API
oderayi May 13, 2020
c3316df
Add bulk quotes support
oderayi May 14, 2020
06b6df0
WIP: Add bulk transfer model and handler
oderayi May 14, 2020
f00a91b
Fix audit issues
oderayi May 14, 2020
9be4c8e
Make sim, report, and test ports configuraable
oderayi May 14, 2020
ee2d43d
Restore default ports in docker-compose
oderayi May 14, 2020
62faa70
Port config update
oderayi May 14, 2020
579f619
Updates for bulk quotes and bulk transfers
oderayi May 15, 2020
ffb7083
Add POST /bulkQuotes, remove PUT /bulkTransfers/{bulkTransferId}. Fix…
oderayi May 20, 2020
deb9fa9
Update unit test for config.js
oderayi May 21, 2020
59cf29f
Add tests for bulkQuotes model
oderayi May 21, 2020
87c4c4d
Fix audit issues
oderayi May 21, 2020
7138982
Add tests for bulk quotes
oderayi May 22, 2020
184b2fc
Update unit tests for simulator handler
oderayi May 22, 2020
1b88509
Format code
oderayi May 22, 2020
9a1f37d
Update contributors list
oderayi May 22, 2020
0cf5cdf
Fix bug with POST bulkQuotes and tests
oderayi May 22, 2020
9223fba
Update contributors list
oderayi May 22, 2020
a840da1
Update api spec
oderayi May 22, 2020
49fcba6
Add getBulkQuoteById and getBulkTransferById
oderayi May 27, 2020
876f14b
Add unit tests for bulk quotes and bulk transfers handlers
oderayi Jun 3, 2020
77923f0
Resolve audit issues
oderayi Jun 3, 2020
6182ef9
Cleanup
oderayi Jun 3, 2020
8a61c09
Update package.json
oderayi Jun 10, 2020
228ac32
Update src/package.json
oderayi Jun 10, 2020
8e2b514
Fix audit issues
oderayi Jun 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,7 @@ simulator.log
# environments
docker-compose.local.yml
goldenpayerfsp
goldenpayeefsp
goldenpayeefsp

#vscode configs
.vscode/
40 changes: 29 additions & 11 deletions src/audit-resolve.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
{
"1300|nyc>istanbul-reports>handlebars": {
"fix": 1
"decisions": {
"1300|nyc>istanbul-reports>handlebars": {
"madeAt": 0,
"decision": "fix"
},
"1316|nyc>istanbul-reports>handlebars": {
"madeAt": 0,
"decision": "fix"
},
"1324|nyc>istanbul-reports>handlebars": {
"madeAt": 0,
"decision": "fix"
},
"1325|nyc>istanbul-reports>handlebars": {
"madeAt": 0,
"decision": "fix"
},
"1500|npm-audit-resolver>yargs-unparser>yargs>yargs-parser": {
"decision": "ignore",
"madeAt": 1591787086979,
"expiresAt": 1592391879076
},
"1500|npm-audit-resolver>audit-resolve-core>yargs-parser": {
"decision": "ignore",
"madeAt": 1591787090589,
"expiresAt": 1592391879076
}
},
"1316|nyc>istanbul-reports>handlebars": {
"fix": 1
},
"1324|nyc>istanbul-reports>handlebars": {
"fix": 1
},
"1325|nyc>istanbul-reports>handlebars": {
"fix": 1
}
"rules": {},
"version": 1
}
8 changes: 8 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const config = {
key: null,
},
},
ports: {
simulatorApi: 3000,
reportApi: 3002,
testApi: 3003,
},
};


Expand All @@ -70,6 +75,9 @@ const setConfig = async (cfg) => {
readFile(cfg.SERVER_KEY_PATH),
]);
}
config.ports.simulatorApi = cfg.SIMULATOR_API_LISTEN_PORT || config.ports.simulatorApi;
config.ports.reportApi = cfg.REPORT_API_LISTEN_PORT || config.ports.reportApi;
config.ports.testApi = cfg.TEST_API_LISTEN_PORT || config.ports.testApi;
};


Expand Down
9 changes: 6 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

- Name Surname <name.surname@gatesfoundation.com>
* Mowali

* ModusBox <https://modusbox.com>
- Steven Oderayi <steven.oderayi@modusbox.com>
--------------
******/
'use strict';
Expand Down Expand Up @@ -255,9 +258,9 @@ const testApi = new Koa();
// If config specifies TLS, start an HTTPS server; otherwise HTTP
let simServer;
const conf = getConfig();
const simulatorPort = 3000;
const reportPort = 3002;
const testApiPort = 3003;
const simulatorPort = conf.ports.simulatorApi;
const reportPort = conf.ports.reportApi;
const testApiPort = conf.ports.testApi;

if (conf.tls.mutualTLS.enabled || conf.tls.enabled) {
if (!(conf.tls.creds.ca && conf.tls.creds.cert && conf.tls.creds.key)) {
Expand Down
123 changes: 123 additions & 0 deletions src/models/bulkQuote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*****
License
--------------
Copyright © 2020 Bill & Melinda Gates Foundation
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
http://www.apache.org/licenses/LICENSE-2.0
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.
Contributors
--------------
This is the official list of the Mojaloop project contributors for this file.
Names of the original copyright holders (individuals or organizations)
should be listed with a '*' in the first column. People who have
contributed from an organization can be listed under the organization
that actually holds the copyright for their contributions (see the
Gates Foundation organization for an example). Those individuals should have
their names indented and be marked with a '-'. Email address can be added
optionally within square brackets <email>.
* Gates Foundation
- Name Surname <name.surname@gatesfoundation.com>
* ModusBox <https://modusbox.com>
- Steven Oderayi <steven.oderayi@modusbox.com>
--------------
******/
'use strict';

/**
* @file Simulator resources BulkQuote model
* @description Defines the bulk quote model structure and operations within the simulator.
*/
const { bulkQuoteTable } = require('./constants');

// eslint-disable-next-line import/no-unresolved
require('dotenv').config();

/**
* @typedef {Object} BulkQuote
*
* Data model for bulk quotes.
*/
module.exports = class BulkQuote {
constructor(db) {
this.db = db;
}

/**
* Gets a BulkQuote with the provided bulkQuoteId
*
* @async
* @param {String} bulkQuoteId The bulk quote Id.
* @returns {Promise<Object>} BulkQuote object.
*/
async get(bulkQuoteId) {
const res = await this.db.get(`SELECT * FROM ${bulkQuoteTable} WHERE id = ?`, [bulkQuoteId]);
return res;
}

/**
* Creates a bulk quote.
*
* @async
* @param {Object} bulkQuoteRequest The bulk quote request object.
* @returns {Promise<Object>} The BulkQuote response.
*/
async create(bulkQuoteRequest) {
const { bulkQuoteId } = bulkQuoteRequest;
const individualQuoteResults = bulkQuoteRequest.individualQuotes.map((quote) => {
const fee = Math
.floor(Number(quote.amount) * Number(process.env.FEE_MULTIPLIER))
.toString();
return {
quoteId: quote.quoteId,
transactionId: quote.transactionId,
transferAmount: quote.amount,
transferAmountCurrency: quote.currency,
payeeFspFeeAmount: fee,
payeeFspFeeAmountCurrency: quote.currency,
payeeFspCommissionAmount: fee,
payeeFspCommissionAmountCurrency: quote.currency,
};
});
const response = {
bulkQuoteId,
individualQuoteResults,
};
const reqStr = JSON.stringify(bulkQuoteRequest);
const resStr = JSON.stringify(response);
const created = new Date().toISOString().slice(0, 19);

await this.db.get(`INSERT INTO ${bulkQuoteTable} (id, request, response, created) VALUES (?, ?, ?, ?)`,
[bulkQuoteId, reqStr, resStr, created]);

return response;
}

/**
* Updates a bulk quote
*
* @param {String} currentBulkOuoteId The bulk quote id to update.
* @param {Object} newBulkQuoteRequest The new BulkQuote object.
*/
async update(currentBulkOuoteId, newBulkQuoteRequest) {
const response = newBulkQuoteRequest.individualQuotes.map(
(quote) => ({ transferAmount: quote.amount, transferAmountCurrency: quote.currency }),
);
const reqStr = JSON.stringify(newBulkQuoteRequest);
const resStr = JSON.stringify(response);

await this.db.run(`
UPDATE ${bulkQuoteTable}
SET id = ?, request = ?, response = ?
WHERE id = ?`, [newBulkQuoteRequest.bulkQuoteId, reqStr, resStr, currentBulkOuoteId]);
}

/**
* Deletes a BulkQuote.
*
* @async
* @param {String} bulkQuoteId The bulk quote id.
*/
async delete(bulkQuoteId) {
await this.db.run(`DELETE FROM ${bulkQuoteTable} WHERE id = ?`, [bulkQuoteId]);
}
};
100 changes: 100 additions & 0 deletions src/models/bulkTransfer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*****
License
--------------
Copyright © 2020 Bill & Melinda Gates Foundation
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
http://www.apache.org/licenses/LICENSE-2.0
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.
Contributors
--------------
This is the official list of the Mojaloop project contributors for this file.
Names of the original copyright holders (individuals or organizations)
should be listed with a '*' in the first column. People who have
contributed from an organization can be listed under the organization
that actually holds the copyright for their contributions (see the
Gates Foundation organization for an example). Those individuals should have
their names indented and be marked with a '-'. Email address can be added
optionally within square brackets <email>.
* Gates Foundation
- Name Surname <name.surname@gatesfoundation.com>
* ModusBox <https://modusbox.com>
- Steven Oderayi <steven.oderayi@modusbox.com>
--------------
******/
'use strict';

/**
* @file Simulator resources BulkTransfer model
* @description Defines the bulk transfer model structure and operations within the simulator.
*/
const { bulkTransferTable } = require('./constants');
require('dotenv').config();

/**
* @typedef {Object} BulkTransfer
*
* Data model for bulk transfer.
*/
module.exports = class BulkTransfer {
constructor(db) {
this.db = db;
}

/**
* Retrieves a bulk transfer
*
* @async
* @param {String} bulkTransferId The bulk transfer id.
* @returns {Promise<Object>} BulkTransfer object.
*/
async get(bulkTransferId) {
const res = await this.db.get(`SELECT * FROM ${bulkTransferTable} WHERE id = ?`, [bulkTransferId]);
return res;
}

/**
* Creates a bulk transfer.
*
* @async
* @param {Object} bulkTransferRequest The bulk transfer request object.
* @returns {Promise<Object>} BulkTransfer response.
*/
async create(bulkTransferRequest) {
const { bulkTransferId } = bulkTransferRequest;
const response = { bulkTransferId };
const reqStr = JSON.stringify(bulkTransferRequest);
const resStr = JSON.stringify(response);

await this.db.get(`INSERT INTO ${bulkTransferTable} (id, request, response) VALUES (?, ?, ?)`, [bulkTransferId, reqStr, resStr]);

return response;
}

/**
* Updates a bulk transfer
*
* @param {String} bulkTransferId The current bulk transfer id.
* @param {Object} BulkTansferRequest The new BulkTransfer object.
*/
async update(currentBulkTransferId, bulkTransferRequest) {
const { homeTransactionId: newBulkTransferId } = bulkTransferRequest;
const response = { newBulkTransferId };
const reqStr = JSON.stringify(bulkTransferRequest);
const resStr = JSON.stringify(response);

await this.db.run(`
UPDATE ${bulkTransferTable}
SET id = ?, request = ?, response = ?
WHERE id = ?`, [newBulkTransferId, reqStr, resStr, currentBulkTransferId]);
}

/**
* Deletes a bulk transfer.
*
* @async
* @param {String} bulkTransferId The bulk transfer id.
*/
async delete(bulkTransferId) {
await this.db.run(`DELETE FROM ${bulkTransferTable} WHERE id = ?`, [bulkTransferId]);
}
};
31 changes: 28 additions & 3 deletions src/models/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const partyTable = 'party';
const quoteTable = 'quote';
const transactionRequestTable = 'transactionRequest';
const transferTable = 'transfer';
const bulkQuoteTable = 'bulkQuote';
const bulkTransferTable = 'bulkTransfer';
const partyExtensionTable = 'partyExtension';

const createPartyTable = `
Expand Down Expand Up @@ -59,6 +61,16 @@ CREATE TABLE IF NOT EXISTS ${quoteTable} (
)
`;

const createBulkQuoteTable = `
CREATE TABLE IF NOT EXISTS ${bulkQuoteTable} (
id TEXT NOT NULL PRIMARY KEY,
request TEXT,
response TEXT,
created TIMESTAMP
CHECK(id <> '')
)
`;

const createTransactionRequestTable = `
CREATE TABLE IF NOT EXISTS ${transactionRequestTable} (
id TEXT NOT NULL PRIMARY KEY,
Expand All @@ -78,15 +90,28 @@ CREATE TABLE IF NOT EXISTS ${transferTable} (
)
`;

const createBulkTransferTable = `
CREATE TABLE IF NOT EXISTS ${bulkTransferTable} (
id TEXT NOT NULL PRIMARY KEY,
request TEXT,
response TEXT,
CHECK(id <> '')
)
`;

module.exports = {
partyTable,
quoteTable,
bulkQuoteTable,
transferTable,
bulkTransferTable,
transactionRequestTable,
partyExtensionTable,
createPartyTable,
createQuoteTable,
createTransactionRequestTable,
createBulkQuoteTable,
createBulkTransferTable,
createTransferTable,
transferTable,
partyExtensionTable,
createTransactionRequestTable,
createPartyExtensionTable,
};
Loading