From 4d9d456e2aa4b5ad93031289cfa889c9e599003a Mon Sep 17 00:00:00 2001 From: Jonathan Niles Date: Thu, 3 Jan 2019 18:56:31 +0100 Subject: [PATCH] feat(vouchers): add lookup of hrEntity to API This commit adds the ability to create vouchers with entity_uuids by specifying an hrEntity that is automatically linked via helper functions. Currently, if an hrEntity does not match, the API simply ignores it. In the long run, we might want to block the user if we cannot find a match for the entity specified - this would require flipping to a series of db.one()s or comparing unique array lengths. db.one() would be less efficient (more DB calls), but arguably simpler to read and maintain. --- server/controllers/finance/vouchers.js | 30 +++++++++++++++++++------- test/integration/vouchers.js | 25 +++++++++++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/server/controllers/finance/vouchers.js b/server/controllers/finance/vouchers.js index 245c00afd6..f1d0ae222a 100644 --- a/server/controllers/finance/vouchers.js +++ b/server/controllers/finance/vouchers.js @@ -14,9 +14,9 @@ * @requires lib/errors/BadRequest */ +const _ = require('lodash'); const util = require('../../lib/util'); const db = require('../../lib/db'); - const BadRequest = require('../../lib/errors/BadRequest'); const FilterParser = require('../../lib/filter'); @@ -82,6 +82,7 @@ async function lookupVoucher(vUuid) { JOIN document_map dm ON dm.uuid = v.uuid JOIN project p ON p.id = v.project_id JOIN user u ON u.id = v.user_id + JOIN document_map dm ON dm.uuid = v.uuid LEFT JOIN transaction_type ON v.type_id = transaction_type.id WHERE v.uuid = ?; `; @@ -140,6 +141,7 @@ function find(options) { JOIN document_map dm ON v.uuid = dm.uuid JOIN project p ON p.id = v.project_id JOIN user u ON u.id = v.user_id + LEFT JOIN document_map dm ON v.uuid = dm.uuid LEFT JOIN transaction_type ON v.type_id = transaction_type.id `; @@ -217,7 +219,8 @@ function totalAmountByCurrency(options) { } const sql = ` - SELECT c.id as currencyId, c.symbol as currencySymbol, SUM(v.amount) as totalAmount, COUNT(c.symbol) AS numVouchers + SELECT c.id as currencyId, c.symbol as currencySymbol, SUM(v.amount) as totalAmount, + COUNT(c.symbol) AS numVouchers, dm.text as reference FROM voucher v JOIN document_map dm ON v.uuid = dm.uuid JOIN currency c ON v.currency_id = c.id @@ -264,14 +267,13 @@ function create(req, res, next) { createVoucher(voucher, req.session.user.id, req.session.project.id) .then((result) => res.status(201).json({ uuid : result.uuid })) - .catch(next) - .done(); + .catch(next); } -function createVoucher(voucherDetails, userId, projectId) { +async function createVoucher(voucherDetails, userId, projectId) { const items = voucherDetails.items || []; - const voucherType = voucherDetails.type_id; + const voucherTypeId = voucherDetails.type_id; const updatesPaiementData = []; // a voucher without two items doesn't make any sense in double-entry @@ -298,13 +300,25 @@ function createVoucher(voucherDetails, userId, projectId) { voucherDetails.uuid = db.bid(vuid); const SALARY_PAYMENT_VOUCHER_TYPE_ID = 7; + const referencedEntities = _.uniq(items.map(item => item.hrEntity)); + + let hrEntityMap; + if (referencedEntities.length) { + const hrEntities = await shared.getEntityUuidByTextBulk(referencedEntities); + hrEntityMap = _.keyBy(hrEntities, 'text'); + } // preprocess the items so they have uuids as required items.forEach(value => { let item = value; + // prefer the entity_uuid, and substitute the hrEntity if it exists. + if (hrEntityMap) { + item.entity_uuid = item.entity_uuid || hrEntityMap[item.hrEntity]; + } + // Only for Employee Salary Paiement - if (voucherType === SALARY_PAYMENT_VOUCHER_TYPE_ID) { + if (voucherTypeId === SALARY_PAYMENT_VOUCHER_TYPE_ID) { if (item.document_uuid) { const updatePaiement = ` UPDATE payment SET @@ -358,7 +372,7 @@ function createVoucher(voucherDetails, userId, projectId) { transaction.addQuery('CALL PostVoucher(?);', [voucherDetails.uuid]); // Only for Employee Salary Paiement - if (voucherType === 7) { + if (voucherTypeId === SALARY_PAYMENT_VOUCHER_TYPE_ID) { updatesPaiementData.forEach(updatePaiement => { transaction.addQuery(updatePaiement.query, updatePaiement.params); }); diff --git a/test/integration/vouchers.js b/test/integration/vouchers.js index 6521cb899e..dd69573658 100644 --- a/test/integration/vouchers.js +++ b/test/integration/vouchers.js @@ -45,13 +45,13 @@ describe('test/integration/vouchers The vouchers HTTP endpoint', () => { }], }; - // NOTE: this voucher does not have any uuids + // NOTE: this voucher does not have any uuids and uses hrEntity tags const items = [ { - account_id : 197, debit : 11, credit : 0, document_uuid : genuuid(), entity_uuid : genuuid(), + account_id : 197, debit : 11, credit : 0, document_uuid : genuuid(), hrEntity : 'PA.TPA.1', }, { - account_id : 191, debit : 0, credit : 11, document_uuid : genuuid(), entity_uuid : genuuid(), + account_id : 191, debit : 0, credit : 11, document_uuid : genuuid(), }, { account_id : 197, debit : 0, credit : 12 }, { account_id : 190, debit : 12, credit : 0 }, @@ -64,7 +64,7 @@ describe('test/integration/vouchers The vouchers HTTP endpoint', () => { currency_id : helpers.data.USD, amount : 23, type_id : 2, - description : 'Multiple Voucher Transaction', + description : 'Multiple Voucher Transaction with PA.TPA.1 as entity', user_id : 1, }; @@ -150,11 +150,28 @@ describe('test/integration/vouchers The vouchers HTTP endpoint', () => { .catch(helpers.handler); }); + function filterUniqueValues(row, index, array) { + return array.indexOf(row) === index; + } + it('POST /vouchers create a new voucher record with multiple voucher_items', () => { return agent.post('/vouchers') .send({ voucher : secondVoucher }) .then((res) => { helpers.api.created(res); + + // check that the voucher is linked the entities + return agent.get(`/vouchers/${res.body.uuid}`); + }) + .then(res => { + expect(res.body.items).to.be.a('array'); + + const entityUuids = res.body.items + .map(row => row.entity_uuid) + .filter(filterUniqueValues) + .filter(value => value !== null); + + expect(entityUuids).to.have.length(1); }) .catch(helpers.handler); });