From b0ff20180e5af9612043574bca5cd980092ff17d Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Wed, 7 Apr 2021 14:22:53 -0700 Subject: [PATCH] Added Euros and fixed exchange rate selection page. --- client/src/i18n/currency/eur.json | 29 ++++++++ client/src/i18n/en/form.json | 1 + client/src/i18n/fr/form.json | 1 + client/src/js/services/currencyFormat.js | 2 +- .../src/modules/exchange/exchange.modal.html | 7 +- client/src/modules/exchange/exchange.modal.js | 4 + server/config/routes.js | 2 +- server/controllers/finance/exchange.js | 7 +- server/models/bhima.sql | 3 +- server/models/migrations/next/migrate.sql | 11 +++ test/data.sql | 4 +- test/integration/currencies.js | 20 ++++- test/integration/exchange.js | 74 ++++++++++++++++--- 13 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 client/src/i18n/currency/eur.json diff --git a/client/src/i18n/currency/eur.json b/client/src/i18n/currency/eur.json new file mode 100644 index 0000000000..654d444cac --- /dev/null +++ b/client/src/i18n/currency/eur.json @@ -0,0 +1,29 @@ +{ + "CURRENCY_SYM": "€", + "DECIMAL_SEP": ".", + "GROUP_SEP": ",", + "PATTERNS": [ + { + "gSize": 3, + "lgSize": 3, + "maxFrac": 3, + "minFrac": 0, + "minInt": 1, + "negPre": "-", + "negSuf": "", + "posPre": "", + "posSuf": "" + }, + { + "gSize": 3, + "lgSize": 3, + "maxFrac": 2, + "minFrac": 2, + "minInt": 1, + "negPre": "-\u00a4", + "negSuf": "", + "posPre": "\u00a4", + "posSuf": "" + } + ] +} diff --git a/client/src/i18n/en/form.json b/client/src/i18n/en/form.json index 3d45f4dcc0..f1e37cd64f 100644 --- a/client/src/i18n/en/form.json +++ b/client/src/i18n/en/form.json @@ -221,6 +221,7 @@ "PATIENT_INVOICE_FOUND": "Invoice found", "PATIENT_INVOICE_NOT_FOUND": "No invoices found for the patient: {{name}}", "PAYMENT": "Cash Payment", + "PER": "per", "PREVIOUS": "Previous", "RECORD_SAME":"No changes have been made to the form", "REQUISITION": { diff --git a/client/src/i18n/fr/form.json b/client/src/i18n/fr/form.json index 44cf2579c5..6c2bbe6e21 100644 --- a/client/src/i18n/fr/form.json +++ b/client/src/i18n/fr/form.json @@ -221,6 +221,7 @@ "PATIENT_INVOICE_FOUND": "La facture a été trouvée", "PATIENT_INVOICE_NOT_FOUND": "La facture est inexistante pour le patient: {{name}}", "PAYMENT": "Référence du Paiement", + "PER": "par", "PREVIOUS": "Précédent", "RECORD_SAME":"Aucun changement n'a été apporté sur le formulaire", "REQUISITION": { diff --git a/client/src/js/services/currencyFormat.js b/client/src/js/services/currencyFormat.js index edea6b1160..b48400dc6e 100644 --- a/client/src/js/services/currencyFormat.js +++ b/client/src/js/services/currencyFormat.js @@ -37,7 +37,7 @@ function currencyFormat(Currencies, $http, Store) { var formatObject = null; fetchingKeys[key] = true; - $http.get(currencyConfigurationPath.concat(key, '.json')) + $http.get(currencyConfigurationPath.concat(key.toLowerCase(), '.json')) .then(function (response) { // Add configuration to local cache diff --git a/client/src/modules/exchange/exchange.modal.html b/client/src/modules/exchange/exchange.modal.html index 506ef19d1d..098b6e6737 100644 --- a/client/src/modules/exchange/exchange.modal.html +++ b/client/src/modules/exchange/exchange.modal.html @@ -17,13 +17,14 @@ {{ ModalCtrl.format($select.selected.id) }} + repeat="currency as currency in ModalCtrl.currencies | filter:$select.search"> @@ -39,7 +40,9 @@

- EXCHANGE.CURRENT_RATE: {{ ModalCtrl.currentExchangeRate | currency:ModalCtrl.rate.currency.id }} + EXCHANGE.CURRENT_RATE: + {{ ModalCtrl.currentExchangeRate | currency:ModalCtrl.rate.currency.id }} + FORM.INFO.PER {{ModalCtrl.enterprise.currencySymbol}}

{ + vm.currentExchangeRate = Exchange.getCurrentRate(vm.rate.currency.id); + }; + // this turns on and off the currency select input vm.hasMultipleCurrencies = false; diff --git a/server/config/routes.js b/server/config/routes.js index b63068c966..37670e6b19 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -175,7 +175,7 @@ exports.configure = function configure(app) { app.get('/invoices/stats', stats.invoices); // exchange rate modules - app.get('/exchange', exchange.list); + app.get('/exchange/:id?', exchange.list); app.post('/exchange', exchange.create); app.put('/exchange/:id', exchange.update); app.delete('/exchange/:id', exchange.delete); diff --git a/server/controllers/finance/exchange.js b/server/controllers/finance/exchange.js index 5f9906f88f..347ba2a37f 100644 --- a/server/controllers/finance/exchange.js +++ b/server/controllers/finance/exchange.js @@ -38,7 +38,7 @@ function formatExchangeRateForDisplay(value) { */ exports.list = function list(req, res, next) { const { enterprise } = req.session; - const options = req.query; + const options = { ...req.query, ...req.params }; getExchangeRateList(enterprise.id, options) .then(rows => { @@ -60,17 +60,17 @@ function getExchangeRateList(enterpriseId, opts) { const limit = Number(options.limit); const limitQuery = Number.isNaN(limit) ? '' : `LIMIT ${limit}`; + const whereQuery = options.id ? `AND exchange_rate.id = ${options.id}` : ''; const sql = ` SELECT exchange_rate.id, exchange_rate.enterprise_id, exchange_rate.currency_id, exchange_rate.rate, exchange_rate.date, enterprise.currency_id AS 'enterprise_currency_id' FROM exchange_rate JOIN enterprise ON enterprise.id = exchange_rate.enterprise_id - WHERE exchange_rate.enterprise_id = ? + WHERE exchange_rate.enterprise_id = ? ${whereQuery} ORDER BY date DESC ${limitQuery}; `; - return db.exec(sql, [enterpriseId]); } @@ -103,7 +103,6 @@ exports.update = function update(req, res, next) { if (req.body.date) { req.body.date = new Date(req.body.date); } - db.exec(sql, [req.body, req.params.id]) .then(() => { sql = `SELECT diff --git a/server/models/bhima.sql b/server/models/bhima.sql index 5e3f5728a9..640556a110 100644 --- a/server/models/bhima.sql +++ b/server/models/bhima.sql @@ -247,7 +247,8 @@ INSERT INTO `language` VALUES -- Currencies INSERT INTO `currency` (`id`, `name`, `format_key`, `symbol`, `note`, `min_monentary_unit`) VALUES (1,'Congolese Francs','fc','Fc',NULL,50.00), - (2,'United States Dollars','usd','$',NULL,0.01); + (2,'United States Dollars','usd','$',NULL,0.01), + (3,'Euro','EUR','€',NULL,0.01); INSERT INTO `inventory_type` VALUES (1,'Article'),(2,'Assembly'),(3,'Service'); INSERT INTO `inventory_unit` VALUES diff --git a/server/models/migrations/next/migrate.sql b/server/models/migrations/next/migrate.sql index 6bcd33c4f8..d706d41e58 100644 --- a/server/models/migrations/next/migrate.sql +++ b/server/models/migrations/next/migrate.sql @@ -33,3 +33,14 @@ CALL drop_column_if_exists('lots', 'initial_quantity'); CALL drop_column_if_exists('lots', 'quantity'); CALL drop_column_if_exists('lots', 'entry_date'); +/** + * @author: jmcameron + * @date: 2021-04-08 + * @desc: Add support for Euros + */ +INSERT IGNORE INTO `currency` (`id`, `name`, `format_key`, `symbol`, `note`, `min_monentary_unit`) +VALUES + (3,'Euro','EUR','€',NULL,0.01); +INSERT IGNORE INTO `exchange_rate` +VALUES + (3, 1, @EUR, 0.84, NOW()); diff --git a/test/data.sql b/test/data.sql index 47b28582ad..9959c65a69 100644 --- a/test/data.sql +++ b/test/data.sql @@ -373,11 +373,13 @@ INSERT INTO `project_permission` VALUES (1, 1, 1),(2, 1, 2),(3, 2, 1),(4, 4, 1); SET @USD = 1; SET @FC = 2; +SET @EUR = 3; -- exchange rate for the current date INSERT INTO `exchange_rate` VALUES (1, 1, @USD, 900.0000, DATE('2016-01-01')), - (2, 1, @USD, 930.0000, NOW()); + (2, 1, @USD, 930.0000, NOW()), + (3, 1, @EUR, 0.8400, NOW()); INSERT INTO `cash_box` (id, label, project_id, is_auxiliary) VALUES (1, 'Caisse Principale', 1, 0), diff --git a/test/integration/currencies.js b/test/integration/currencies.js index ae7ab39153..717b522455 100644 --- a/test/integration/currencies.js +++ b/test/integration/currencies.js @@ -4,7 +4,8 @@ const helpers = require('./helpers'); describe('(/currencies) currencies API routes', () => { - const currencyId = 1; + const currencyIdFc = 1; + const currencyIdEur = 3; const keys = [ 'id', 'name', 'note', 'format_key', 'symbol', 'min_monentary_unit', ]; @@ -12,21 +13,32 @@ describe('(/currencies) currencies API routes', () => { it('GET /currencies should return a list of currencies', () => { return agent.get('/currencies') .then((res) => { - helpers.api.listed(res, 2); + helpers.api.listed(res, 3); }) .catch(helpers.handler); }); - it('GET /currencies/:id should return a single currency', () => { - return agent.get('/currencies/'.concat(currencyId)) + it('GET /currencies/:id should return a single currency for Fc', () => { + return agent.get('/currencies/'.concat(currencyIdFc)) .then((res) => { expect(res).to.have.status(200); expect(res).to.be.json; expect(res.body).to.have.keys(keys); + expect(res.body.name).to.equal('Congolese Francs'); }) .catch(helpers.handler); }); + it('GET /currencies/:id should return a single currency for EUR', () => { + return agent.get('/currencies/'.concat(currencyIdEur)) + .then((res) => { + expect(res).to.have.status(200); + expect(res).to.be.json; + expect(res.body).to.have.keys(keys); + expect(res.body.name).to.equal('Euro'); + }) + .catch(helpers.handler); + }); it('GET /currencies/:id should return an error for unknown id', () => { return agent.get('/currencies/123456789') .then((res) => { diff --git a/test/integration/exchange.js b/test/integration/exchange.js index 4c31a1d0e2..bc60633138 100644 --- a/test/integration/exchange.js +++ b/test/integration/exchange.js @@ -9,13 +9,20 @@ const helpers = require('./helpers'); describe('(/exchange) The /exchange API endpoint', () => { // constants - const RATE = { + const FcRATE = { enterprise_id : 1, // Enterprise ID currency_id : 1, // FC in test database rate : 930, date : new Date('2015-10-10'), }; + const EuroRATE = { + enterprise_id : 1, // Enterprise ID + currency_id : 3, // Euro in test database + rate : 0.84, + date : new Date('2021-04-08'), + }; + const RATE_KEY = [ 'id', 'enterprise_id', 'currency_id', 'enterprise_currency_id', 'rate', 'date', ]; @@ -23,7 +30,7 @@ describe('(/exchange) The /exchange API endpoint', () => { it('GET /exchange returns a list of exchange rates', () => { return agent.get('/exchange') .then((res) => { - helpers.api.listed(res, 2); + helpers.api.listed(res, 3); }) .catch(helpers.handler); }); @@ -38,15 +45,15 @@ describe('(/exchange) The /exchange API endpoint', () => { .catch(helpers.handler); }); - it('POST /exchange creates a new exchange rate', () => { + it('POST /exchange creates a new exchange rate for Fc', () => { return agent.post('/exchange') - .send({ rate : RATE }) + .send({ rate : FcRATE }) .then((res) => { // make sure the API conforms to app standards helpers.api.created(res); - RATE.id = res.body.id; + FcRATE.id = res.body.id; return agent.get('/exchange'); }) .then((res) => { @@ -59,13 +66,62 @@ describe('(/exchange) The /exchange API endpoint', () => { .catch(helpers.handler); }); - it('PUT /exchange should update an existing exchange rate', () => { - return agent.put(`/exchange/${RATE.id}`) + it('PUT /exchange should update an existing exchange rate for Fc', () => { + return agent.put(`/exchange/${FcRATE.id}`) .send({ rate : 925 }) .then((res) => { expect(res).to.have.status(200); expect(res.body).to.have.keys(RATE_KEY); - expect(res.body.rate).to.not.equal(RATE.rate); + expect(res.body.rate).to.not.equal(FcRATE.rate); + }) + .catch(helpers.handler); + }); + + it('POST /exchange creates a new exchange rate for Euros', () => { + return agent.post('/exchange') + .send({ rate : EuroRATE }) + .then((res) => { + + // make sure the API conforms to app standards + helpers.api.created(res); + + EuroRATE.id = res.body.id; + return agent.get('/exchange'); + }) + .then((res) => { + expect(res).to.have.status(200); + expect(res).to.be.json; + expect(res.body).to.not.be.empty; + expect(res.body[0]).to.not.be.empty; + expect(res.body[0]).to.contain.keys('currency_id', 'date', 'rate'); + }) + .catch(helpers.handler); + }); + + it('PUT /exchange should update an existing exchange rate for Euros', () => { + return agent.put(`/exchange/${EuroRATE.id}`) + .send({ rate : 0.86 }) + .then((res) => { + expect(res).to.have.status(200); + expect(res.body).to.have.keys(RATE_KEY); + expect(res.body.rate).to.not.equal(EuroRATE.rate); + }) + .catch(helpers.handler); + }); + + it('GET /exchange returns a list of the updated exchange rates', () => { + return agent.get('/exchange') + .then((res) => { + helpers.api.listed(res, 5); + }) + .catch(helpers.handler); + }); + + it('GET /exchange/id get updated exchange rate for Euros', () => { + return agent.get(`/exchange/${EuroRATE.id}`) + .then((res) => { + helpers.api.listed(res, 1); + expect(res.body[0].rate).to.equal(0.86); }) .catch(helpers.handler); }); @@ -111,7 +167,7 @@ describe('(/exchange) The /exchange API endpoint', () => { }); it('DELETE /exchange/:id should delete an exchange rate ', () => { - return agent.delete(`/exchange/${RATE.id}`) + return agent.delete(`/exchange/${FcRATE.id}`) .then((res) => { helpers.api.deleted(res); })