Skip to content

Commit

Permalink
Merge pull request #17 from PiusKariuki/feat/esm-billing-app
Browse files Browse the repository at this point in the history
Kenya EMR's current billing implemenation
  • Loading branch information
PiusKariuki authored Jun 10, 2024
2 parents 32b0971 + da37c44 commit 42a8dc7
Show file tree
Hide file tree
Showing 88 changed files with 2,849 additions and 2,696 deletions.
151 changes: 151 additions & 0 deletions packages/esm-billing-app/__mocks__/visit.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
export const mockCurrentVisit = {
uuid: 'ee527f74-7373-4494-98bc-002c979971d1',
encounters: [],
patient: { uuid: '0b25b92a-add3-4d52-8491-778bec556e02' },
visitType: { uuid: '3371a4d4-f66f-4454-a86d-92c7b3da990c', name: 'Outpatient', display: 'Outpatient' },
attributes: [
{
uuid: 'e1522ecb-d027-4c30-aa25-38698ba18020',
display: 'Source form: 13',
attributeType: {
name: 'Source form',
datatypeClassname: 'org.openmrs.module.kenyaemr.datatype.FormDatatype',
uuid: '8bfab185-6947-4958-b7ab-dfafae1a3e3d',
},
value: {
uuid: '23b4ebbd-29ad-455e-be0e-04aa6bc30798',
display: 'MOH 257 Visit Summary',
name: 'MOH 257 Visit Summary',
description: null,
encounterType: {
uuid: 'a0034eee-1940-4e35-847f-97537a35d05e',
display: 'HIV Consultation',
},
version: '1',
build: null,
published: true,
formFields: [],
retired: false,
resourceVersion: '1.9',
},
},
{
uuid: '5dbb093d-b377-4684-9583-05074ae7187a',
display: 'Payment Method: 28989582-e8c3-46b0-96d0-c249cb06d5c6',
attributeType: {
name: 'Payment Method',
datatypeClassname: 'org.openmrs.customdatatype.datatype.FreeTextDatatype',
uuid: 'e6cb0c3b-04b0-4117-9bc6-ce24adbda802',
},
value: '28989582-e8c3-46b0-96d0-c249cb06d5c6',
},
{
uuid: '85abc096-8524-4c2e-863c-b44c99c144f7',
display: 'Patient Type: false',
attributeType: {
name: 'Patient Type',
datatypeClassname: 'org.openmrs.customdatatype.datatype.FreeTextDatatype',
uuid: '3b9dfac8-9e4d-11ee-8c90-0242ac120002',
},
value: 'false',
},
{
uuid: '7eb402bb-2bf8-43b7-91aa-ee3f5c753de1',
display: 'Visit queue number: CLI-090',
attributeType: {
name: 'Visit queue number',
datatypeClassname: 'org.openmrs.customdatatype.datatype.FreeTextDatatype',
uuid: 'c61ce16f-272a-41e7-9924-4c555d0932c5',
},
value: 'CLI-090',
},
],
location: {
uuid: '233de33e-2778-4f9a-a398-fa09da9daa14',
name: 'Wamagana Health Centre',
display: 'Wamagana Health Centre',
},
startDatetime: '2024-05-29T15:19:00.000+0300',
stopDatetime: '',
};

export const mockBills = [
{
id: 1888,
uuid: '3b784fa7-c124-4710-9152-cad3dbaa19e8',
patientName: ' Test Unit patient',
identifier: 'MGTKYE ',
patientUuid: '0b25b92a-add3-4d52-8491-778bec556e02',
status: 'PENDING',
receiptNumber: '1916-6',
cashier: {
uuid: '693acc9b-734f-488d-b6d2-60368d02cec0',
display: '23797304 - Test Patient',
},
cashPointUuid: '54065383-b4d4-42d2-af4d-d250a1fd2590',
cashPointName: 'OPD Cash Point',
cashPointLocation: 'Moi Teaching Refferal Hospital',
dateCreated: '29 — May — 2024',
lineItems: [
{
uuid: '528c3411-b3b8-41dc-bf88-174b4adc1b5b',
display: 'BillLineItem',
voided: false,
voidReason: null,
item: '',
billableService: '3f5d0684-a280-477e-a67b-2a956a1f6dca:Registration Revist',
quantity: 1,
price: 50,
priceName: 'Default',
priceUuid: '',
lineItemOrder: 0,
paymentStatus: 'PENDING',
order: null,
resourceVersion: '1.8',
},
],
billingService: '3f5d0684-a280-477e-a67b-2a956a1f6dca:Registration Revist',
payments: [],
display: '1916-6',
totalAmount: 50,
},
{
id: 1213,
uuid: '5b633220-9a99-4517-bcdf-c06a7d38dd23',
patientName: ' peter ndungu mairo',
identifier: 'MGTKYE ',
patientUuid: '0b25b92a-add3-4d52-8491-778bec556e02',
status: 'PENDING',
receiptNumber: '1228-6',
cashier: {
uuid: '48b55692-e061-4ffa-b1f2-fd4aaf506224',
display: 'admin - Super User',
},
cashPointUuid: '54065383-b4d4-42d2-af4d-d250a1fd2590',
cashPointName: 'OPD Cash Point',
cashPointLocation: 'Moi Teaching Refferal Hospital',
dateCreated: '15 — May — 2024',
lineItems: [
{
uuid: '16cc8b90-f2d4-4907-a3d5-0f57486e5dcf',
display: 'BillLineItem',
voided: false,
voidReason: null,
item: '',
billableService: '3f5d0684-a280-477e-a67b-2a956a1f6dca:Registration Revist',
quantity: 1,
price: 50,
priceName: 'Default',
priceUuid: '',
lineItemOrder: 0,
paymentStatus: 'PENDING',
order: null,
resourceVersion: '1.8',
},
],
billingService: '3f5d0684-a280-477e-a67b-2a956a1f6dca:Registration Revist',
payments: [],
display: '1228-6',
totalAmount: 50,
},
];
2 changes: 1 addition & 1 deletion packages/esm-billing-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sjthc/esm-billing-app",
"version": "1.0.2",
"version": "1.0.3",
"description": "Billing frontend module for use in O3",
"browser": "dist/sjthc-esm-billing-app.js",
"main": "src/index.ts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import {
Button,
DataTable,
DataTableSkeleton,
Layer,
Pagination,
Table,
TableBody,
TableCell,
DataTable,
TableContainer,
TableExpandedRow,
TableExpandHeader,
TableExpandRow,
Table,
TableHead,
TableHeader,
TableRow,
TableBody,
TableCell,
Tile,
Pagination,
TableExpandHeader,
TableExpandRow,
TableExpandedRow,
Button,
} from '@carbon/react';
import { isDesktop, useConfig, useLayoutType, usePagination } from '@openmrs/esm-framework';
import {
CardHeader,
EmptyDataIllustration,
ErrorState,
launchPatientWorkspace,
usePaginationInfo,
} from '@openmrs/esm-patient-common-lib';
import { Add } from '@carbon/react/icons';
import { isDesktop, useLayoutType, usePagination, launchWorkspace } from '@openmrs/esm-framework';
import { EmptyDataIllustration, ErrorState, usePaginationInfo, CardHeader } from '@openmrs/esm-patient-common-lib';
import { useBills } from '../billing.resource';
import InvoiceTable from '../invoice/invoice-table.component';
import styles from './bill-history.scss';
import { Add } from '@carbon/react/icons';
import { convertToCurrency } from '../helpers';

interface BillHistoryProps {
patientUuid: string;
Expand All @@ -40,10 +33,9 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
const { t } = useTranslation();
const { bills, isLoading, error } = useBills(patientUuid);
const layout = useLayoutType();
const [pageSize, setPageSize] = React.useState(10);
const responsiveSize = isDesktop(layout) ? 'sm' : 'lg';
const { paginated, goTo, results, currentPage } = usePagination(bills);
const { pageSize, defaultCurrency } = useConfig();
const [currentPageSize, setCurrentPageSize] = React.useState(pageSize);
const { paginated, goTo, results, currentPage } = usePagination(bills, pageSize);
const { pageSizes } = usePaginationInfo(pageSize, bills?.length, currentPage, results?.length);

const headerData = [
Expand All @@ -66,12 +58,15 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
];

const setBilledItems = (bill) =>
bill?.lineItems?.reduce((acc, item) => acc + (acc ? ' & ' : '') + (item?.billableService || item?.item || ''), '');
bill.lineItems.reduce(
(acc, item) => acc + (acc ? ' & ' : '') + (item.billableService?.split(':')[1] || item.item?.split(':')[1] || ''),
'',
);

const rowData = results?.map((bill) => ({
id: bill.uuid,
uuid: bill.uuid,
billTotal: convertToCurrency(bill?.totalAmount, defaultCurrency),
billTotal: bill.totalAmount,
visitTime: bill.dateCreated,
identifier: bill.identifier,
billedItems: setBilledItems(bill),
Expand All @@ -97,24 +92,32 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {

if (bills.length === 0) {
return (
<Layer className={styles.emptyStateContainer}>
<Tile className={styles.tile}>
<div className={styles.illo}>
<EmptyDataIllustration />
</div>
<p className={styles.content}>There are no bills to display.</p>
<Button onClick={() => launchPatientWorkspace('billing-form-workspace')} kind="ghost">
{t('launchBillForm', 'Launch bill form')}
</Button>
</Tile>
</Layer>
<>
<CardHeader title={t('patientBilling', 'Patient billing')}>
<></>
</CardHeader>
<Layer>
<Tile className={styles.tile}>
<div className={styles.illo}>
<EmptyDataIllustration />
</div>
<p className={styles.content}>There are no bills to display.</p>
<Button onClick={() => launchWorkspace('billing-form', { workspaceTitle: 'Billing Form' })} kind="ghost">
{t('launchBillForm', 'Launch bill form')}
</Button>
</Tile>
</Layer>
</>
);
}

return (
<>
<CardHeader title={t('billingHistory', 'Billing History')}>
<Button renderIcon={Add} onClick={() => launchPatientWorkspace('billing-form-workspace', {})} kind="ghost">
<div>
<CardHeader title={t('patientBilling', 'Patient billing')}>
<Button
renderIcon={Add}
onClick={() => launchWorkspace('billing-form', { workspaceTitle: 'Billing Form' })}
kind="ghost">
{t('addBill', 'Add bill item(s)')}
</Button>
</CardHeader>
Expand Down Expand Up @@ -153,9 +156,7 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
<React.Fragment key={row.id}>
<TableExpandRow {...getRowProps({ row })}>
{row.cells.map((cell) => (
<TableCell key={cell.id} className={styles.tableCells}>
{cell.value}
</TableCell>
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
</TableExpandRow>
{row.isExpanded ? (
Expand All @@ -180,7 +181,7 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
forwardText={t('nextPage', 'Next page')}
backwardText={t('previousPage', 'Previous page')}
page={currentPage}
pageSize={currentPageSize}
pageSize={pageSize}
pageSizes={pageSizes}
totalItems={bills.length}
className={styles.pagination}
Expand All @@ -189,12 +190,12 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
if (newPage !== currentPage) {
goTo(newPage);
}
setCurrentPageSize(pageSize);
setPageSize(pageSize);
}}
/>
)}
</div>
</>
</div>
);
};

Expand Down
43 changes: 21 additions & 22 deletions packages/esm-billing-app/src/bill-history/bill-history.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@
margin: 2rem 0;
}

.emptyStateContainer,
.loaderContainer {
@extend .container;
}

.billHistoryContainer {
background-color: $ui-02;
border: 1px solid $ui-03;
Expand Down Expand Up @@ -117,7 +112,7 @@

.tile {
text-align: center;
border: 1px solid $ui-03;
// border: 1px solid $ui-03;
}

.filterEmptyState {
Expand Down Expand Up @@ -145,22 +140,26 @@
}

.table {
width: 100%;
table-layout: fixed; // This helps with uniform column sizing
border-collapse: collapse;

td:has(:global(.billingTable)) {
td{
padding: 0.375rem 2rem 0.4375rem !important;
white-space:normal;
text-overflow: unset;
}
}
:global(tr.cds--parent-row.cds--expandable-row + tr[data-child-row]) td {
padding-left: 1rem;
tr[data-child-row] td {
padding-left: 2rem !important;
}
}

.tableCells {
white-space: wrap !important;
}
.billingHeading {
position: relative;
max-width: 400px;
text-align: 'left';
margin-bottom: 40px;
}

.billingHeading::after {
position: absolute;
bottom: -10px;
width: 50px;
height: 5px;
background: green;
content: '';
display: block;
left: 6%;
transform: translatex(-50%);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
import { useBills } from '../billing.resource';
import BillHistory from './bill-history.component';
import { useBills } from '../billing.resource';
import userEvent from '@testing-library/user-event';

const testProps = {
patientUuid: 'some-uuid',
Expand Down
Loading

0 comments on commit 42a8dc7

Please sign in to comment.