Skip to content

Commit

Permalink
merge patients tool
Browse files Browse the repository at this point in the history
  • Loading branch information
mbayopanda committed May 28, 2019
1 parent 5dc2a0b commit a6ca2de
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 83 deletions.
2 changes: 1 addition & 1 deletion .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ PORT=8080
DB_HOST='localhost'
DB_USER='bhima'
DB_PASS='HISCongo2013'
DB_NAME='imck'
DB_NAME='bhima_test'

# session variables
SESS_SECRET='XopEn BlowFISH'
Expand Down
3 changes: 2 additions & 1 deletion client/src/i18n/en/patient_registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"YEAR_OLD":"year old",
"YEARS_OLD":"years old",
"TITLE":"Patient Registry",
"RECORD":"Record"
"RECORD":"Record",
"MERGE_SUCCESS":"Patiens fusionnés avec succès"
}
}
3 changes: 2 additions & 1 deletion client/src/i18n/fr/patient_registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"RECORD":"Enregistrement",
"YEAR_OLD":"an",
"YEARS_OLD":"ans",
"TITLE":"Registre des Patients"
"TITLE":"Registre des Patients",
"MERGE_SUCCESS":"Patiens fusionnés avec succès"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ angular.module('bhima.controllers')
.controller('MergePatientsModalController', MergePatientsModalController);

MergePatientsModalController.$inject = [
'PatientService', '$state', 'NotifyService',
'PatientService', '$state', 'NotifyService', '$uibModalInstance',
];

function MergePatientsModalController(Patients, $state, Notify) {
function MergePatientsModalController(Patients, $state, Notify, Instance) {
const vm = this;

vm.patients = $state.params.patients;
Expand All @@ -18,12 +18,14 @@ function MergePatientsModalController(Patients, $state, Notify) {
function submit() {
const params = {
selected : vm.selected,
other : vm.patients.filter(p => p.uuid === vm.selected).map(p => p.uuid),
other : vm.patients.filter(p => p.uuid !== vm.selected).map(p => p.uuid),
};

return Patients.merge(params)
.then(res => {
console.log(res);
.then(() => {
Notify.success('PATIENT_REGISTRY.MERGE_SUCCESS');
Instance.close();
$state.go('patientRegistry', null, { reload : true });
})
.catch(Notify.handleError);
}
Expand Down
53 changes: 27 additions & 26 deletions server/controllers/medical/patients/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
* one patient.
*
* The merge consists to :
* - get debtor_uuids of the selected patients and others
* - get debtor_uuids of the selected patient (patient to keep) and others patients (patients to remove)
* - replace all occurences of debtor_uuid of patient to remove by the debtor_uuid
* of the selected patient in journal and general ledger
* - remove the not selected patient
* - recalculate period total
* of the selected patient (patient to keep) in journal and general ledger
* cash, debtor_group_history, invoice, patient, employee, patient_assignment,
* patient_document, patient_hospitalization, patient_visit
* - remove the patient to remove
* - remove the debtor relate to patient to remove
*/
const db = require('../../../lib/db');

Expand All @@ -17,11 +19,11 @@ function mergePatients(req, res, next) {
const params = req.body;
const glb = {};

const selectedUuid = db.bid(params.selected);
const otherUuids = params.other.map(uuid => db.bid(uuid));
const selectedPatientUuid = db.bid(params.selected);
const otherPatientUuids = params.other.map(uuid => db.bid(uuid));

const getSelectedDebtorUuid = `SELECT debtor_uuid FROM patient WHERE uuid = ?`;
const getOtherDebtorUuid = `SELECT debtor_uuid FROM patient WHERE uuid IN (?)`;
const getOtherDebtorUuids = `SELECT debtor_uuid FROM patient WHERE uuid IN (?)`;

const replaceDebtorInJournal = `
UPDATE posting_journal SET entity_uuid = ? WHERE entity_uuid IN (?);
Expand All @@ -48,7 +50,7 @@ function mergePatients(req, res, next) {
UPDATE patient_assignment SET patient_uuid = ? WHERE patient_uuid IN (?);
`;
const replacePatientInPatientDocument = `
UPDATE patient_assignment SET patient_uuid = ? WHERE patient_uuid IN (?);
UPDATE patient_document SET patient_uuid = ? WHERE patient_uuid IN (?);
`;
const replacePatientInPatientHospitalization = `
UPDATE patient_hospitalization SET patient_uuid = ? WHERE patient_uuid IN (?);
Expand All @@ -64,38 +66,37 @@ function mergePatients(req, res, next) {
DELETE FROM patient WHERE uuid IN (?);
`;

db.one(getSelectedDebtorUuid, [selectedUuid])
db.one(getSelectedDebtorUuid, [selectedPatientUuid])
.then(row => {
glb.selectedDebtorUuid = row.debtor_uuid;
return db.exec(getOtherDebtorUuid, otherUuids);
return db.exec(getOtherDebtorUuids, otherPatientUuids);
})
.then(rows => {
glb.otherDebtorUuids = rows.map(row => row.debtor_uuid);

const transaction = db.transaction();
console.log('>>>', glb.selectedDebtorUuid, glb.otherDebtorUuids);
transaction.addQuery(replaceDebtorInJournal, [glb.selectedDebtorUuid, glb.otherDebtorUuids]);
transaction.addQuery(replaceDebtorInLedger, [glb.selectedDebtorUuid, glb.otherDebtorUuids]);

transaction.addQuery(replaceDebtorInCash, [glb.selectedDebtorUuid, glb.otherDebtorUuids]);
transaction.addQuery(replaceDebtorInDebtorGroupHistory, [glb.selectedDebtorUuid, glb.otherDebtorUuids]);
transaction.addQuery(replaceDebtorInInvoice, [glb.selectedDebtorUuid, glb.otherDebtorUuids]);
transaction.addQuery(replaceDebtorInPatient, [glb.selectedDebtorUuid, glb.otherDebtorUuids]);
transaction.addQuery(replaceDebtorInJournal, [glb.selectedDebtorUuid, [glb.otherDebtorUuids]]);
transaction.addQuery(replaceDebtorInLedger, [glb.selectedDebtorUuid, [glb.otherDebtorUuids]]);

transaction.addQuery(replaceDebtorInCash, [glb.selectedDebtorUuid, [glb.otherDebtorUuids]]);
transaction.addQuery(replaceDebtorInDebtorGroupHistory, [glb.selectedDebtorUuid, [glb.otherDebtorUuids]]);
transaction.addQuery(replaceDebtorInInvoice, [glb.selectedDebtorUuid, [glb.otherDebtorUuids]]);
transaction.addQuery(replaceDebtorInPatient, [glb.selectedDebtorUuid, [glb.otherDebtorUuids]]);

transaction.addQuery(replacePatientInEmployee, [selectedUuid, otherUuids]);
transaction.addQuery(replacePatientInPatientAssignment, [selectedUuid, otherUuids]);
transaction.addQuery(replacePatientInPatientDocument, [selectedUuid, otherUuids]);
transaction.addQuery(replacePatientInPatientHospitalization, [selectedUuid, otherUuids]);
transaction.addQuery(replacePatientInPatientVisit, [selectedUuid, otherUuids]);
transaction.addQuery(replacePatientInEmployee, [selectedPatientUuid, [otherPatientUuids]]);
transaction.addQuery(replacePatientInPatientAssignment, [selectedPatientUuid, [otherPatientUuids]]);
transaction.addQuery(replacePatientInPatientDocument, [selectedPatientUuid, [otherPatientUuids]]);
transaction.addQuery(replacePatientInPatientHospitalization, [selectedPatientUuid, [otherPatientUuids]]);
transaction.addQuery(replacePatientInPatientVisit, [selectedPatientUuid, [otherPatientUuids]]);

transaction.addQuery(removeOtherPatients, [otherUuids]);
transaction.addQuery(removeOtherPatients, [otherPatientUuids]);
transaction.addQuery(removeOtherDebtors, [glb.otherDebtorUuids]);
return transaction.execute();
})
.then(rows => {
.then(() => {
res.sendStatus(204);
})
.catch(next)

res.sendStatus(200);
.done();
}
18 changes: 18 additions & 0 deletions test/end-to-end/patient/registry.merge.page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* global element, by */

// const FU = require('../../shared/FormUtils');
// const GU = require('../../shared/GridUtils');

function PatientMergePage() {
const page = this;
const gridId = 'patient-registry';

page.gridId = gridId;

page.openMergeTool = async function openMergeTool() {
element(by.css('[data-action="open-tools"]')).click();
element(by.css('[data-action="merge-patient"]')).click();
};
}

module.exports = PatientMergePage;
11 changes: 11 additions & 0 deletions test/end-to-end/patient/registry.merge.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const MergePatientPage = require('./registry.merge.page');

describe('Merge Patients', () => {

const Page = new MergePatientPage();

it('successfully merge two selected patients into one', async () => {
await Page.openMergeTool();
});

});
6 changes: 5 additions & 1 deletion test/end-to-end/patient/registry.spec.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
const helpers = require('../shared/helpers');
const PatientRegistrySearch = require('./registry.search');
const PatientMerge = require('./registry.merge.spec');

// patient registry tests
describe('Patient Registry', () => {
describe.only('Patient Registry', () => {
before(() => helpers.navigate('#/patients'));

// groups patient search modal queries
describe('Search', PatientRegistrySearch);

// merge patients
describe('Merge patients', PatientMerge);
});
158 changes: 110 additions & 48 deletions test/integration/patients.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,79 @@

const helpers = require('./helpers');

describe('(/patients) Patients', () => {
// TODO Should this import UUID library and track mock patient throughout?
const mockPatientUuid = '85BF7A8516D94AE5B5C01FEC9748D2F9';
const mockDebtorUuid = 'EC4241E43558493B9D78DBAA47E3CEFD';
const missingPatientUuid = 'D74BC1673E14487EAF7822FD725E4AC1';

const mockDebtor = {
uuid : mockDebtorUuid,
// TODO Should this import UUID library and track mock patient throughout?
const mockPatientUuid = '85BF7A8516D94AE5B5C01FEC9748D2F9';
const mockDebtorUuid = 'EC4241E43558493B9D78DBAA47E3CEFD';
const missingPatientUuid = 'D74BC1673E14487EAF7822FD725E4AC1';
const mockPatientDoublonUuid = 'WWBF7A8516D94AE5B5C01FEC9748D2F9';
const mockDebtorDoublonUuid = 'WW4241E43558493B9D78DBAA47E3CEFD';

const mockDebtor = {
uuid : mockDebtorUuid,
debtor_group_uuid : '4DE0FE47177F4D30B95FCFF8166400B4',
};

const mockPatient = {
display_name : 'Mock Patient First',
dob : new Date('1993-06-01'),
current_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
origin_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
sex : 'M',
project_id : 1,
hospital_no : 120,
uuid : mockPatientUuid,
};

// missing last name, sex
const missingParamsPatient = {
display_name : 'Mock Patient',
dob : new Date('1993-06-01'),
current_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
origin_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
project_id : 1,
hospital_no : 121,
uuid : missingPatientUuid,
};

const mockRequest = {
finance : mockDebtor,
medical : mockPatient,
};

const mockMissingRequest = {
finance : {
debtor_group_uuid : '4DE0FE47177F4D30B95FCFF8166400B4',
};

const mockPatient = {
display_name : 'Mock Patient First',
dob : new Date('1993-06-01'),
current_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
origin_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
sex : 'M',
project_id : 1,
hospital_no : 120,
uuid : mockPatientUuid,
};

// missing last name, sex
const missingParamsPatient = {
display_name : 'Mock Patient',
dob : new Date('1993-06-01'),
current_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
origin_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
project_id : 1,
hospital_no : 121,
uuid : missingPatientUuid,
};

const mockRequest = {
finance : mockDebtor,
medical : mockPatient,
};

const mockMissingRequest = {
finance : {
debtor_group_uuid : '4DE0FE47177F4D30B95FCFF8166400B4',
},
medical : missingParamsPatient,
};

const badRequest = {
incorrectLayout : mockDebtor,
incorrectTest : mockPatient,
};
},
medical : missingParamsPatient,
};

const badRequest = {
incorrectLayout : mockDebtor,
incorrectTest : mockPatient,
};

const mockDebtorDoublon = {
uuid : mockDebtorDoublonUuid,
debtor_group_uuid : '4DE0FE47177F4D30B95FCFF8166400B4',
};

const mockPatientDoublon = {
display_name : 'Mock Patient First Doublon',
dob : new Date('2017-08-24'),
current_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
origin_location_id : '1F162A109F6747889EFFC1FEA42FCC9B',
sex : 'M',
project_id : 1,
hospital_no : 220,
uuid : mockPatientDoublonUuid,
};

const mockDoublonRequest = {
finance : mockDebtorDoublon,
medical : mockPatientDoublon,
};

describe('(/patients) Patients', () => {
// HTTP API Test for /patients/ routes
describe('Patient Search', () => {

Expand Down Expand Up @@ -238,6 +261,9 @@ describe('(/patients) Patients', () => {
.catch(helpers.handler);
});

// merge patients
describe('merge patients', MergePatients);

// hospital number uniqueness tests
describe('/hospital_number/:id/exists', HospitalNumber);

Expand All @@ -249,6 +275,42 @@ describe('(/patients) Patients', () => {
describe('patient subsidies', subsidies);
});

// patients merge
function MergePatients() {
// add a doublon
it('POST /patients will register a valid doublon patient', () => {
return agent.post('/patients')
.send(mockDoublonRequest)
.then((res) => {
helpers.api.created(res);
})
.catch(helpers.handler);
});

const params = {
selected : mockPatientUuid,
other : [mockPatientDoublonUuid],
};

it('POST /patients/merge will merge two patients into one', () => {
return agent.post('/patients/merge')
.send(params)
.then((res) => {
expect(res).to.have.status(204);
})
.catch(helpers.handler);
});

it('GET /patients returns a correct reduced list of patients', () => {
const INITIAL_TEST_PATIENTS_PLUS_ONE_ADDED = 5;
return agent.get('/patients')
.then((res) => {
helpers.api.listed(res, INITIAL_TEST_PATIENTS_PLUS_ONE_ADDED - 1);
})
.catch(helpers.handler);
});
}

// Tests for /patients/:uuid/groups
function PatientGroups() {

Expand Down

0 comments on commit a6ca2de

Please sign in to comment.