Skip to content

Commit

Permalink
KHP3-7165 - feat/Print item transactions (Bin Card and Stock Card) (#246
Browse files Browse the repository at this point in the history
)

* first strike

* Added Bin Card Printout on Item Transactions

* Fixed recommanded areas

* Fixed logo printing
  • Loading branch information
PatrickWaweru authored Dec 16, 2024
1 parent 3010dc7 commit 615910e
Show file tree
Hide file tree
Showing 14 changed files with 491 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"lodash-es": "^4.17.21",
"react-hook-form": "^7.45.4",
"react-image-annotate": "^1.8.0",
"react-to-print": "^2.14.13",
"yup": "^1.2.0",
"zod": "^3.22.2"
},
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import StockSources from './stock-sources/stock-sources.component';
import StockLocations from './stock-locations/stock-locations.component';
import StockReports from './stock-reports/report-list/stock-reports.component';
import StockSettings from './stock-settings/stock-settings.component';
import TransactionsPrintPreview from './stock-items/add-stock-item/transactions/printout/transactions-print-preview.modal';
const moduleName = '@openmrs/esm-stock-management-app';

const options = {
Expand Down Expand Up @@ -126,7 +127,7 @@ export const deletePackagingUnitButton = getSyncLifecycle(deletePackagingUnitMod
});

export const stockManagementAppMenuItem = getSyncLifecycle(appMenu, options);

export const transactionPrintPreviewModal = getSyncLifecycle(TransactionsPrintPreview, options)
export function startupApp() {
defineConfigSchema(moduleName, configSchema);
}
6 changes: 5 additions & 1 deletion src/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@
{
"name": "stock-operation-dialog",
"component": "stockOperationModal"
},
{
"name": "transactions-print-preview-modal",
"component": "transactionPrintPreviewModal"
}
],
"pages": [
Expand All @@ -206,4 +210,4 @@
"route": "stock-management"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import styles from './printable-transaction-footer.scss';
import { useTranslation } from 'react-i18next';
import dayjs from 'dayjs';
import { formatDate, useSession } from '@openmrs/esm-framework';

type PrintableFooterProps = {
title: string;
};

const PrintableTransactionFooter: React.FC<PrintableFooterProps> = ({ title }) => {
const { t } = useTranslation();
const session = useSession();

return (
<div className={styles.container}>
<p className={styles.itemFooter}>{title}</p>
<p className={styles.footDescription}>
{t(
'generatedMessage',
'The card has been electronically generated and is a valid document. It was created by {{userName}} on {{date}}',
{
userName: `${session?.user?.display}`,
// date: dayjs().format('DD-MM-YYYY'),
// time: dayjs().format('hh:mm A'),
date: `${formatDate(new Date(), { mode: 'standard', noToday: true })}`,
},
)}
</p>
</div>
);
};

export default PrintableTransactionFooter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@use '@carbon/colors';
@use '@carbon/layout';
@use '@carbon/type';

.container {
display: flex;
flex-direction: column;
width: 100%;
bottom: 0;
padding: layout.$spacing-01;
justify-content: center;
}

.itemFooter {
padding: layout.$spacing-01 layout.$spacing-05;
@include type.type-style('body-compact-02');
color: colors.$cool-gray-90;
}

.footDescription {
@include type.type-style('legal-01');
padding: layout.$spacing-01 layout.$spacing-05;
color: colors.$cool-gray-70;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import styles from './printable-transaction-header.scss';
import { useConfig } from '@openmrs/esm-framework';
import { useTranslation } from 'react-i18next';
import startCase from 'lodash-es/startCase';

interface PrintableTransactionHeaderProps {
itemName: string;
}

const PrintableTransactionHeader: React.FC<PrintableTransactionHeaderProps> = ({ itemName }) => {
const { t } = useTranslation();
const { logo } = useConfig({ externalModuleName: '@kenyaemr/esm-login-app' });

return (
<div className={styles.container}>
<div className={styles.printableHeader}>
<p className={styles.heading}>{t('bincard', 'Bin Card')}</p>
{logo?.src ? (
<img className={styles.img} height={60} width={250} src={logo.src} alt={logo.alt} />
) : logo?.name ? (
logo.name
) : (
// OpenMRS Logo
<svg
className={styles.img}
role="img"
width={110}
height={40}
viewBox="0 0 380 119"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M40.29 40.328a27.755 27.755 0 0 1 19.688-8.154c7.669 0 14.613 3.102 19.647 8.116l.02-18.54A42.835 42.835 0 0 0 59.978 17c-7.089 0-13.813 1.93-19.709 4.968l.021 18.36ZM79.645 79.671a27.744 27.744 0 0 1-19.684 8.154c-7.67 0-14.614-3.101-19.651-8.116l-.02 18.54A42.857 42.857 0 0 0 59.96 103a42.833 42.833 0 0 0 19.672-4.751l.013-18.578ZM40.328 79.696c-5.038-5.037-8.154-11.995-8.154-19.685 0-7.669 3.102-14.612 8.116-19.65l-18.54-.02A42.85 42.85 0 0 0 17 60.012a42.819 42.819 0 0 0 4.752 19.672l18.576.013ZM79.634 40.289a27.753 27.753 0 0 1 8.154 19.688 27.744 27.744 0 0 1-8.117 19.646l18.542.02a42.842 42.842 0 0 0 4.749-19.666c0-7.09-1.714-13.779-4.751-19.675l-18.577-.013ZM156.184 60.002c0-8.748-6.118-15.776-15.025-15.776-8.909 0-15.025 7.028-15.025 15.776 0 8.749 6.116 15.78 15.025 15.78 8.907 0 15.025-7.031 15.025-15.78Zm-34.881 0c0-11.482 8.318-19.958 19.856-19.958 11.536 0 19.855 8.477 19.855 19.959 0 11.484-8.319 19.964-19.855 19.964-11.538 0-19.856-8.48-19.856-19.965ZM179.514 75.54c5.507 0 9.05-4.14 9.05-9.482 0-5.341-3.543-9.483-9.05-9.483-5.505 0-9.046 4.142-9.046 9.483 0 5.342 3.541 9.482 9.046 9.482ZM166.22 53.306h4.248v3.704h.11c2.344-2.725 5.449-4.36 9.154-4.36 8.014 0 13.408 5.67 13.408 13.408 0 7.63-5.613 13.406-12.752 13.406-4.58 0-8.231-2.29-9.81-5.178h-.11V90.87h-4.248V53.306ZM217.773 63.768c-.163-4.305-3-7.193-7.686-7.193-4.685 0-7.79 2.888-8.335 7.193h16.021Zm3.653 10.412c-3.001 3.868-6.596 5.284-11.339 5.284-8.01 0-12.914-5.993-12.914-13.406 0-7.901 5.559-13.407 13.08-13.407 7.196 0 12.096 4.906 12.096 13.354v1.362h-20.597c.325 4.413 3.704 8.173 8.335 8.173 3.65 0 6.105-1.307 8.12-3.868l3.219 2.508ZM227.854 59.356c0-2.346-.216-4.36-.216-6.05h4.031c0 1.363.11 2.777.11 4.195h.11c1.144-2.505 4.306-4.85 8.5-4.85 6.705 0 9.699 4.252 9.699 10.41v15.748h-4.248v-15.31c0-4.253-1.856-6.924-5.833-6.924-5.503 0-7.903 3.979-7.903 9.811V78.81h-4.25V59.356ZM259.211 41.008h6.708L278.8 70.791h.107l12.982-29.782h6.549v37.99h-4.506V47.124h-.106L280.192 79h-2.738l-13.629-31.875h-.107V79h-4.507V41.01ZM312.392 57.752h4.023c4.992 0 11.487 0 11.487-6.282 0-5.47-4.776-6.276-9.177-6.276h-6.333v12.558Zm-4.506-16.744h9.711c7.352 0 15.132 1.072 15.132 10.462 0 5.527-3.594 9.125-9.495 10.037L334.018 79h-5.525l-10.304-17.063h-5.797V79h-4.506V41.01ZM358.123 47.712c-1.506-2.413-4.187-3.486-6.926-3.486-3.973 0-8.1 1.88-8.1 6.385 0 3.49 1.931 5.047 7.994 6.98 5.903 1.878 11.377 3.809 11.377 11.267 0 7.567-6.495 11.11-13.36 11.11-4.402 0-9.125-1.45-11.7-5.262l3.862-3.165c1.61 2.794 4.83 4.24 8.105 4.24 3.862 0 8.263-2.253 8.263-6.601 0-4.669-3.165-5.474-9.928-7.728-5.366-1.771-9.442-4.134-9.442-10.463 0-7.298 6.277-10.945 12.929-10.945 4.241 0 7.836 1.178 10.625 4.45l-3.699 3.218Z"
/>
</svg>
)}
</div>

<div className={styles.printableBody}>
<div className={styles.transactionDetails}>
<p className={styles.itemHeading}>{t('itemname', 'Item Name')}</p>
<p className={styles.itemLabel}>{startCase(itemName)}</p>
</div>
</div>
</div>
);
};

export default PrintableTransactionHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@use '@carbon/colors';
@use '@carbon/layout';
@use '@carbon/type';

.container {
padding: 0 1rem 2rem;
border-bottom: 1px solid #ebedf2;
margin-bottom: 2rem;
}

.printableBody {
display: flex;
flex-direction: row;
justify-content: space-between;
}

.printableHeader {
display: flex;
flex-direction: row;
}

.img {
display: flex;
margin-left: auto;
}

.transactionDetails {
display: flex;
width: 50%;
flex-direction: column;
}

.facilityDetails {
display: flex;
flex-flow: column wrap;
text-align: right;
}

.heading {
font-size: 40px;
text-transform: uppercase;
margin-bottom: layout.$spacing-05;
}

.facilityName {
@include type.type-style('heading-compact-02');
font-weight: bold;
color: colors.$green-70;
}

.itemHeading {
@include type.type-style('body-compact-02');
margin-bottom: 0.25rem;
font-weight: bold;
color: colors.$cool-gray-90;
}

.itemLabel {
@include type.type-style('body-compact-02');
color: colors.$cool-gray-90;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
@use '@carbon/colors';
@use '@carbon/layout';
@use '@carbon/type';

.printableInvoiceContainer {
display: flex;
flex-direction: row;
}

.container {
margin-top: layout.$spacing-05;
}

.itemsContainer {
display: flex;
flex-direction: column;
width: 96%;
padding: layout.$spacing-05;
margin: layout.$spacing-05;
font-size: 6px;
}

.detailsContainer {
margin: layout.$spacing-05 0;
width: 20%;
}

.tableContainer {
margin-bottom: layout.$spacing-05;
font-size: 6px;
}

.totalContainer {
display: flex;
flex-direction: column;
}

.item {
margin: layout.$spacing-04;
}

.itemHeading {
@include type.type-style('label-02');
font-style: bold;
color: colors.$cool-gray-90;
margin-bottom: layout.$spacing-01;
}

.itemValue {
@include type.type-style('legal-01');
color: colors.$cool-gray-90;
}

.itemTotal {
border-bottom: solid 0.00125rem colors.$cool-gray-10;
padding: layout.$spacing-02;
}

.itemLabel {
float: right;
@include type.type-style('label-01');
}

.tableBody {
font-size: 8px;
}

.printButton {
padding: layout.$spacing-01;
margin: layout.$spacing-01;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { Button, Stack, ComboButton, MenuItem } from '@carbon/react';
import { Printer } from '@carbon/react/icons';
import { useTranslation } from 'react-i18next';
import { useStockItem } from '../../../stock-items.resource';
import { showModal } from '@openmrs/esm-framework';
import styles from './printable-transaction.scss';

type Props = {
itemUuid: string;
columns: any;
data: any;
};

const TransactionsPrintAction: React.FC<Props> = ({ columns, data, itemUuid }) => {
const { t } = useTranslation();

const { item: stockItem, isLoading: isStockItemLoading } = useStockItem(itemUuid);

const handleClick = () => {
// stockItem.drugName || stockItem.conceptName || ''
const dispose = showModal('transactions-print-preview-modal', {
onClose: () => dispose(),
title: stockItem.drugName || stockItem.conceptName || '',
columns,
data,
});
};

return (
<>
<ComboButton label="Print">
<MenuItem
label={t('printStockCard', 'Print Stock Card')}
renderIcon={(props) => <Printer size={24} {...props} />}
iconDescription="Print Stock Card"
/>
<MenuItem
label={t('printBinCard', 'Print Bin Card')}
renderIcon={(props) => <Printer size={24} {...props} />}
iconDescription="Print Bin Card"
onClick={handleClick}
disabled={isStockItemLoading}
/>
</ComboButton>
</>
);
};

export default TransactionsPrintAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useRef } from 'react';
import TransactionsPrintout from './transactions-printout.component';
import { ModalBody, ModalHeader, ModalFooter, Button } from '@carbon/react';
import { useTranslation } from 'react-i18next';
import { useReactToPrint } from 'react-to-print';
type Props = {
onClose?: () => void;
title?: string;
columns: any;
data: any;
};

const TransactionsPrintPreview: React.FC<Props> = ({ onClose, title, columns, data }) => {
const { t } = useTranslation();
const ref = useRef<HTMLDivElement>(null);

const handlePrint = useReactToPrint({
content: () => ref.current,
});
return (
<>
<ModalHeader closeModal={onClose} title={t('printbincard', 'Print Bin Card')} />
<ModalBody>
<div ref={ref}>
<TransactionsPrintout title={title} columns={columns} data={data} />
</div>
</ModalBody>
<ModalFooter>
<Button kind="secondary" onClick={onClose}>
{t('cancel', 'Cancel')}
</Button>
<Button type="button" onClick={handlePrint}>
{t('print', 'Print')}
</Button>
</ModalFooter>
</>
);
};

export default TransactionsPrintPreview;
Loading

0 comments on commit 615910e

Please sign in to comment.