diff --git a/server/config/routes.js b/server/config/routes.js index 8e028c3d3c..00e7a0ee56 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -357,6 +357,7 @@ exports.configure = function (app) { app.post('/sales', patientInvoice.create); app.get('/sales/search', patientInvoice.search); app.get('/sales/:uuid', patientInvoice.details); + app.get('/sales/references/:reference', patientInvoice.reference); // Patients API app.get('/patients', patient.list); diff --git a/server/controllers/finance/patientInvoice.js b/server/controllers/finance/patientInvoice.js index 9086b45b6c..6c562e8a13 100644 --- a/server/controllers/finance/patientInvoice.js +++ b/server/controllers/finance/patientInvoice.js @@ -22,9 +22,14 @@ exports.details = details; /** Write a new patient invoice record and attempt to post it to the journal. */ exports.create = create; -/** Filter the patient table by any column via query strings */ +/** Filter the patient invoice table by any column via query strings */ exports.search = search; +/** + * Retrieves a sale uuid by searching for a human readable reference (e.g. HBB123) + */ +exports.reference = reference; + /** Undo the financial effects of a sale generating an equal and opposite credit note. */ // exports.reverse = reverse; @@ -198,6 +203,8 @@ function linkSaleItems(saleItems, saleUuid) { /** * Searches for a sale by query parameters provided. + * + * GET sales/search */ function search(req, res, next) { 'use strict'; @@ -237,3 +244,34 @@ function search(req, res, next) { .catch(next) .done(); } + +/** + * Searches for a particular sale uuid by reference string. + * + * NOTE - this cannot be combined with the /search route since it would require + * wrapping a MySQL query in an outer query to do the filtering. This would be + * highly inefficient in most cases, or lead to complex code. + * + * GET sales/references/:reference + */ +function reference(req, res, next) { + 'use strict'; + + var sql = + 'SELECT s.uuid FROM (' + + 'SELECT sale.uuid, CONCAT(project.abbr, sale.reference) AS reference ' + + 'FROM sale JOIN project ON sale.project_id = project.id ' + + ')s WHERE s.reference = ?;'; + + db.exec(sql, [ req.params.reference ]) + .then(function (rows) { + if (rows.length === 0) { + throw new req.codes.ERR_NOT_FOUND(); + } + + // references should be unique -- send back only the first result + res.status(200).json(rows[0]); + }) + .catch(next) + .done(); +} diff --git a/server/test/api/patientInvoice.js b/server/test/api/patientInvoice.js index 1aa7a46de8..9c8d4956af 100644 --- a/server/test/api/patientInvoice.js +++ b/server/test/api/patientInvoice.js @@ -51,6 +51,9 @@ describe('The /sales API', function () { /** @const total number of sales in the database */ var NUM_SALES = 2; + + /** @const a reference for one of the sales in the database */ + var REFERENCE = 'TPA1'; /** login before each request */ beforeEach(helpers.login(agent)); @@ -198,6 +201,26 @@ describe('The /sales API', function () { }) .catch(helpers.handler); }); + }); + + describe('(/sales/references) reference interface for the sales table', function () { + it('GET /sales/reference/:reference should return a uuid for a valid sale reference', function () { + return agent.get('/sales/references/'.concat(REFERENCE)) + .then(function (res) { + expect(res).to.have.status(200); + expect(res).to.be.json; + expect(res.body).to.have.property('uuid'); + }) + .catch(helpers.handler); + }); + + it('GET /sales/references/:reference should fail for an invalid sale reference', function () { + return agent.get('/sales/references/unknown') + .then(function (res) { + helpers.api.errored(res, 404); + }) + .catch(helpers.handler); + }); }); });