diff --git a/app/admin/custom-forms/edit/controller.js b/app/admin/custom-forms/edit/controller.js
index 9e8e13010c..cc9c446c8a 100644
--- a/app/admin/custom-forms/edit/controller.js
+++ b/app/admin/custom-forms/edit/controller.js
@@ -79,7 +79,9 @@ export default AbstractEditController.extend({
'operativePlan',
'patient',
'socialwork',
- 'visit'
+ 'visit',
+ 'opdReport',
+ 'dischargeReport'
],
formTypes: computed(function() {
diff --git a/app/appointments/edit/route.js b/app/appointments/edit/route.js
index bd5c5c7055..59103d68e0 100644
--- a/app/appointments/edit/route.js
+++ b/app/appointments/edit/route.js
@@ -14,6 +14,7 @@ const {
} = Ember;
export default AbstractEditRoute.extend(AddToPatientRoute, PatientListRoute, {
+
editTitle: t('appointments.editTitle'),
modelName: 'appointment',
newButtonText: t('appointments.buttons.newButton'),
@@ -59,6 +60,9 @@ export default AbstractEditRoute.extend(AddToPatientRoute, PatientListRoute, {
if (!isEmpty(params.forPatientId)) {
let modelPromise = this._super(params);
return this._setPatientOnModel(modelPromise, params.forPatientId);
+ } else if (!isEmpty(params.forVisitId)) {
+ let modelPromise = this._super(params);
+ return this._setVisitOnModel(modelPromise, params.forVisitId);
} else {
return this._createNewRecord(params);
}
diff --git a/app/helpers/date-format.js b/app/helpers/date-format.js
index 7f4ec8d0c3..084f1be96b 100644
--- a/app/helpers/date-format.js
+++ b/app/helpers/date-format.js
@@ -7,6 +7,9 @@ export default Ember.Helper.helper(function(params, hash) {
if (hash && hash.format) {
dateFormat = hash.format;
}
+ if (date && typeof date.get == 'function') {
+ date = date.get('content');
+ }
return moment(date).format(dateFormat);
}
});
diff --git a/app/locales/en/translations.js b/app/locales/en/translations.js
index 8a56e98bd5..bd0c908b59 100644
--- a/app/locales/en/translations.js
+++ b/app/locales/en/translations.js
@@ -173,7 +173,9 @@ export default {
socialworkFormType: 'Social Work',
text: 'Text',
textarea: 'Large Text',
- visitFormType: 'Visit'
+ visitFormType: 'Visit',
+ opdReportFormType: 'Outpatient Report',
+ dischargeReportFormType: 'Discharge Report'
},
messages: {
deleteForm: 'Are you sure you want to delete this custom form?',
@@ -994,14 +996,16 @@ export default {
statusDischarged: 'Discharged',
statusCheckedIn: 'Checked In',
statusCheckedOut: 'Checked Out',
- createNewPatient: 'Create New Patient'
+ createNewPatient: 'Create New Patient',
+ reportType: 'Report type'
},
navigation: {
charges: 'Charges',
notes: 'Notes',
orders: 'Orders',
procedures: 'Procedures',
- vitals: 'Vitals'
+ vitals: 'Vitals',
+ reports: 'Reports'
}
},
labs: {
@@ -1105,6 +1109,8 @@ export default {
backToPatients: 'Back to Patient List',
newPatient: '+ new patient',
patientCheckIn: 'Patient Check In',
+ newOPDReport: 'New OPD Report',
+ newDischargeReport: 'New Discharge Report',
scheduleSurgery: 'Schedule Surgery'
},
labels: {
@@ -1234,6 +1240,55 @@ export default {
addMedication: 'Add Medication'
}
},
+ reports: {
+ titles: {
+ saved: 'Report saved',
+ opdTitle: 'OPD Report',
+ dischargeReport: 'Discharge Report'
+ },
+ form: {
+ visitDate: 'Date of Visit',
+ admissionDate: 'Admission Date',
+ dischargeDate: 'Discharge Date',
+ notes: {
+ title: 'Notes',
+ date: 'Date',
+ author: 'Author'
+ },
+ primaryDiagnosis: 'Primary Diagnosis',
+ secondaryDiagnosis: 'Secondary Diagnosis',
+ procedures: 'Procedures',
+ allProcedures: 'All Procedures Performed',
+ labs: 'Labs',
+ images: 'Images',
+ medications: 'Medications',
+ nextAppointment: 'Next Appointment',
+ nextAppointments: 'Next Appointments',
+ operativePlan: {
+ title: 'Operative Plan',
+ description: 'Operation Description',
+ procedures: 'Planned Procedures',
+ instructions: 'Instructions upon Admission'
+ },
+ completedBy: 'Completed By'
+ },
+ opd: {
+ titles: {
+ new: 'New OPD Report',
+ edit: 'Edit OPD Report'
+ }
+ },
+ discharge: {
+ titles: {
+ new: 'New Discharge Report',
+ edit: 'Edit Discharge Report'
+ }
+ },
+ messages: {
+ delete: 'Are you sure you wish to delete this report?',
+ saved: 'The report has been saved.'
+ }
+ },
components: {
chargesByTypeTab: {
charges: 'charges'
diff --git a/app/medication/edit/controller.js b/app/medication/edit/controller.js
index 9aaa6a6666..21c142449a 100644
--- a/app/medication/edit/controller.js
+++ b/app/medication/edit/controller.js
@@ -35,7 +35,7 @@ export default AbstractEditController.extend(AddNewPatient, FulfillRequest, Inve
prescriptionClass: function() {
let quantity = this.get('model.quantity');
if (Ember.isEmpty(quantity)) {
- return 'required';
+ return 'required test-medication-prescription';
}
}.property('model.quantity'),
diff --git a/app/medication/edit/route.js b/app/medication/edit/route.js
index 7cdbed5d87..e8ae0b4b0d 100644
--- a/app/medication/edit/route.js
+++ b/app/medication/edit/route.js
@@ -35,6 +35,8 @@ export default AbstractEditRoute.extend(AddToPatientRoute, FulfillRequest, Inven
if (!Ember.isEmpty(idParam) && params[idParam] === 'new' || params[idParam] === 'dispense') {
if (!isEmpty(params.forPatientId)) {
return this._setPatientOnModel(modelPromise, params.forPatientId);
+ } else if (!isEmpty(params.forVisitId)) {
+ return this._setVisitOnModel(modelPromise, params.forVisitId);
} else {
return this._createNewRecord(params);
}
diff --git a/app/mixins/add-to-patient-route.js b/app/mixins/add-to-patient-route.js
index c1f79dfe39..865816d2c7 100644
--- a/app/mixins/add-to-patient-route.js
+++ b/app/mixins/add-to-patient-route.js
@@ -6,14 +6,23 @@ export default Mixin.create({
queryParams: {
forPatientId: {
refreshModel: false
+ },
+ forVisitId: {
+ refreshModel: false
}
},
model(params) {
let idParam = get(this, 'idParam');
let modelPromise = this._super(params);
- if (!isEmpty(params.forPatientId) && params[idParam] === 'new') {
- return this._setPatientOnModel(modelPromise, params.forPatientId);
+ if (params[idParam] === 'new') {
+ if (!isEmpty(params.forPatientId)) {
+ return this._setPatientOnModel(modelPromise, params.forPatientId);
+ } else if (!isEmpty(params.forVisitId)) {
+ return this._setVisitOnModel(modelPromise, params.forVisitId);
+ } else {
+ return this._createNewRecord(params);
+ }
} else {
return modelPromise;
}
@@ -32,5 +41,21 @@ export default Mixin.create({
return model;
});
});
+ },
+
+ /**
+ * Resolves the model promise and then sets the visit information on the model.
+ */
+ _setVisitOnModel(modelPromise, visitId) {
+ let store = get(this, 'store');
+ return modelPromise.then((model) => {
+ return store.find('visit', visitId).then((visit) => {
+ model.set('visit', visit);
+ model.set('returnToVisit', visitId);
+ model.set('selectPatient', false);
+ model.set('patient', visit.get('patient'));
+ return model;
+ });
+ });
}
});
diff --git a/app/mixins/patient-submodule.js b/app/mixins/patient-submodule.js
index 999c342fb1..704bf69cbc 100644
--- a/app/mixins/patient-submodule.js
+++ b/app/mixins/patient-submodule.js
@@ -183,6 +183,17 @@ export default Ember.Mixin.create(PatientVisits, {
});
}.property('model.patient.id', 'newVisitAdded'),
+ patientProcedures: Ember.computed('patientVisits.[]', function() {
+ let patient = get(this, 'model.patient');
+ return DS.PromiseArray.create({
+ promise: get(this, 'patientVisits').then((patientVisits) => {
+ return get(patient, 'operationReports').then((operationReports) => {
+ return this._getPatientProcedures(operationReports, patientVisits);
+ });
+ })
+ });
+ }),
+
patientVisitsForSelect: function() {
return DS.PromiseArray.create({
promise: this.get('patientVisits').then(function(patientVisits) {
@@ -227,6 +238,7 @@ export default Ember.Mixin.create(PatientVisits, {
promises.push(visit.get('medication'));
promises.push(visit.get('procedures'));
promises.push(visit.get('vitals'));
+ promises.push(visit.get('reports'));
}
return promises;
},
diff --git a/app/mixins/patient-visits.js b/app/mixins/patient-visits.js
index aee87fa98b..716ac48c34 100644
--- a/app/mixins/patient-visits.js
+++ b/app/mixins/patient-visits.js
@@ -1,9 +1,11 @@
import Ember from 'ember';
import PouchDbMixin from 'hospitalrun/mixins/pouchdb';
import VisitStatus from 'hospitalrun/utils/visit-statuses';
-
+import DS from 'ember-data';
+import moment from 'moment';
const {
- isEmpty
+ isEmpty,
+ get
} = Ember;
export default Ember.Mixin.create(PouchDbMixin, {
@@ -20,6 +22,63 @@ export default Ember.Mixin.create(PouchDbMixin, {
});
},
+ getPatientFutureAppointment(visit, outPatient) {
+ let patientId = get(visit, 'patient.id');
+ let visitDate = get(visit, 'startDate');
+ let maxValue = get(this, 'maxValue');
+ let promise = this.store.query('appointment', {
+ options: {
+ startkey: [patientId, null, null, 'appointment_'],
+ endkey: [patientId, maxValue, maxValue, maxValue]
+ },
+ mapReduce: 'appointments_by_patient'
+ }).then(function(result) {
+ let futureAppointments = result.filter(function(data) {
+ let startDate = get(data, 'startDate');
+ return startDate && moment(startDate).isAfter(moment(visitDate), 'day');
+ }).sortBy('startDate');
+ if (!futureAppointments.length) {
+ return null;
+ }
+ if (!outPatient) {
+ let [appointment] = futureAppointments;
+ return appointment;
+ } else {
+ return futureAppointments.slice(0, 3);
+ }
+
+ });
+ return (outPatient) ? DS.PromiseArray.create({ promise }) : DS.PromiseObject.create({ promise });
+ },
+
+ _getVisitCollection(visits, name) {
+ let returnList = [];
+ if (!Ember.isEmpty(visits)) {
+ visits.forEach(function(visit) {
+ get(visit, name).then(function(items) {
+ returnList.addObjects(items);
+ });
+ });
+ }
+ return returnList;
+ },
+
+ _getPatientProcedures(operationReports, visits) {
+ let patientProcedures = this._getVisitCollection(visits, 'procedures');
+ operationReports.forEach((report) => {
+ let reportedProcedures = get(report, 'procedures');
+ let surgeryDate = get(report, 'surgeryDate');
+ reportedProcedures.forEach((procedure) => {
+ patientProcedures.addObject({
+ description: get(procedure, 'description'),
+ procedureDate: surgeryDate,
+ report
+ });
+ });
+ });
+ return patientProcedures;
+ },
+
checkoutVisit(visit, status) {
visit.set('status', status);
visit.set('endDate', new Date());
diff --git a/app/mixins/user-session.js b/app/mixins/user-session.js
index 4316714ba6..8a77720332 100644
--- a/app/mixins/user-session.js
+++ b/app/mixins/user-session.js
@@ -198,6 +198,15 @@ export default Ember.Mixin.create({
'Nurse Manager',
'System Administrator'
],
+ add_report: [
+ 'Data Entry',
+ 'Doctor',
+ 'Hospital Administrator',
+ 'Medical Records Officer',
+ 'Nurse',
+ 'Nurse Manager',
+ 'System Administrator'
+ ],
admit_patient: [
'Data Entry',
'Doctor',
@@ -324,6 +333,14 @@ export default Ember.Mixin.create({
'Nurse Manager',
'System Administrator'
],
+ delete_report: [
+ 'Doctor',
+ 'Hospital Administrator',
+ 'Medical Records Officer',
+ 'Nurse',
+ 'Nurse Manager',
+ 'System Administrator'
+ ],
delete_visit: [
'Doctor',
'Hospital Administrator',
diff --git a/app/models/report.js b/app/models/report.js
new file mode 100644
index 0000000000..2de87f00e8
--- /dev/null
+++ b/app/models/report.js
@@ -0,0 +1,32 @@
+import AbstractModel from 'hospitalrun/models/abstract';
+import DS from 'ember-data';
+
+export default AbstractModel.extend({
+ // Attributes
+ reportDate: DS.attr('date'),
+ customForms: DS.attr('custom-forms'),
+ reportType: DS.attr('string'),
+ surgeon: DS.attr('string'),
+
+ // Associations
+ visit: DS.belongsTo('visit', { async: false }),
+
+ validations: {
+ visit: {
+ presence: true
+ },
+
+ reportDate: {
+ presence: true
+ },
+
+ surgeon: {
+ presence: {
+ 'if'(object) {
+ return !object.get('visit.outPatient');
+ },
+ message: 'Please select a surgeon'
+ }
+ }
+ }
+});
diff --git a/app/models/visit.js b/app/models/visit.js
index e400cb4136..317d5ae968 100644
--- a/app/models/visit.js
+++ b/app/models/visit.js
@@ -70,6 +70,7 @@ export default AbstractModel.extend({
status: DS.attr('string'),
visitType: DS.attr(),
vitals: DS.hasMany('vital', { async: true }),
+ reports: DS.hasMany('report', { async: true }),
diagnosisList: computed('diagnoses.[]', function() {
let diagnoses = this.get('diagnoses');
diff --git a/app/patients/edit/controller.js b/app/patients/edit/controller.js
index 6de354eb74..0b0ba25527 100644
--- a/app/patients/edit/controller.js
+++ b/app/patients/edit/controller.js
@@ -8,13 +8,14 @@ import ReturnTo from 'hospitalrun/mixins/return-to';
import SelectValues from 'hospitalrun/utils/select-values';
import UserSession from 'hospitalrun/mixins/user-session';
import VisitStatus from 'hospitalrun/utils/visit-statuses';
+import PatientVisits from 'hospitalrun/mixins/patient-visits';
const {
get,
isEmpty
} = Ember;
-export default AbstractEditController.extend(BloodTypes, DiagnosisActions, PatientId, ReturnTo, UserSession, PatientNotes, {
+export default AbstractEditController.extend(BloodTypes, DiagnosisActions, ReturnTo, UserSession, PatientId, PatientNotes, PatientVisits, {
canAddAppointment: function() {
return this.currentUserCan('add_appointment');
@@ -144,32 +145,21 @@ export default AbstractEditController.extend(BloodTypes, DiagnosisActions, Patie
}],
patientImaging: function() {
- return this._getVisitCollection('imaging');
+ return this.getVisitCollection('imaging');
}.property('model.visits.[].imaging'),
patientLabs: function() {
- return this._getVisitCollection('labs');
+ return this.getVisitCollection('labs');
}.property('model.visits.[].labs'),
patientMedications: function() {
- return this._getVisitCollection('medication');
+ return this.getVisitCollection('medication');
}.property('model.visits.[].medication'),
patientProcedures: function() {
- let patientProcedures = this._getVisitCollection('procedures');
+ let visits = this.get('model.visits');
let operationReports = get(this, 'model.operationReports');
- operationReports.forEach((report) => {
- let reportedProcedures = get(report, 'procedures');
- let surgeryDate = get(report, 'surgeryDate');
- reportedProcedures.forEach((procedure) => {
- patientProcedures.addObject({
- description: get(procedure, 'description'),
- procedureDate: surgeryDate,
- report
- });
- });
- });
- return patientProcedures;
+ return this._getPatientProcedures(operationReports, visits);
}.property('model.visits.[].procedures', 'model.operationReports.[].procedures'),
showExpenseTotal: function() {
@@ -533,17 +523,9 @@ export default AbstractEditController.extend(BloodTypes, DiagnosisActions, Patie
this.send('openModal', `patients.socialwork.${route}`, model);
},
- _getVisitCollection(name) {
- let returnList = [];
+ getVisitCollection(name) {
let visits = this.get('model.visits');
- if (!Ember.isEmpty(visits)) {
- visits.forEach(function(visit) {
- visit.get(name).then(function(items) {
- returnList.addObjects(items);
- });
- });
- }
- return returnList;
+ return this._getVisitCollection(visits, name);
},
_updateSocialRecord(recordToUpdate, name) {
diff --git a/app/procedures/edit/route.js b/app/procedures/edit/route.js
index cfac071baf..714a4b84eb 100644
--- a/app/procedures/edit/route.js
+++ b/app/procedures/edit/route.js
@@ -1,9 +1,10 @@
import AbstractEditRoute from 'hospitalrun/routes/abstract-edit-route';
+import AddToPatientRoute from 'hospitalrun/mixins/add-to-patient-route';
import ChargeRoute from 'hospitalrun/mixins/charge-route';
import Ember from 'ember';
import { translationMacro as t } from 'ember-i18n';
-export default AbstractEditRoute.extend(ChargeRoute, {
+export default AbstractEditRoute.extend(AddToPatientRoute, ChargeRoute, {
editTitle: t('procedures.titles.edit'),
modelName: 'procedure',
newTitle: t('procedures.titles.new'),
diff --git a/app/reports/edit/controller.js b/app/reports/edit/controller.js
new file mode 100644
index 0000000000..fda9cad173
--- /dev/null
+++ b/app/reports/edit/controller.js
@@ -0,0 +1,79 @@
+import AbstractEditController from 'hospitalrun/controllers/abstract-edit-controller';
+import Ember from 'ember';
+import PatientSubmodule from 'hospitalrun/mixins/patient-submodule';
+import PatientDiagnosis from 'hospitalrun/mixins/patient-diagnosis';
+import PouchDbMixin from 'hospitalrun/mixins/pouchdb';
+
+const {
+ get,
+ set
+} = Ember;
+
+export default AbstractEditController.extend(PatientSubmodule, PatientDiagnosis, PouchDbMixin, {
+ lookupListsToUpdate: [{
+ name: 'physicianList',
+ property: 'model.surgeon',
+ id: 'physician_list'
+ }],
+
+ newReport: false,
+
+ visitsController: Ember.inject.controller('visits'),
+
+ physicianList: Ember.computed.alias('visitsController.physicianList'),
+
+ logoURL: Ember.computed.alias('visitsController.printHeader.value.logoURL'),
+ facilityName: Ember.computed.alias('visitsController.printHeader.value.facilityName'),
+ headerLine1: Ember.computed.alias('visitsController.printHeader.value.headerLine1'),
+ headerLine2: Ember.computed.alias('visitsController.printHeader.value.headerLine2'),
+ headerLine3: Ember.computed.alias('visitsController.printHeader.value.headerLine3'),
+
+ diagnosisList: Ember.computed.alias('visitsController.diagnosisList'),
+
+ additionalButtons: Ember.computed('model.{isNew}', function() {
+ let isNew = get(this, 'model.isNew');
+ if (!isNew) {
+ return [{
+ class: 'btn btn-primary on-white',
+ buttonAction: 'printReport',
+ buttonIcon: 'octicon octicon-check',
+ buttonText: 'Print'
+ }];
+ }
+ }),
+
+ updateCapability: 'add_report',
+
+ beforeUpdate() {
+ return new Ember.RSVP.Promise((resolve) => {
+ let model = get(this, 'model');
+ if (get(model, 'isNew')) {
+ if (get(this, 'model.visit.outPatient')) {
+ set(model, 'reportType', 'OPD Report');
+ } else {
+ set(model, 'reportType', 'Discharge Report');
+ }
+ }
+ resolve();
+ });
+ },
+
+ afterUpdate() {
+ let alertTitle = get(this, 'i18n').t('reports.titles.saved');
+ let alertMessage = get(this, 'i18n').t('reports.messages.saved');
+ this.saveVisitIfNeeded(alertTitle, alertMessage);
+ let opdTitle = get(this, 'i18n').t('reports.opd.titles.edit');
+ let dischargeTitle = get(this, 'i18n').t('reports.discharge.titles.edit');
+ let editTitle = get(this, 'model.visit.outPatient') ? opdTitle : dischargeTitle;
+ let sectionDetails = {};
+ sectionDetails.currentScreenTitle = editTitle;
+ this.send('setSectionHeader', sectionDetails);
+ },
+
+ actions: {
+ printReport() {
+ window.print();
+ }
+ }
+
+});
diff --git a/app/reports/edit/route.js b/app/reports/edit/route.js
new file mode 100644
index 0000000000..f5277f0748
--- /dev/null
+++ b/app/reports/edit/route.js
@@ -0,0 +1,68 @@
+import AbstractEditRoute from 'hospitalrun/routes/abstract-edit-route';
+import AddToPatientRoute from 'hospitalrun/mixins/add-to-patient-route';
+import Ember from 'ember';
+import { translationMacro as t } from 'ember-i18n';
+import PatientVisits from 'hospitalrun/mixins/patient-visits';
+
+const {
+ get,
+ set
+} = Ember;
+
+export default AbstractEditRoute.extend(AddToPatientRoute, PatientVisits, {
+ modelName: 'report',
+ customForms: Ember.inject.service(),
+
+ getNewData() {
+ let newReportData = {
+ reportDate: new Date(),
+ customForms: Ember.Object.create()
+ };
+ let customForms = get(this, 'customForms');
+ return customForms.setDefaultCustomForms(['opdReport', 'dischargeReport'], newReportData);
+ },
+
+ getScreenTitle(model) {
+ let state = get(model, 'isNew') ? 'new' : 'edit';
+ let type = get(model, 'visit.outPatient') ? 'opd' : 'discharge';
+ return t(`reports.${type}.titles.${state}`);
+ },
+
+ getDiagnosisContainer(visit) {
+ if (get(visit, 'outPatient')) {
+ return visit;
+ }
+ return null;
+ },
+
+ getCurrentOperativePlan(patient) {
+ let operativePlans = get(patient, 'operativePlans');
+ return operativePlans.findBy('isPlanned', true);
+ },
+
+ afterModel(model) {
+ if (!get(model, 'isNew')) {
+ let patient = get(model, 'visit.patient');
+ set(model, 'patient', patient);
+ }
+ if (!get(model, 'visit')) {
+ return this.transitionTo('patients');
+ }
+ },
+
+ setupController(controller, model) {
+ this._super(controller, model);
+ let visit = get(model, 'visit');
+ let patient = get(model, 'patient');
+ let isOutPatient = get(visit, 'outPatient');
+ set(controller, 'visit', visit);
+ set(controller, 'isOutPatient', isOutPatient);
+ set(controller, 'diagnosisContainer', this.getDiagnosisContainer(visit));
+ set(controller, 'currentOperativePlan', this.getCurrentOperativePlan(patient));
+ if (isOutPatient) {
+ set(controller, 'nextAppointments', this.getPatientFutureAppointment(visit, true));
+ } else {
+ set(controller, 'nextAppointment', this.getPatientFutureAppointment(visit));
+ }
+ }
+});
diff --git a/app/reports/edit/template.hbs b/app/reports/edit/template.hbs
new file mode 100644
index 0000000000..00000bc153
--- /dev/null
+++ b/app/reports/edit/template.hbs
@@ -0,0 +1,204 @@
+
+
+ {{#edit-panel editPanelProps=editPanelProps}}
+ {{#em-form model=model submitButton=false }}
+ {{#if model.patient}}
+ {{patient-summary
+ patient=model.patient
+ disablePatientLink=true
+ diagnosisContainer=diagnosisContainer
+ diagnosisList=diagnosisList
+ }}
+ {{/if}}
+
+
+
+ {{date-format visit.startDate format="DD/MM/YYYY"}}
+
+
+ {{#if isOutPatient}}
+
+ {{#if visit.procedures}}
+
+
+
+ {{#each visit.procedures as |item|}}
+ - {{item.description}}
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if visit.labs}}
+
+
+
+ {{#each visit.labs as |item|}}
+ - {{item.labType.name}}-{{item.result}} ({{item.status}})
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if visit.imaging}}
+
+
+
+ {{#each visit.imaging as |item|}}
+ - {{item.imagingType.name}}-{{item.result}} ({{item.status}})
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if visit.medication}}
+
+
+
+ {{#each visit.medication as |medication|}}
+ - {{medication.medicationName}} - {{medication.prescription}} ({{medication.status}})
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if nextAppointments}}
+
+
+
+ {{#each nextAppointments as |appointment|}}
+ -
+ {{date-format appointment.startDate format="DD/MM/YYYY hh:mm a"}}
+ {{#if appointment.appointmentType}}
+ ({{appointment.appointmentType}})
+ {{/if}}
+
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if currentOperativePlan}}
+
+
+
+ {{#if currentOperativePlan.operationDescription}}
+ -
+
{{t 'reports.form.operativePlan.description' }}:
+ {{currentOperativePlan.operationDescription}}
+
+ {{/if}}
+
+ -
+
{{t 'reports.form.operativePlan.procedures' }}:
+
+ {{#each currentOperativePlan.procedures as |procedure|}}
+ - {{procedure.description}}
+ {{/each}}
+
+
+
+ {{#if currentOperativePlan.admissionInstructions}}
+ -
+
{{t 'reports.form.operativePlan.instructions' }}:
+ {{currentOperativePlan.admissionInstructions}}
+
+ {{/if}}
+
+
+ {{/if}}
+
+ {{custom-form-manager model=model formType="opdReport"}}
+
+ {{else}}
+
+
+
+ {{date-format model.reportDate format="DD/MM/YYYY"}}
+
+
+
+ {{select-or-typeahead className="col-sm-4" property="surgeon"
+ label=(t "operativePlan.labels.surgeon") list=physicianList
+ selection=model.surgeon
+ class="plan-surgeon"
+ }}
+
+
+ {{#if patientProcedures}}
+
+
+ {{#each patientProcedures as |procedure|}}
+ - {{procedure.description}} -
+ {{#if procedure.procedureDate }}
+ {{date-format procedure.procedureDate format="DD/MM/YYYY"}}
+ {{/if}}
+ {{/each}}
+
+ {{/if}}
+
+ {{#if visit.patientNotes}}
+
+
+
+ {{#each visit.patientNotes as |note|}}
+ -
+ {{t 'reports.form.notes.date' }}: {{date-format note.date}}
+ {{t 'reports.form.notes.author' }}: {{note.authoredBy}}
+ {{note.noteType}}: {{note.content}}
+
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if nextAppointment}}
+
+
+ {{date-format nextAppointment.startDate format="DD/MM/YYYY hh:mm a"}}
+ {{#if nextAppointment.location}}
+ ({{nextAppointment.location}})
+ {{/if}}
+
+ {{/if}}
+
+ {{custom-form-manager model=model formType="dischargeReport"}}
+
+ {{#if model.modifiedBy}}
+
+
+ {{model.modifiedBy}}
+
+ {{/if}}
+
+ {{/if}}
+ {{/em-form}}
+ {{/edit-panel}}
+
diff --git a/app/router.js b/app/router.js
index 37f4489015..d59b63baa5 100755
--- a/app/router.js
+++ b/app/router.js
@@ -115,6 +115,13 @@ Router.map(function() {
}, function() {
this.route('edit', { path: '/edit/:procedure_id' });
});
+
+ this.route('reports', {
+ resetNamespace: true
+ }, function() {
+ this.route('edit', { path: '/edit/:report_id' });
+ });
+
});
});
diff --git a/app/services/database.js b/app/services/database.js
index e04e25c424..249bb14388 100644
--- a/app/services/database.js
+++ b/app/services/database.js
@@ -3,8 +3,10 @@ import createPouchViews from 'hospitalrun/utils/pouch-views';
import List from 'npm:pouchdb-list';
import PouchAdapterMemory from 'npm:pouchdb-adapter-memory';
import UnauthorizedError from 'hospitalrun/utils/unauthorized-error';
+import enviroment from './../config/environment';
const {
+ get,
isEmpty
} = Ember;
@@ -20,9 +22,47 @@ export default Ember.Service.extend({
.then((db) => {
this.set('mainDB', db);
this.set('setMainDB', true);
+ })
+ .then(() => {
+ this.createOptionHeader([enviroment.hospitalInfoDoc]);
});
},
+ createOptionHeader(docs) {
+ return new Ember.RSVP.Promise((resolve, reject) => {
+ let mainDB = get(this, 'mainDB');
+ let ids = docs.map((doc) => {
+ return doc._id;
+ });
+ return mainDB.allDocs({ keys: ids })
+ .then((res) => {
+ if (res.rows) {
+ let docsToCreate = res.rows.filter((row) => {
+ return (row.error && row.error === 'not_found') || (row.value && row.value.deleted);
+ }).map((row) => {
+ return docs.find((doc) => {
+ if (doc._id === row.key) {
+ if (row.value && row.value.deleted && row.value.rev !== doc._rev) {
+ doc._rev = row.value.rev;
+ }
+ return true;
+ }
+ });
+ });
+ if (docsToCreate.length) {
+ return mainDB.bulkDocs(docsToCreate);
+ }
+ }
+ })
+ .then((res) => {
+ resolve(res);
+ })
+ .catch((err) => {
+ reject(err);
+ });
+ });
+ },
+
createDB(configs) {
return new Ember.RSVP.Promise((resolve, reject) => {
let pouchOptions = {};
diff --git a/app/styles/_print.scss b/app/styles/_print.scss
index 2816743972..750c1e367c 100644
--- a/app/styles/_print.scss
+++ b/app/styles/_print.scss
@@ -1,4 +1,4 @@
-.print-section {
+.report-header {
display: none;
}
@@ -17,8 +17,10 @@
width: 90%;
}
- .print-section {
+ .report-header {
display: block;
+ border-bottom: 1px solid #d2dae3;
+ padding: 10px 0;
text-align: center;
}
@@ -32,4 +34,46 @@
.patient-history-heading {
border-bottom: 1px solid $black;
}
+
+ .report-logo {
+ height: 60px;
+ }
+
+ .report .patient-summary {
+ margin-bottom: 20px;
+ border-bottom: 1px solid #d2dae3;
+ }
+
+ .report input {
+ border: 0;
+ padding: 5px;
+ font-size: .8em;
+ }
+
+ .report select {
+ outline: 0;
+ border: 0;
+ text-overflow: '';
+ -moz-appearance: none;
+ -webkit-appearance: none;
+ }
+
+ .report .panel-primary {
+ position: absolute;
+ left: 0;
+ margin: 0;
+ width: 100%;
+ }
+
+ .print-hide {
+ display: none;
+ }
+
+ .view-top-bar {
+ display: none;
+ }
+
+ .view-sub-bar {
+ display: none;
+ }
}
diff --git a/app/templates/section.hbs b/app/templates/section.hbs
index 7deaed121b..7c89d7f305 100644
--- a/app/templates/section.hbs
+++ b/app/templates/section.hbs
@@ -2,7 +2,6 @@
{{currentScreenTitle}}
-
{{t 'messages.forAuthorizedPersons'}}
{{#if newButtonAction}}
diff --git a/app/users/edit/controller.js b/app/users/edit/controller.js
index b2d0733f2e..bac2f26798 100644
--- a/app/users/edit/controller.js
+++ b/app/users/edit/controller.js
@@ -3,6 +3,10 @@ import Ember from 'ember';
import UserRoles from 'hospitalrun/mixins/user-roles';
import uuid from 'npm:uuid';
+const {
+ get
+} = Ember;
+
export default AbstractEditController.extend(UserRoles, {
usersController: Ember.inject.controller('users/index'),
updateCapability: 'add_user',
@@ -39,7 +43,11 @@ export default AbstractEditController.extend(UserRoles, {
updateModel.set('userPrefix', prefix);
}
updateModel.save().then(() => {
- this.displayAlert(this.get('i18n').t('messages.userSaved'), this.get('i18n').t('messages.userHasBeenSaved'));
+ this.displayAlert(get(this, 'i18n').t('messages.userSaved'), get(this, 'i18n').t('messages.userHasBeenSaved'));
+ let editTitle = get(this, 'i18n').t('labels.editUser');
+ let sectionDetails = {};
+ sectionDetails.currentScreenTitle = editTitle;
+ this.send('setSectionHeader', sectionDetails);
}).catch((error) => this.send('error', error));
}
}
diff --git a/app/utils/pouch-views.js b/app/utils/pouch-views.js
index 4f229dccf3..845bf55312 100644
--- a/app/utils/pouch-views.js
+++ b/app/utils/pouch-views.js
@@ -477,6 +477,12 @@ let designDocs = [{
emit([doc.data.patient, startDate, endDate, doc.data.visitType, doc._id]);`
),
version: 4
+}, {
+ name: 'report_by_visit',
+ function: generateView('report',
+ 'emit(doc.data.visit);'
+ ),
+ version: 1
}];
export default function(db, runningTest, testDumpFile) {
diff --git a/app/visits/edit/controller.js b/app/visits/edit/controller.js
index fc17787684..f6a1db76f7 100644
--- a/app/visits/edit/controller.js
+++ b/app/visits/edit/controller.js
@@ -37,6 +37,8 @@ export default AbstractEditController.extend(AddNewPatient, ChargeActions, Diagn
}
}),
+ noReport: false,
+
canAddAppointment: computed('model.isNew', function() {
return (!this.get('model.isNew') && this.currentUserCan('add_appointment'));
}),
@@ -65,6 +67,10 @@ export default AbstractEditController.extend(AddNewPatient, ChargeActions, Diagn
return this.currentUserCan('add_vitals');
}.property(),
+ canAddReport: computed('hasReport', function() {
+ return this.currentUserCan('add_report') && !this.get('hasReport');
+ }),
+
canDeleteImaging: function() {
return this.currentUserCan('delete_imaging');
}.property(),
@@ -85,6 +91,10 @@ export default AbstractEditController.extend(AddNewPatient, ChargeActions, Diagn
return this.currentUserCan('delete_vitals');
}.property(),
+ canDeleteReport: function() {
+ return this.currentUserCan('delete_report');
+ }.property(),
+
isAdmissionVisit: function() {
let visitType = this.get('model.visitType');
let isAdmission = (visitType === 'Admission');
@@ -162,17 +172,16 @@ export default AbstractEditController.extend(AddNewPatient, ChargeActions, Diagn
}.property('visitTypes', 'model.outPatient'),
_addChildObject(route, afterTransition) {
- this.transitionToRoute(route, 'new').then(function(newRoute) {
- newRoute.currentModel.setProperties({
- patient: this.get('model.patient'),
- visit: this.get('model'),
- selectPatient: false,
- returnToVisit: this.get('model.id')
- });
+ let options = {
+ queryParams: {
+ forVisitId: this.get('model.id')
+ }
+ };
+ this.transitionToRoute(route, 'new', options).then((newRoute) => {
if (afterTransition) {
afterTransition(newRoute);
}
- }.bind(this));
+ });
},
_finishAfterUpdate() {
@@ -398,6 +407,11 @@ export default AbstractEditController.extend(AddNewPatient, ChargeActions, Diagn
}
},
+ editReport(report) {
+ set(report, 'returnToVisit', get(this, 'model.id'));
+ this.transitionToRoute('reports.edit', report);
+ },
+
newPatientChanged(createNewPatient) {
set(this, 'model.createNewPatient', createNewPatient);
let model = this.get('model');
@@ -443,6 +457,10 @@ export default AbstractEditController.extend(AddNewPatient, ChargeActions, Diagn
this._addChildObject('medication.edit');
},
+ newReport() {
+ this._addChildObject('reports.edit');
+ },
+
showAddProcedure() {
this._addChildObject('procedures.edit');
},
diff --git a/app/visits/edit/route.js b/app/visits/edit/route.js
index d49288ce9b..8a275b614c 100644
--- a/app/visits/edit/route.js
+++ b/app/visits/edit/route.js
@@ -3,8 +3,16 @@ import AbstractEditRoute from 'hospitalrun/routes/abstract-edit-route';
import ChargeRoute from 'hospitalrun/mixins/charge-route';
import Ember from 'ember';
import PatientListRoute from 'hospitalrun/mixins/patient-list-route';
+import PatientVisit from 'hospitalrun/mixins/patient-visits';
+import DS from 'ember-data';
-export default AbstractEditRoute.extend(ChargeRoute, PatientListRoute, {
+const {
+ get,
+ set,
+ isEmpty
+} = Ember;
+
+export default AbstractEditRoute.extend(ChargeRoute, PatientListRoute, PatientVisit, {
customForms: Ember.inject.service(),
editTitle: t('visits.titles.editVisit'),
modelName: 'visit',
@@ -12,11 +20,11 @@ export default AbstractEditRoute.extend(ChargeRoute, PatientListRoute, {
pricingCategory: 'Ward',
model(params) {
- let idParam = this.get('idParam');
- if (!Ember.isEmpty(idParam) && params[idParam] === 'checkin') {
+ let idParam = get(this, 'idParam');
+ if (!isEmpty(idParam) && params[idParam] === 'checkin') {
return this.getNewData().then((newData) => {
newData.checkIn = true;
- let newVisit = this.get('store').createRecord('visit', newData);
+ let newVisit = get(this, 'store').createRecord('visit', newData);
return newVisit;
});
} else {
@@ -42,6 +50,20 @@ export default AbstractEditRoute.extend(ChargeRoute, PatientListRoute, {
}
},
+ setupController(controller, model) {
+ let promise = this.store.query('report', {
+ options: {
+ key: get(model, 'id')
+ },
+ mapReduce: 'report_by_visit'
+ }).then((reports) => {
+ set(controller, 'noReport', isEmpty(reports));
+ return isEmpty(reports) ? '' : get(reports, 'firstObject');
+ });
+ set(controller, 'report', DS.PromiseObject.create({ promise }));
+ this._super(controller, model);
+ },
+
actions: {
updateNote() {
this.controller.send('update', true);
diff --git a/app/visits/edit/template.hbs b/app/visits/edit/template.hbs
index 49d6331c14..1837d98fa1 100644
--- a/app/visits/edit/template.hbs
+++ b/app/visits/edit/template.hbs
@@ -129,6 +129,11 @@
{{t 'visits.navigation.charges'}}
+
+
+ {{t 'visits.navigation.reports'}}
+
+
@@ -196,7 +201,7 @@
@@ -257,6 +262,48 @@
{{partial 'item-charges'}}
{{/em-form}}
+
+
+ {{#if noReport}}
+
+
+ {{#if canAddReport}}
+
+ {{/if}}
+
+
+ {{else}}
+
+
+
+
+
+
+ {{date-format report.reportDate}} |
+ {{report.modifiedBy}} |
+ {{report.reportType}} |
+
+
+ |
+
+
+
+
+ {{/if}}
+
+
+
{{/unless}}
diff --git a/app/visits/route.js b/app/visits/route.js
index d397fb2d74..3c66313539 100644
--- a/app/visits/route.js
+++ b/app/visits/route.js
@@ -37,6 +37,9 @@ export default AbstractModuleRoute.extend({
}, {
name: 'wardPricingTypes',
findArgs: ['lookup', 'ward_pricing_types']
+ }, {
+ name: 'printHeader',
+ findArgs: ['option', 'print_header']
}],
moduleName: 'visits',
newButtonAction: null, // No new button
diff --git a/config/environment.js b/config/environment.js
index 54cd1a20c6..b84301428c 100644
--- a/config/environment.js
+++ b/config/environment.js
@@ -74,5 +74,18 @@ module.exports = function(environment) {
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source'
};
+ ENV.hospitalInfoDoc = {
+ "_id": "option_2_print_header",
+ "_rev": "1-4457555eacb405267c6d3b7a53d8521d",
+ "data": {
+ "value": {
+ "facilityName": "Beit CURE International Hospital",
+ "headerLine1": "PO Box 31236",
+ "headerLine2": "Blantyre 3",
+ "headerLine3": "+265 (0) 1 871 900 / +265 (0) 1 875 015 /+265 (0) 1 873 694 / +265 (0) 999 505 212",
+ "logoURL": "https://curehospital.mw/wp-content/uploads/4/2012/11/CURE-Malawi-Logo_rgb_280_89.jpg"
+ }
+ }
+ };
return ENV;
};
diff --git a/tests/acceptance/users-test.js b/tests/acceptance/users-test.js
index 8c1060087a..2fe3d4e189 100644
--- a/tests/acceptance/users-test.js
+++ b/tests/acceptance/users-test.js
@@ -126,6 +126,7 @@ test('create new user', function(assert) {
waitToAppear('.modal-dialog');
andThen(() => {
assert.equal(find('.modal-title').text(), 'User Saved', 'User was saved successfully');
+ assert.equal(find('.view-current-title').text(), 'Edit User', 'Page title changed to Edit User');
});
click('button:contains(Ok)');
});
diff --git a/tests/acceptance/visit-test.js b/tests/acceptance/visit-test.js
index 29dfdc895c..a572b75ea0 100644
--- a/tests/acceptance/visit-test.js
+++ b/tests/acceptance/visit-test.js
@@ -1,7 +1,29 @@
import Ember from 'ember';
+import moment from 'moment';
import { module, test } from 'qunit';
import startApp from 'hospitalrun/tests/helpers/start-app';
+const { isEmpty } = Ember;
+
+const visitData = {
+ outPatient: {
+ PRIMARY_DIAGNOSIS: 'ACL deficient knee, right',
+ SECONDARY_DIAGNOSIS: 'ACL deficient knee, left',
+ OPERATION_DESCRIPTION: 'Describe Operation here',
+ PROCEDURE_SPLINT: 'application of long arm post splint',
+ ADMISSION_INSTRUCTIONS: 'Admission Instructions here',
+ OPD_PROCEDURE_DESCRIPTION: 'Bilateral knee Release',
+ OPD_PROCEDURE_PHYSICIAN: 'Sarah Kearney',
+ LAB_TYPE: 'Cholesterol',
+ IMAGING_TYPE: 'Cervical Spine AP-L',
+ APPOINTMENT_START_DATE: moment().add(7, 'days').format('l h:mm A'),
+ APPOINTMENT_END_DATE: moment().add(8, 'days').format('l h:mm A')
+ },
+ admission: {
+ NOTE_CONTENT: 'Patient notes are entered here'
+ }
+};
+
module('Acceptance | visits', {
beforeEach() {
this.application = startApp();
@@ -12,27 +34,27 @@ module('Acceptance | visits', {
}
});
-test('Add visit', function(assert) {
+test('Add admission visit', function(assert) {
runWithPouchDump('patient', function() {
authenticateUser();
- visit('/patients');
- andThen(function() {
- assert.equal(currentURL(), '/patients', 'Patient url is correct');
- click('button:contains(Edit)');
- });
- andThen(function() {
- assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Joe Bagadonuts patient record displays');
- click('[data-test-selector=visits-tab]');
- waitToAppear('#visits button:contains(Edit)'); // Make sure visits have been retrieved.
- });
- andThen(function() {
- click('#visits button:contains(New Visit)');
- waitToAppear('#visit-info');
- });
- andThen(function() {
- assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Joe Bagadonuts displays as patient for visit');
- updateVisit(assert, 'Add');
- });
+ addVisit(assert);
+ addAdmissionData(assert);
+ newReport(assert, 'Discharge');
+ checkDischargeReport(assert);
+ saveReport(assert, 'Discharge');
+ editReport(assert, 'Discharge');
+ });
+});
+
+test('Add OPD visit', function(assert) {
+ runWithPouchDump('patient', function() {
+ authenticateUser();
+ addVisit(assert, 'Clinic');
+ addOutpatientData(assert);
+ newReport(assert, 'OPD');
+ checkOPDReport(assert);
+ saveReport(assert, 'OPD');
+ editReport(assert, 'OPD');
});
});
@@ -68,7 +90,7 @@ test('Edit visit', function(assert) {
click('button:contains(New Medication)');
});
andThen(function() {
- assert.equal(currentURL(), '/medication/edit/new', 'New medication url is correct');
+ assert.equal(currentURL(), '/medication/edit/new?forVisitId=03C7BF8B-04E0-DD9E-9469-96A5604F5340', 'New medication url is correct');
assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'New medication prepopulates with patient');
click('button:contains(Cancel)');
});
@@ -76,7 +98,7 @@ test('Edit visit', function(assert) {
click('button:contains(New Lab)');
});
andThen(function() {
- assert.equal(currentURL(), '/labs/edit/new', 'New lab url is correct');
+ assert.equal(currentURL(), '/labs/edit/new?forVisitId=03C7BF8B-04E0-DD9E-9469-96A5604F5340', 'New lab url is correct');
assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'New lab prepopulates with patient');
click('button:contains(Cancel)');
});
@@ -84,7 +106,7 @@ test('Edit visit', function(assert) {
click('button:contains(New Imaging)');
});
andThen(function() {
- assert.equal(currentURL(), '/imaging/edit/new', 'New imaging url is correct');
+ assert.equal(currentURL(), '/imaging/edit/new?forVisitId=03C7BF8B-04E0-DD9E-9469-96A5604F5340', 'New imaging url is correct');
assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'New imaging prepopulates with patient');
click('button:contains(Cancel)');
});
@@ -196,8 +218,246 @@ test('Delete visit', function(assert) {
});
});
-function updateVisit(assert, buttonText) {
+function addVisit(assert, type) {
+ visit('/patients');
+ andThen(function() {
+ assert.equal(currentURL(), '/patients', 'Patient url is correct');
+ click('button:contains(Edit)');
+ });
+ andThen(function() {
+ assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Joe Bagadonuts patient record displays');
+ click('[data-test-selector=visits-tab]');
+ waitToAppear('#visits button:contains(Edit)');
+ });
+ andThen(function() {
+ click('#visits button:contains(New Visit)');
+ waitToAppear('#visit-info');
+ });
+ andThen(function() {
+ assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Joe Bagadonuts displays as patient for visit');
+ updateVisit(assert, 'Add', type);
+ });
+
+}
+
+function addOutpatientData(assert) {
+ andThen(() =>{
+ click('a:contains(Add Diagnosis)');
+ waitToAppear('.modal-dialog');
+ });
+ andThen(() => {
+ assert.equal(find('.modal-title').text(), 'Add Diagnosis', 'Add Diagnosis dialog displays');
+ fillIn('.diagnosis-text input', visitData.outPatient.PRIMARY_DIAGNOSIS);
+ click('.modal-footer button:contains(Add)');
+ });
+ andThen(function() {
+ waitToDisappear('.modal-dialog');
+ });
+ andThen(() => {
+ click('a:contains(Add Diagnosis)');
+ waitToAppear('.modal-dialog');
+ });
+ andThen(() => {
+ assert.equal(find('.modal-title').text(), 'Add Diagnosis', 'Add Diagnosis dialog displays');
+ fillIn('.diagnosis-text input', visitData.outPatient.SECONDARY_DIAGNOSIS);
+ click('.secondary-diagnosis input');
+ click('.modal-footer button:contains(Add)');
+ });
+ andThen(function() {
+ waitToDisappear('.modal-dialog');
+ });
+ andThen(() => {
+ click('a:contains(Add Operative Plan)');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('/patients/operative-plan/new?forVisitId') > -1, 'New operative plan URL is visited');
+ assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Joe Bagadonuts patient header displays');
+ assert.equal(find('.view-current-title').text(), 'New Operative Plan', 'New operative plan title is correct');
+ fillIn('.operation-description textarea', visitData.outPatient.OPERATION_DESCRIPTION);
+ typeAheadFillIn('.procedure-description', visitData.outPatient.PROCEDURE_SPLINT);
+ click('button:contains(Add Procedure)');
+ waitToAppear('.procedure-listing td.procedure-description');
+ fillIn('.admission-instructions textarea', visitData.outPatient.ADMISSION_INSTRUCTIONS);
+ });
+ updateVisitData(assert, 'Plan Saved');
+ andThen(() => {
+ click('[data-test-selector=procedures-tab]');
+ waitToAppear('[data-test-selector=new-procedure-btn]');
+ assert.equal(find('[data-test-selector=new-procedure-btn]').text().trim(), 'New Procedure', 'New Procedure button displayed');
+ click('[data-test-selector=new-procedure-btn]');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('visits/procedures/edit/new?forVisitId') > -1, 'New Procedures URL is visited');
+ typeAheadFillIn('.procedure-description', visitData.outPatient.OPD_PROCEDURE_DESCRIPTION);
+ typeAheadFillIn('.procedure-physician', visitData.outPatient.OPD_PROCEDURE_PHYSICIAN);
+ });
+ updateVisitData(assert, 'Procedure Saved');
+ andThen(() => {
+ click('button:contains(New Lab)');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('/labs/edit/new?forVisitId') > -1, 'New Lab URL is visited');
+ typeAheadFillIn('.test-lab-type', visitData.outPatient.LAB_TYPE);
+ });
+ updateVisitData(assert, 'Lab Request Saved');
+ andThen(() => {
+ click('button:contains(New Imaging)');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('/imaging/edit/new?forVisitId') > -1, 'New Imaging URL is visited');
+ typeAheadFillIn('.imaging-type-input', visitData.outPatient.IMAGING_TYPE);
+ });
+ updateVisitData(assert, 'Imaging Request Saved');
+ andThen(() => {
+ click('button:contains(New Appointment)');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('/appointments/edit/new?forVisitId') > -1, 'New Appointment URL is visited');
+ click('.appointment-all-day input');
+ fillIn('.test-appointment-start input', visitData.outPatient.APPOINTMENT_START_DATE);
+ fillIn('.test-appointment-end input', visitData.outPatient.APPOINTMENT_END_DATE);
+ });
+ updateVisitData(assert, 'Appointment Saved');
+}
+
+function addAdmissionData(assert) {
+ andThen(function() {
+ click('[data-test-selector=notes-tab]');
+ waitToAppear('[data-test-selector=new-note-btn]');
+ click('[data-test-selector=new-note-btn]');
+ });
+ andThen(() => {
+ assert.equal(find('.modal-title').text(), 'New Note for Joe Bagadonuts', 'New Note dialog displays');
+ fillIn('.test-note-content textarea', visitData.admission.NOTE_CONTENT);
+ click('.modal-footer button:contains(Add)');
+ });
+ andThen(function() {
+ waitToDisappear('.modal-dialog');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('visits/edit/') > -1, 'Returns back to visit URL');
+ });
+}
+
+function newReport(assert, type) {
+ andThen(function() {
+ click('[data-test-selector=reports-tab]');
+ waitToAppear('[data-test-selector=report-btn]');
+ assert.equal(find('[data-test-selector=report-btn]').text().trim(), `New ${type} Report`, 'Discharge report can be created for this type of visit');
+ click('[data-test-selector=report-btn]');
+ });
+ andThen(function() {
+ assert.ok(currentURL().indexOf('visits/reports/edit/new') > -1, 'Report url is correct');
+ assert.equal(find('.view-current-title').text(), `New ${type} Report`, `${type} report title displayed correctly`);
+ assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Patient record displays');
+ });
+}
+
+function checkOPDReport(assert) {
+ andThen(() => {
+ assert.equal(find('.patient-id .ps-info-data').text(), 'P00001', 'Patient ID is displayed');
+ assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Patient First Name & Last Name is displayed');
+ assert.equal(find('.test-visit-date .test-visit-date-label').text().trim(), 'Date of Visit:', 'Visit date label displayed');
+ assert.ok(!isEmpty(find('.test-visit-date .test-visit-date-data').text()), 'Visit date is displayed');
+ findWithAssert(`.primary-diagnosis:contains(${visitData.outPatient.PRIMARY_DIAGNOSIS})`);
+ findWithAssert(`.secondary-diagnosis:contains(${visitData.outPatient.SECONDARY_DIAGNOSIS})`);
+ findWithAssert('.test-opd-procedure .test-opd-procedure-label:contains(Procedures)');
+ assert.ok(find('.test-opd-procedure .test-opd-procedure-data').text().indexOf(visitData.outPatient.OPD_PROCEDURE_DESCRIPTION) > -1, 'OPD Procedure is displayed');
+ findWithAssert('.test-labs .test-labs-label:contains(Labs)');
+ assert.ok(find('.test-labs .test-labs-data').text().indexOf(visitData.outPatient.LAB_TYPE) > -1, 'Lab request is displayed');
+ findWithAssert('.test-images .test-images-label:contains(Images)');
+ assert.ok(find('.test-images .test-images-data').text().indexOf(visitData.outPatient.IMAGING_TYPE) > -1, 'Image request is displayed');
+ findWithAssert('.test-operative-plan .test-operative-plan-label:contains(Operative Plan)');
+ findWithAssert('.test-operative-plan .test-operative-plan-description-label:contains(Operation Description:)');
+ assert.equal(find('.test-operative-plan .test-operative-plan-description-data').text(), visitData.outPatient.OPERATION_DESCRIPTION);
+ findWithAssert('.test-operative-plan .test-operative-plan-procedures-label:contains(Planned Procedures:)');
+ assert.equal(find('.test-operative-plan .test-operative-plan-procedures-description').text(), visitData.outPatient.PROCEDURE_SPLINT);
+ findWithAssert('.test-operative-plan .test-operative-plan-instructions-label:contains(Instructions upon Admission:)');
+ assert.equal(find('.test-operative-plan .test-operative-plan-instructions-data').text(), visitData.outPatient.ADMISSION_INSTRUCTIONS, 'Admission Instruction is displayed');
+ });
+}
+
+function checkDischargeReport(assert) {
+ andThen(function() {
+ assert.equal(find('.test-visit-date .test-visit-date-label').text().trim(), 'Admission Date:', 'Visit date label displays as admission');
+ assert.equal(find('.test-visit-date .test-visit-discharge-date-label').text().trim(), 'Discharge Date:', 'Discharge date label displays');
+ findWithAssert('.test-notes .test-notes-label:contains(Notes)');
+ assert.ok(find('.test-notes .test-notes-data').text().indexOf(visitData.admission.NOTE_CONTENT) > -1, 'Notes are displayed');
+ });
+ andThen(function() {
+ click('.panel-footer button:contains(Add)');
+ waitToAppear('.modal-dialog');
+ });
+ andThen(function() {
+ assert.equal(find('.modal-title').text(), 'Warning!!!!', 'Cant save discharge report without entering doctors name');
+ click('button:contains(Ok)');
+ waitToDisappear('.modal-dialog');
+ });
+ andThen(function() {
+ typeAheadFillIn('.plan-surgeon', 'Dr Test');
+ });
+}
+
+function saveReport(assert, type) {
+ andThen(function() {
+ click('.panel-footer button:contains(Add)');
+ waitToAppear('.modal-dialog');
+ });
+ andThen(function() {
+ assert.equal(find('.modal-title').text(), 'Report saved', `${type} report saved successfully`);
+ click('button:contains(Ok)');
+ waitToDisappear('.modal-dialog');
+ });
+ andThen(function() {
+ assert.equal(find('.view-current-title').text(), `Edit ${type} Report`, 'Report title updated correctly');
+ assert.ok(find('.panel-footer button:contains(Print)').is(':visible'), 'Print button is now visible');
+ click('button:contains(Return)');
+ });
+ andThen(function() {
+ assert.ok(currentURL().indexOf('visits/edit/') > -1, 'Visit url is correct');
+ });
+}
+
+function editReport(assert, type) {
+ andThen(function() {
+ click('[data-test-selector=reports-tab]');
+ waitToAppear('[data-test-selector=edit-report-btn]');
+ click('[data-test-selector=edit-report-btn]');
+ });
+ andThen(function() {
+ assert.ok(currentURL().indexOf('visits/reports/edit') > -1, 'Edit report url is correct');
+ assert.equal(find('.patient-name .ps-info-data').text(), 'Joe Bagadonuts', 'Patient record displays');
+ assert.equal(find('.view-current-title').text(), `Edit ${type} Report`, 'Edit report title displayed correctly');
+ assert.ok(find('.panel-footer button:contains(Print)').is(':visible'), 'Print button is on edit visible');
+ });
+}
+
+function updateVisitData(assert, modalTitle) {
+ andThen(() => {
+ click('.panel-footer button:contains(Add)');
+ waitToAppear('.modal-dialog');
+ });
+ andThen(() => {
+ assert.equal(find('.modal-title').text(), modalTitle, `${modalTitle} modal displays`);
+ click('.modal-footer button:contains(Ok)');
+ });
+ andThen(function() {
+ waitToDisappear('.modal-dialog');
+ });
+ andThen(() => {
+ click('button:contains(Return)');
+ });
+ andThen(() => {
+ assert.ok(currentURL().indexOf('visits/edit/') > -1, 'Returns back to visit URL');
+ });
+}
+
+function updateVisit(assert, buttonText, visitType) {
andThen(function() {
+ if (visitType) {
+ select('select[id*="visitType"]', visitType);
+ waitToDisappear('label[for*="display_endDate"]');
+ }
click(`.panel-footer button:contains(${buttonText})`);
waitToAppear('.modal-dialog');
});
diff --git a/tests/unit/mixins/patient-diagnosis-test.js b/tests/unit/mixins/patient-diagnosis-test.js
index 8001771292..11fdf1714e 100644
--- a/tests/unit/mixins/patient-diagnosis-test.js
+++ b/tests/unit/mixins/patient-diagnosis-test.js
@@ -22,6 +22,7 @@ moduleFor('mixin:patient-diagnosis', 'Unit | Mixin | patient-diagnosis', {
'model:patient-note',
'model:procedure',
'model:diagnosis',
+ 'model:report',
'ember-validations@validator:local/acceptance',
'ember-validations@validator:local/presence'
],
diff --git a/tests/unit/models/visit-test.js b/tests/unit/models/visit-test.js
index 601379d135..50db6d0be0 100644
--- a/tests/unit/models/visit-test.js
+++ b/tests/unit/models/visit-test.js
@@ -16,6 +16,7 @@ moduleForModel('visit', 'Unit | Model | visit', {
'model:proc-charge',
'model:vital',
'model:visit',
+ 'model:report',
'service:validations'
]
});