Skip to content

Commit

Permalink
feat(Patients): implement financial activity
Browse files Browse the repository at this point in the history
This commit implements the patient financial activity bar on the patient
edit page.  The financial activity gives at a glance the amount of time
a patient has been a client of the hospital and their activity over
time.  It also indicates whether the patient has an outstanding debt or
any financial irregularities.
  • Loading branch information
jniles committed Apr 6, 2018
1 parent 711ffd8 commit e6b6434
Show file tree
Hide file tree
Showing 15 changed files with 498 additions and 175 deletions.
2 changes: 1 addition & 1 deletion client/src/i18n/en/form.json
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@
"TRANSACTION_TYPE": "Transaction Type",
"TRANSFER_ACCOUNT": "Transfer Account",
"TAKE_SNAPSHOT": "Take snapshot",
"TAKE_A_PICTURE": "Take a Pucture",
"TAKE_A_PICTURE": "Take a Picture",
"TYPE": "Type",
"UNCONFIGURED": "Unconfigured",
"UNDEFINED": "Undefined",
Expand Down
70 changes: 39 additions & 31 deletions client/src/i18n/en/patient_records.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
{"PATIENT_RECORDS":{"TITLE":"Patients",
"UPDATE_PICTURE":"Update Patient Photo",
"UPLOAD_PICTURE":"Upload Patient Photo",
"NOT_FOUND":"Unable to find patient with that ID. Please check with your system administrator.",
"DOB_NOT_SPECIFIED":"Only a year of birth was specified during patient registration. This is an approximate date.",
"CHECK_IN":{"TITLE":"Check In",
"SUBMIT":"Check Patient In",
"NOT_RECENT":"This patient has not recently been checked in, check the patient in to track this hospital visit.",
"ORIGINAL":"This patient has never been checked in.",
"RECENT":"Recent Visits",
"ITEM":"Checked in",
"BY":"by",
"REPORT_TITLE":"Patient Checkin Report",
"SUCCESS":"Patient has been checked in"},
"VISITS":{"TITLE":"Patient Visits",
"ADMIT":"Admit Patient",
"ADMISSION_DIAGNOSIS":"Admission Diagnosis",
"ADMISSION":"Admission",
"DISCHARGE":"Discharge Patient",
"ORIGINAL":"This patient has no logged visits.",
"RECENT":"Recent Visits",
"IN_PROGRESS":"In Progress",
"SEARCH_INFO":"The input will search for diagnosis after 3 characters have been typed."},
"FINANCIAL_ACTIVITY":{"ACCOUNT":"Account Number",
"DEBTOR_GROUP":"Debtor Group",
"REPORT_TITLE":"Patient Financial Activity"},
"STAT_TOTAL_PATIENT":"Total Patients",
"STAT_TOTAL_VISIT":"Total Visits",
"IS_COVERED_BY":"is covered by",
"INVOICE_COVERED_BY":"Invoice covered by",
"STAT_TOTAL_NEW":"New Patients"}}
{
"PATIENT_RECORDS":{
"TITLE":"Patients",
"UPDATE_PICTURE":"Update Patient Photo",
"UPLOAD_PICTURE":"Upload Patient Photo",
"NOT_FOUND":"Unable to find patient with that ID. Please check with your system administrator.",
"DOB_NOT_SPECIFIED":"Only a year of birth was specified during patient registration. This is an approximate date.",
"CHECK_IN":{"TITLE":"Check In",
"SUBMIT":"Check Patient In",
"NOT_RECENT":"This patient has not recently been checked in, check the patient in to track this hospital visit.",
"ORIGINAL":"This patient has never been checked in.",
"RECENT":"Recent Visits",
"ITEM":"Checked in",
"BY":"by",
"REPORT_TITLE":"Patient Checkin Report",
"SUCCESS":"Patient has been checked in"},
"VISITS":{
"TITLE":"Patient Visits",
"ADMIT":"Admit Patient",
"ADMISSION_DIAGNOSIS":"Admission Diagnosis",
"ADMISSION":"Admission",
"DISCHARGE":"Discharge Patient",
"ORIGINAL":"This patient has no logged visits.",
"RECENT":"Recent Visits",
"IN_PROGRESS":"In Progress",
"SEARCH_INFO":"The input will search for diagnosis after 3 characters have been typed."
},
"FINANCIAL_ACTIVITY":{
"ACCOUNT":"Account Number",
"DEBTOR_GROUP":"Debtor Group",
"REPORT_TITLE":"Patient Financial Activity"
},
"STAT_TOTAL_PATIENT":"Total Patients",
"STAT_TOTAL_VISIT":"Total Visits",
"IS_COVERED_BY":"is covered by",
"INVOICE_COVERED_BY":"Invoice covered by",
"STAT_TOTAL_NEW":"New Patients"
}
}
14 changes: 14 additions & 0 deletions client/src/js/components/bhPanelOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const bhPanelOverlayTemplate = `
<div class="panel-overlay">
<div class="panel-overlay-container">
<span class="panel-overlay-text" ng-transclude>
</span>
</div>
</div>
`;

angular.module('bhima.components')
.component('bhPanelOverlay', {
transclude : true,
template : bhPanelOverlayTemplate,
});
119 changes: 119 additions & 0 deletions client/src/js/components/bhPatientFinancialActivity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
angular.module('bhima.components')
.component('bhPatientFinancialActivity', {
controller : PatientFinancialActivityCtrl,
templateUrl : 'modules/patients/record/bh-patient-financial-activity.html',
bindings : {
patientUuid : '<',
},
});

PatientFinancialActivityCtrl.$inject = [
'PatientService', 'moment', 'SessionService', 'bhConstants',
];

/**
* @function PatientFinancialActivityCtrl
*
* @description
* This component is responsible for giving an overview of the patient's
* financial situation.
*/
function PatientFinancialActivityCtrl(Patients, moment, Session, Constants) {
const $ctrl = this;

// TODO(@jniles) - add the ability for users to change this
const EXCESSIVE_DEBT_LIMIT = 250000; // FC (enterprise currency)
const OLD_DEBT_LIMIT = 30; // days

this.$onInit = () => {
$ctrl.enterpriseCurrencyId = Session.enterprise.currency_id;
angular.merge($ctrl, { EXCESSIVE_DEBT_LIMIT, OLD_DEBT_LIMIT });

$ctrl.DATE_FORMAT = Constants.dates.format;

$ctrl.loading = true;

Patients.getFinancialActivity($ctrl.patientUuid)
.then(data => {
$ctrl.data = data;

// indicate that the patient does not have a financial history
$ctrl.noFinancialHistory = data.transactions.length === 0;

$ctrl.status = calculateFinancialStatus(data.transactions, data.aggregates);
$ctrl.groups = groupFinancialRecords(data.transactions);

$ctrl.hasWarnings = (
$ctrl.status.hasExcessiveDebt ||
$ctrl.status.hasCreditorBalance ||
$ctrl.status.hasOldDebt
);
})
.finally(() => {
$ctrl.loading = false;
});
};


/**
* @function calculateFinancialStatus
*
* @description
*
*/
function calculateFinancialStatus(transactions, totals) {
const hasExcessiveDebt = (totals.balance >= EXCESSIVE_DEBT_LIMIT);
const hasDebtorBalance = (totals.balance > 0);
const hasCreditorBalance = (totals.balance < 0);

// hasOldDebt checks if there is debt and it is too old
const isOldDebt = (date) => (moment().diff(date, 'days') >= OLD_DEBT_LIMIT);
const hasOldDebt = hasDebtorBalance && isOldDebt(totals.until);

const isInGoodStanding = !(hasExcessiveDebt || hasOldDebt);

return {
hasExcessiveDebt,
hasCreditorBalance,
hasOldDebt,
isInGoodStanding,
};
}

// returns IV, CP, VO by parsing on the document id
const ident = (record) => record.document.slice(0, 2);

// make a record object for tracking records
const mkRecord = () => ({
count : 0,
lastDate : null,
lastUuid : null,
lastAmount : 0,
totalAmount : 0,
});

function groupFinancialRecords(transactions) {
// summary of all the types of financial records
const records = {
VO : mkRecord(),
IV : mkRecord(),
CP : mkRecord(),
};

transactions.forEach(record => {
const summary = records[ident(record)];
summary.count++;
summary.lastDate = record.trans_date;
summary.lastUuid = record.record_uuid;
summary.lastAmount = Math.abs(record.balance);
summary.totalAmount += record.balance;
});

const isCreditBalance = balance => balance < 0;
records.VO.isCreditBalance = isCreditBalance(records.VO.totalAmount);
records.IV.isCreditBalance = isCreditBalance(records.IV.totalAmount);
records.CP.isCreditBalance = isCreditBalance(records.CP.totalAmount);

return records;
}
}
24 changes: 24 additions & 0 deletions client/src/less/bhima-bootstrap.less
Original file line number Diff line number Diff line change
Expand Up @@ -432,3 +432,27 @@ div.ui-grid-cell .form-group.has-error input.ng-invalid {
.text-bold {
font-weight: bold;
}

/* note: panels must have position:relative set on them */
.panel-overlay {
top: 0;
left: 0;
right : 0;
bottom : 0;
background-color: rgba(255,255,255, 0.95);
position : absolute;
z-index: 1000;
}

.panel-overlay-container {
height: 100%;
width: 100%;
position: relative;
}

.panel-overlay-text {
top: 50%;
left: 50%;
position: absolute;
transform: translate(-50%, -50%);
}
Loading

0 comments on commit e6b6434

Please sign in to comment.