Skip to content

Commit

Permalink
refactor billing form and add uat backend
Browse files Browse the repository at this point in the history
  • Loading branch information
ODORA0 committed Feb 21, 2024
1 parent c6be57d commit 22927c8
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 93 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"prettier": "prettier --config prettier.config.js --write \"src/**/*.{ts,tsx,css,scss}\" \"e2e/**/*.ts\"",
"release": "lerna version --no-git-tag-version",
"serve": "webpack serve --mode=development",
"start": "openmrs develop",
"start": "openmrs develop --backend https://uat.kenyahmis.org/ ",
"test-e2e": "playwright test",
"test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests",
"test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js",
Expand Down
249 changes: 157 additions & 92 deletions src/billing-form/billing-form.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,93 +15,140 @@ import {
import styles from './billing-form.scss';
import { useTranslation } from 'react-i18next';
import { showSnackbar } from '@openmrs/esm-framework';
import { useFetchSearchResults, processBillItems } from '../billing.resource'; // Corrected the import path
import { useFetchSearchResults, processBillItems } from '../billing.resource';
import { mutate } from 'swr';

type BillItem = {
uuid: string;
Item: string;
Qnty: number;
Price: number;
Total: number;
category: string;
};

type BillingFormProps = {
patientUuid: string;
closeWorkspace: () => void;
};

const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }) => {
const { t } = useTranslation();
const [GrandTotal, setGrandTotal] = useState<number>(0);
const [searchOptions, setSearchOptions] = useState<BillItem[]>([]);
const [BillItems, setBillItems] = useState<BillItem[]>([]);
const [searchVal, setSearchVal] = useState<string>('');
const [category, setCategory] = useState<string>('');

const numberRef = useRef<HTMLInputElement>(null);
const [grandTotal, setGrandTotal] = useState(0);
const [searchOptions, setSearchOptions] = useState([]);
const [billItems, setBillItems] = useState([]);
const [searchVal, setSearchVal] = useState('');
const [category, setCategory] = useState('');

const toggleSearch = (choiceSelected: string) => {
setSearchVal('');
setSearchOptions([]);
const toggleSearch = (choiceSelected) => {
(document.getElementById('searchField') as HTMLInputElement).disabled = false;
setCategory(choiceSelected === 'Stock Item' ? 'Stock Item' : 'Service');
};

const calculateTotal = (event: React.ChangeEvent<HTMLInputElement>, itemName: string) => {
const Qnty = parseInt(event.target.value);
const price = BillItems.find((item) => item.Item.toLowerCase() === itemName.toLowerCase())?.Price || 0;
const total = price * Qnty;
const calculateTotal = (event, itemName) => {
const Qnty = event.target.value;
const price = document.getElementById(`${event.target.id}Price`).innerHTML;
const total = parseInt(price) * Qnty;

const updatedBillItems = BillItems.map((item) =>
item.Item.toLowerCase() === itemName.toLowerCase() ? { ...item, Qnty, Total: total } : item,
);
const updatedItems = billItems.map((item) => {
if (item.Item.toLowerCase().includes(itemName.toLowerCase())) {
item.Qnty = Qnty;
item.Total = total;
}
return item;
});

setBillItems(updatedBillItems);
setBillItems(updatedItems);

const grandTotal = updatedBillItems.reduce((acc, curr) => acc + curr.Total, 0);
setGrandTotal(grandTotal);
const totals = Array.from(document.querySelectorAll('[id$="Total"]'));
let addUpTotals = 0;
totals.forEach((tot) => {
addUpTotals += parseInt(tot.innerHTML);
});
setGrandTotal(addUpTotals);
};

const addItemToBill = (item: BillItem) => {
const existingItemIndex = BillItems.findIndex((existingItem) => existingItem.Item === item.Item);

if (existingItemIndex !== -1) {
const updatedBillItems = [...BillItems];
updatedBillItems[existingItemIndex].Qnty += 1;
updatedBillItems[existingItemIndex].Total =
updatedBillItems[existingItemIndex].Price * updatedBillItems[existingItemIndex].Qnty;
setBillItems(updatedBillItems);
} else {
setBillItems((prevItems) => [...prevItems, { ...item, Qnty: 1, Total: item.Price }]);
}
const calculateTotalAfterAddBillItem = () => {
const sum = billItems.reduce((acc, item) => acc + item.Price, 0);
setGrandTotal(sum);
};

const addItemToBill = (event, itemid, itemname, itemcategory, itemPrice) => {
const newItem = {
uuid: itemid,
Item: itemname,
Qnty: 1,
Price: itemPrice,
Total: itemPrice,
category: itemcategory,
};

setGrandTotal((prevTotal) => prevTotal + item.Price);
setSearchVal('');
setBillItems([...billItems, newItem]);
setSearchOptions([]);
calculateTotalAfterAddBillItem();
(document.getElementById('searchField') as HTMLInputElement).value = '';
};

const { data, error, isLoading, isValidating } = useFetchSearchResults(searchVal, category);

const filterItems = (val) => {
setSearchVal(val);

if (!isLoading && data) {
const res = data as { results: any[] };

const options = res.results.map((o) => {
if (o.commonName && o.commonName !== '') {
return {
uuid: o.uuid || '',
Item: o.commonName,
Qnty: 1,
Price: 10,
Total: 10,
category: 'StockItem',
};
} else if (o.name.toLowerCase().includes(val.toLowerCase())) {
return {
uuid: o.uuid || '',
Item: o.name,
Qnty: 1,
Price: o.servicePrices[0].price,
Total: o.servicePrices[0].price,
category: 'Service',
};
}
});

setSearchOptions(options.filter((option) => option)); // Filter out undefined/null values
}
};

const postBillItems = () => {
const bill = {
cashPoint: '54065383-b4d4-42d2-af4d-d250a1fd2590',
cashier: 'f9badd80-ab76-11e2-9e96-0800200c9a66',
lineItems: BillItems.map((item) => ({
[item.category === 'StockItem' ? 'item' : 'billableService']: item.uuid,
quantity: item.Qnty,
lineItems: [],
payments: [],
patient: patientUuid,
status: 'PENDING',
};

billItems.forEach((item) => {
const lineItem: any = {
quantity: parseInt(item.Qnty),
price: item.Price,
priceName: 'Default',
priceUuid: '7b9171ac-d3c1-49b4-beff-c9902aee5245',
lineItemOrder: 0,
paymentStatus: 'PENDING',
})),
payments: [],
patient: patientUuid,
status: 'PENDING',
};
};

if (item.category === 'StockItem') {
lineItem.item = item.uuid;
} else {
lineItem.billableService = item.uuid;
}

bill.lineItems.push(lineItem);
});

const url = `/ws/rest/v1/cashier/bill`;
processBillItems(bill).then(
() => {
closeWorkspace();
mutate((key) => typeof key === 'string' && key.startsWith(url), undefined, { revalidate: true });
showSnackbar({
title: t('billItems', 'Save Bill'),
subtitle: 'Bill processing has been successful',
Expand All @@ -122,31 +169,39 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
name="radio-button-group"
defaultSelected="radio-1"
className={styles.billingItem}
onChange={({ value }) => toggleSearch(value)}>
onChange={toggleSearch}>
<RadioButton labelText={t('stockItem', 'Stock Item')} value="Stock Item" id="radio-1" />
<RadioButton labelText={t('service', 'Service')} value="Service" id="radio-2" />
</RadioButtonGroup>

<Search
id="searchField"
size="lg"
placeholder="Find your drugs here..."
labelText="Search"
disabled={!category}
closeButtonLabelText="Clear search input"
onChange={(e) => setSearchVal(e.target.value)}
className={styles.billingItem}
/>

<ul className={styles.searchContent}>
{searchOptions.map((row) => (
<li key={row.uuid} className={styles.searchItem}>
<Button onClick={() => addItemToBill(row)} style={{ background: 'inherit', color: 'black' }}>
{row.Item} Qnty.{row.Qnty} Ksh.{row.Price}
</Button>
</li>
))}
</ul>
<div>
<Search
id="searchField"
size="lg"
placeholder="Find your drugs here..."
labelText="Search"
disabled
closeButtonLabelText="Clear search input"
onChange={() => {}}
className={styles.billingItem}
onKeyUp={(e) => {
filterItems(e.target.value);
}}
/>

<ul className={styles.searchContent}>
{searchOptions.map((row) => (
<li key={row.uuid} className={styles.searchItem}>
<Button
id={row.uuid}
onClick={(e) => addItemToBill(e, row.uuid, row.Item, row.category, row.Price)}
style={{ background: 'inherit', color: 'black' }}>
{row.Item} Qnty.{row.Qnty} Ksh.{row.Price}
</Button>
</li>
))}
</ul>
</div>

<Table aria-label="sample table" className={styles.billingItem}>
<TableHead>
Expand All @@ -158,28 +213,38 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
</TableRow>
</TableHead>
<TableBody>
{BillItems.map((row) => (
<TableRow key={row.uuid}>
<TableCell>{row.Item}</TableCell>
<TableCell>
<input
type="number"
className="form-control"
min={0}
max={100}
value={row.Qnty}
onChange={(e) => calculateTotal(e, row.Item)}
/>
</TableCell>
<TableCell>{row.Price}</TableCell>
<TableCell className="totalValue">{row.Total}</TableCell>
</TableRow>
))}
{billItems && Array.isArray(billItems) ? (
billItems.map((row) => (
<TableRow>
<TableCell>{row.Item}</TableCell>
<TableCell>
<input
type="number"
className="form-control"
id={row.Item}
min={0}
max={100}
value={row.Qnty}
onChange={(e) => {
calculateTotal(e, row.Item);
row.Qnty = e.target.value;
}}
/>
</TableCell>
<TableCell id={row.Item + 'Price'}>{row.Price}</TableCell>
<TableCell id={row.Item + 'Total'} className="totalValue">
{row.Total}
</TableCell>
</TableRow>
))
) : (
<p>Loading...</p>
)}
<TableRow>
<TableCell />
<TableCell />
<TableCell></TableCell>
<TableCell></TableCell>
<TableCell style={{ fontWeight: 'bold' }}>Grand Total:</TableCell>
<TableCell id="GrandTotalSum">{GrandTotal}</TableCell>
<TableCell id="GrandTotalSum">{grandTotal}</TableCell>
</TableRow>
</TableBody>
</Table>
Expand Down

0 comments on commit 22927c8

Please sign in to comment.