@openmrs/esm-billing-app 1.0.2-pre.834 → 1.0.2-pre.838
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/4300.js +1 -1
- package/dist/4344.js +1 -1
- package/dist/4344.js.map +1 -1
- package/dist/4739.js +1 -1
- package/dist/4739.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-billing-app.js.buildmanifest.json +12 -12
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/bill-history/bill-history.component.tsx +3 -3
- package/src/bill-item-actions/edit-bill-item.modal.tsx +1 -1
- package/src/bill-item-actions/edit-bill-item.test.tsx +7 -7
- package/src/billable-services/bill-waiver/bill-selection.component.tsx +1 -1
- package/src/billable-services/bill-waiver/bill-waiver-form.component.tsx +2 -2
- package/src/billable-services/bill-waiver/patient-bills.component.tsx +6 -6
- package/src/billable-services/billable-services-home.component.tsx +3 -3
- package/src/billable-services/billable-services.component.tsx +10 -6
- package/src/billable-services/billable-services.test.tsx +4 -4
- package/src/billable-services/cash-point/add-cash-point.modal.tsx +1 -1
- package/src/billable-services/cash-point/cash-point-configuration.component.tsx +2 -2
- package/src/billable-services/create-edit/add-billable-service.component.tsx +8 -10
- package/src/billable-services/create-edit/add-billable-service.test.tsx +4 -4
- package/src/billable-services/create-edit/edit-billable-service.modal.tsx +1 -1
- package/src/billable-services/dashboard/service-metrics.component.tsx +6 -1
- package/src/billable-services/payment-modes/add-payment-mode.modal.tsx +3 -3
- package/src/billable-services/payment-modes/payment-modes-config.component.tsx +2 -2
- package/src/billing-form/billing-checkin-form.component.tsx +1 -1
- package/src/billing-form/billing-checkin-form.test.tsx +2 -2
- package/src/billing-form/billing-form.component.tsx +8 -8
- package/src/billing-form/visit-attributes/visit-attributes-form.component.tsx +1 -1
- package/src/bills-table/bills-table.component.tsx +3 -3
- package/src/invoice/invoice-table.component.tsx +2 -2
- package/src/invoice/invoice-table.test.tsx +1 -1
- package/src/invoice/invoice.component.tsx +7 -9
- package/src/invoice/payments/payments.component.tsx +3 -3
- package/src/invoice/payments/payments.test.tsx +5 -5
- package/src/invoice/printable-invoice/printable-invoice.component.tsx +4 -4
- package/src/metrics-cards/metrics-cards.component.tsx +6 -1
- package/src/modal/require-payment.modal.tsx +1 -1
- package/translations/en.json +73 -72
|
@@ -547,9 +547,9 @@
|
|
|
547
547
|
"initial": false,
|
|
548
548
|
"entry": false,
|
|
549
549
|
"recorded": false,
|
|
550
|
-
"size":
|
|
550
|
+
"size": 8971,
|
|
551
551
|
"sizes": {
|
|
552
|
-
"javascript":
|
|
552
|
+
"javascript": 8971
|
|
553
553
|
},
|
|
554
554
|
"names": [],
|
|
555
555
|
"idHints": [],
|
|
@@ -561,7 +561,7 @@
|
|
|
561
561
|
"4300.js"
|
|
562
562
|
],
|
|
563
563
|
"auxiliaryFiles": [],
|
|
564
|
-
"hash": "
|
|
564
|
+
"hash": "141498f23f6a5d9f",
|
|
565
565
|
"childrenByOrder": {}
|
|
566
566
|
},
|
|
567
567
|
{
|
|
@@ -591,9 +591,9 @@
|
|
|
591
591
|
"initial": false,
|
|
592
592
|
"entry": false,
|
|
593
593
|
"recorded": false,
|
|
594
|
-
"size":
|
|
594
|
+
"size": 1177948,
|
|
595
595
|
"sizes": {
|
|
596
|
-
"javascript":
|
|
596
|
+
"javascript": 1177906,
|
|
597
597
|
"consume-shared": 42
|
|
598
598
|
},
|
|
599
599
|
"names": [],
|
|
@@ -607,7 +607,7 @@
|
|
|
607
607
|
"auxiliaryFiles": [
|
|
608
608
|
"4344.js.map"
|
|
609
609
|
],
|
|
610
|
-
"hash": "
|
|
610
|
+
"hash": "c7fea203c75a305b",
|
|
611
611
|
"childrenByOrder": {}
|
|
612
612
|
},
|
|
613
613
|
{
|
|
@@ -686,9 +686,9 @@
|
|
|
686
686
|
"initial": false,
|
|
687
687
|
"entry": false,
|
|
688
688
|
"recorded": false,
|
|
689
|
-
"size":
|
|
689
|
+
"size": 43608,
|
|
690
690
|
"sizes": {
|
|
691
|
-
"javascript":
|
|
691
|
+
"javascript": 43608
|
|
692
692
|
},
|
|
693
693
|
"names": [],
|
|
694
694
|
"idHints": [],
|
|
@@ -702,7 +702,7 @@
|
|
|
702
702
|
"auxiliaryFiles": [
|
|
703
703
|
"4739.js.map"
|
|
704
704
|
],
|
|
705
|
-
"hash": "
|
|
705
|
+
"hash": "0506434628a69e0e",
|
|
706
706
|
"childrenByOrder": {}
|
|
707
707
|
},
|
|
708
708
|
{
|
|
@@ -1236,10 +1236,10 @@
|
|
|
1236
1236
|
"initial": true,
|
|
1237
1237
|
"entry": true,
|
|
1238
1238
|
"recorded": false,
|
|
1239
|
-
"size":
|
|
1239
|
+
"size": 5461402,
|
|
1240
1240
|
"sizes": {
|
|
1241
1241
|
"consume-shared": 210,
|
|
1242
|
-
"javascript":
|
|
1242
|
+
"javascript": 5438746,
|
|
1243
1243
|
"share-init": 336,
|
|
1244
1244
|
"runtime": 22110
|
|
1245
1245
|
},
|
|
@@ -1256,7 +1256,7 @@
|
|
|
1256
1256
|
"auxiliaryFiles": [
|
|
1257
1257
|
"main.js.map"
|
|
1258
1258
|
],
|
|
1259
|
-
"hash": "
|
|
1259
|
+
"hash": "311d3f6d2c9ae9d6",
|
|
1260
1260
|
"childrenByOrder": {}
|
|
1261
1261
|
},
|
|
1262
1262
|
{
|
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"}],"modals":[{"name":"add-cash-point-modal","component":"addCashPointModal"},{"name":"add-payment-mode-modal","component":"addPaymentModeModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"edit-bill-item-modal","component":"editBillLineItemModal"},{"name":"edit-bill-line-item-modal","component":"editBillLineItemModal"},{"name":"edit-billable-service-modal","component":"editBillableServiceModal"},{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"webservices.rest":">=2.24.0","fhir2":">=1.2"},"pages":[{"component":"billableServicesHome","route":"billable-services"}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"},"featureFlag":"billing"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"name":"billing-patient-summary","component":"billingPatientSummary","slot":"patient-chart-billing-dashboard-slot","order":10,"meta":{"columnSpan":4}},{"name":"billing-summary-dashboard-link","component":"billingSummaryDashboardLink","slot":"patient-chart-dashboard-slot","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing history"},"featureFlag":"billing"},{"name":"billable-services-app-menu-item","component":"billableServicesAppMenuItem","slot":"app-menu-item-slot","meta":{"name":"Billable Services"}},{"name":"billing-checkin-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm","featureFlag":"billing"},{"slot":"system-admin-page-card-link-slot","component":"billableServicesCardLink","name":"billable-services-admin-card-link"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"billing-home-tiles-ext","slot":"billing-home-tiles-slot","component":"serviceMetrics"}],"modals":[{"name":"add-cash-point-modal","component":"addCashPointModal"},{"name":"add-payment-mode-modal","component":"addPaymentModeModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"edit-bill-item-modal","component":"editBillLineItemModal"},{"name":"edit-bill-line-item-modal","component":"editBillLineItemModal"},{"name":"edit-billable-service-modal","component":"editBillableServiceModal"},{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces":[{"name":"billing-form-workspace","title":"billingForm","component":"billingFormWorkspace","type":"form"}],"featureFlags":[{"flagName":"billing","label":"Billing module","description":"This feature introduces navigation links on the patient chart and home page to allow accessing the billing module features"}],"version":"1.0.2-pre.838"}
|
package/package.json
CHANGED
|
@@ -81,7 +81,7 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
|
|
|
81
81
|
return (
|
|
82
82
|
<div className={styles.errorContainer}>
|
|
83
83
|
<Layer>
|
|
84
|
-
<ErrorState error={error} headerTitle={t('
|
|
84
|
+
<ErrorState error={error} headerTitle={t('billList', 'Bill list')} />
|
|
85
85
|
</Layer>
|
|
86
86
|
</div>
|
|
87
87
|
);
|
|
@@ -107,7 +107,7 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
|
|
|
107
107
|
<div>
|
|
108
108
|
<CardHeader title={t('billingHistory', 'Billing History')}>
|
|
109
109
|
<Button renderIcon={Add} onClick={() => launchWorkspace('billing-form-workspace', {})} kind="ghost">
|
|
110
|
-
{t('addBill', 'Add bill
|
|
110
|
+
{t('addBill', 'Add bill items')}
|
|
111
111
|
</Button>
|
|
112
112
|
</CardHeader>
|
|
113
113
|
<div className={styles.billHistoryContainer}>
|
|
@@ -122,7 +122,7 @@ const BillHistory: React.FC<BillHistoryProps> = ({ patientUuid }) => {
|
|
|
122
122
|
rows,
|
|
123
123
|
}) => (
|
|
124
124
|
<TableContainer {...getTableContainerProps}>
|
|
125
|
-
<Table className={styles.table} {...getTableProps()} aria-label=
|
|
125
|
+
<Table className={styles.table} {...getTableProps()} aria-label={t('billList', 'Bill list')}>
|
|
126
126
|
<TableHead>
|
|
127
127
|
<TableRow>
|
|
128
128
|
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
|
|
@@ -191,7 +191,7 @@ const EditBillLineItemModal: React.FC<EditBillLineItemModalProps> = ({ bill, clo
|
|
|
191
191
|
className={styles.controlField}
|
|
192
192
|
helperText={t('unitPriceHelperText', 'This is the unit price for this item')}
|
|
193
193
|
id="priceInput"
|
|
194
|
-
labelText={t('
|
|
194
|
+
labelText={t('unitPrice', 'Unit price')}
|
|
195
195
|
readOnly
|
|
196
196
|
value={value}
|
|
197
197
|
/>
|
|
@@ -94,24 +94,24 @@ describe('EditBillItem', () => {
|
|
|
94
94
|
test('renders the form with correct fields and default values', () => {
|
|
95
95
|
render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
|
|
96
96
|
|
|
97
|
-
expect(screen.getByText(
|
|
97
|
+
expect(screen.getByText(/edit bill line item/i)).toBeInTheDocument();
|
|
98
98
|
expect(screen.getByText(/John Doe/)).toBeInTheDocument();
|
|
99
99
|
expect(screen.getByText(/Main Cashpoint/)).toBeInTheDocument();
|
|
100
100
|
expect(screen.getByText(/123456/)).toBeInTheDocument();
|
|
101
|
-
expect(screen.getByRole('spinbutton', { name: /
|
|
102
|
-
expect(screen.getByLabelText(/
|
|
103
|
-
expect(screen.getByText(/
|
|
101
|
+
expect(screen.getByRole('spinbutton', { name: /quantity/i })).toHaveValue(2);
|
|
102
|
+
expect(screen.getByLabelText(/unit price/i)).toHaveValue('100');
|
|
103
|
+
expect(screen.getByText(/total/i)).toHaveTextContent(/200/);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
test('updates total when quantity is changed', async () => {
|
|
107
107
|
const user = userEvent.setup();
|
|
108
108
|
render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
|
|
109
109
|
|
|
110
|
-
const quantityInput = screen.getByRole('spinbutton', { name: /
|
|
110
|
+
const quantityInput = screen.getByRole('spinbutton', { name: /quantity/i });
|
|
111
111
|
await user.clear(quantityInput);
|
|
112
112
|
await user.type(quantityInput, '3');
|
|
113
113
|
|
|
114
|
-
expect(screen.getByText(/
|
|
114
|
+
expect(screen.getByText(/total/i)).toHaveTextContent(/300/);
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
test('submits the form and shows a success notification', async () => {
|
|
@@ -120,7 +120,7 @@ describe('EditBillItem', () => {
|
|
|
120
120
|
|
|
121
121
|
render(<EditBillLineItemModal bill={mockBill} item={mockItem} closeModal={mockCloseModal} />);
|
|
122
122
|
|
|
123
|
-
await user.click(screen.getByText(/
|
|
123
|
+
await user.click(screen.getByText(/save/i));
|
|
124
124
|
|
|
125
125
|
await waitFor(() => {
|
|
126
126
|
expect(mockUpdateBillItems).toHaveBeenCalled();
|
|
@@ -42,7 +42,7 @@ const PatientBillsSelections: React.FC<{ bills: MappedBill; setPatientUuid: (pat
|
|
|
42
42
|
<StructuredListRow head>
|
|
43
43
|
<StructuredListCell head>{t('billItem', 'Bill item')}</StructuredListCell>
|
|
44
44
|
<StructuredListCell head>{t('quantity', 'Quantity')}</StructuredListCell>
|
|
45
|
-
<StructuredListCell head>{t('unitPrice', 'Unit
|
|
45
|
+
<StructuredListCell head>{t('unitPrice', 'Unit price')}</StructuredListCell>
|
|
46
46
|
<StructuredListCell head>{t('total', 'Total')}</StructuredListCell>
|
|
47
47
|
<StructuredListCell head>{getCoreTranslation('actions')}</StructuredListCell>
|
|
48
48
|
</StructuredListRow>
|
|
@@ -68,7 +68,7 @@ const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPat
|
|
|
68
68
|
<section className={styles.billWaiverDescription}>
|
|
69
69
|
<label className={styles.label}>{t('billItems', 'Bill Items')}</label>
|
|
70
70
|
<p className={styles.value}>
|
|
71
|
-
{t('billName', '
|
|
71
|
+
{t('billName', '{{billName}}', {
|
|
72
72
|
billName: lineItems.map((item) => item.item || item.billableService).join(', ') ?? '--',
|
|
73
73
|
})}
|
|
74
74
|
</p>
|
|
@@ -80,7 +80,7 @@ const BillWaiverForm: React.FC<BillWaiverFormProps> = ({ bill, lineItems, setPat
|
|
|
80
80
|
|
|
81
81
|
<Layer className={styles.formControlLayer}>
|
|
82
82
|
<NumberInput
|
|
83
|
-
label={t('amountToWaiveLabel', 'Amount to
|
|
83
|
+
label={t('amountToWaiveLabel', 'Amount to waive')}
|
|
84
84
|
helperText={t('amountToWaiveHelper', 'Specify the amount to be deducted from the bill')}
|
|
85
85
|
aria-label={t('amountToWaiveAriaLabel', 'Enter amount to waive')}
|
|
86
86
|
hideSteppers
|
|
@@ -38,8 +38,8 @@ const PatientBills: React.FC<PatientBillsProps> = ({ patientUuid, bills, setPati
|
|
|
38
38
|
|
|
39
39
|
const tableHeaders = [
|
|
40
40
|
{ header: t('date', 'Date'), key: 'date' },
|
|
41
|
-
{ header: t('billableService', 'Billable
|
|
42
|
-
{ header: t('totalAmount', 'Total
|
|
41
|
+
{ header: t('billableService', 'Billable service'), key: 'billableService' },
|
|
42
|
+
{ header: t('totalAmount', 'Total amount'), key: 'totalAmount' },
|
|
43
43
|
];
|
|
44
44
|
|
|
45
45
|
const tableRows = bills.map((bill) => ({
|
|
@@ -58,7 +58,7 @@ const PatientBills: React.FC<PatientBillsProps> = ({ patientUuid, bills, setPati
|
|
|
58
58
|
<div className={styles.illo}>
|
|
59
59
|
<EmptyDataIllustration />
|
|
60
60
|
</div>
|
|
61
|
-
<p className={styles.content}>{t('
|
|
61
|
+
<p className={styles.content}>{t('noBillToDisplay', 'There are no bills to display for this patient')}</p>
|
|
62
62
|
</Tile>
|
|
63
63
|
</Layer>
|
|
64
64
|
</div>
|
|
@@ -84,13 +84,13 @@ const PatientBills: React.FC<PatientBillsProps> = ({ patientUuid, bills, setPati
|
|
|
84
84
|
getTableContainerProps,
|
|
85
85
|
}) => (
|
|
86
86
|
<TableContainer
|
|
87
|
-
title={t('patientBills', 'Patient
|
|
87
|
+
title={t('patientBills', 'Patient bills')}
|
|
88
88
|
description={t('patientBillsDescription', 'List of patient bills')}
|
|
89
89
|
{...getTableContainerProps()}>
|
|
90
|
-
<Table {...getTableProps()} aria-label=
|
|
90
|
+
<Table {...getTableProps()} aria-label={t('billsTable', 'Bills table')}>
|
|
91
91
|
<TableHead>
|
|
92
92
|
<TableRow>
|
|
93
|
-
<TableExpandHeader enableToggle
|
|
93
|
+
<TableExpandHeader enableToggle {...getExpandHeaderProps()} />
|
|
94
94
|
{headers.map((header, i) => (
|
|
95
95
|
<TableHeader
|
|
96
96
|
key={i}
|
|
@@ -37,12 +37,12 @@ const BillableServiceHome: React.FC = () => {
|
|
|
37
37
|
<SideNavLink onClick={() => handleNavigation('waive-bill')} renderIcon={Money}>
|
|
38
38
|
{t('billWaiver', 'Bill waiver')}
|
|
39
39
|
</SideNavLink>
|
|
40
|
-
<SideNavMenu title={t('billingSettings', 'Billing
|
|
40
|
+
<SideNavMenu title={t('billingSettings', 'Billing settings')} renderIcon={Settings}>
|
|
41
41
|
<SideNavMenuItem onClick={() => handleNavigation('cash-point-config')}>
|
|
42
|
-
{t('cashPointConfig', 'Cash
|
|
42
|
+
{t('cashPointConfig', 'Cash point configuration')}
|
|
43
43
|
</SideNavMenuItem>
|
|
44
44
|
<SideNavMenuItem onClick={() => handleNavigation('payment-modes-config')}>
|
|
45
|
-
{t('paymentModesConfig', 'Payment
|
|
45
|
+
{t('paymentModesConfig', 'Payment modes configuration')}
|
|
46
46
|
</SideNavMenuItem>
|
|
47
47
|
</SideNavMenu>
|
|
48
48
|
</UserHasAccess>
|
|
@@ -57,19 +57,19 @@ const BillableServices = () => {
|
|
|
57
57
|
|
|
58
58
|
const headerData = [
|
|
59
59
|
{
|
|
60
|
-
header: t('serviceName', 'Service
|
|
60
|
+
header: t('serviceName', 'Service name'),
|
|
61
61
|
key: 'serviceName',
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
header: t('shortName', 'Short
|
|
64
|
+
header: t('shortName', 'Short name'),
|
|
65
65
|
key: 'shortName',
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
|
-
header: t('serviceType', 'Service
|
|
68
|
+
header: t('serviceType', 'Service type'),
|
|
69
69
|
key: 'serviceType',
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
|
-
header: t('serviceStatus', 'Service
|
|
72
|
+
header: t('serviceStatus', 'Service status'),
|
|
73
73
|
key: 'status',
|
|
74
74
|
},
|
|
75
75
|
{
|
|
@@ -138,7 +138,11 @@ const BillableServices = () => {
|
|
|
138
138
|
|
|
139
139
|
if (isLoading) {
|
|
140
140
|
return (
|
|
141
|
-
<InlineLoading
|
|
141
|
+
<InlineLoading
|
|
142
|
+
status="active"
|
|
143
|
+
iconDescription={getCoreTranslation('loading')}
|
|
144
|
+
description={t('loading', 'Loading data') + '...'}
|
|
145
|
+
/>
|
|
142
146
|
);
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -174,7 +178,7 @@ const BillableServices = () => {
|
|
|
174
178
|
useZebraStyles={rowData?.length > 1}>
|
|
175
179
|
{({ rows, headers, getHeaderProps, getRowProps, getTableProps }) => (
|
|
176
180
|
<TableContainer>
|
|
177
|
-
<Table {...getTableProps()} aria-label=
|
|
181
|
+
<Table {...getTableProps()} aria-label={t('serviceList', 'Service list')}>
|
|
178
182
|
<TableHead>
|
|
179
183
|
<TableRow>
|
|
180
184
|
{headers.map((header) => (
|
|
@@ -57,10 +57,10 @@ describe('BillableService', () => {
|
|
|
57
57
|
render(<BillableServices />);
|
|
58
58
|
|
|
59
59
|
// Check table headers
|
|
60
|
-
expect(screen.getByText('Service
|
|
61
|
-
expect(screen.getByText('Short
|
|
62
|
-
expect(screen.getByText('Service
|
|
63
|
-
expect(screen.getByText('Service
|
|
60
|
+
expect(screen.getByText('Service name')).toBeInTheDocument();
|
|
61
|
+
expect(screen.getByText('Short name')).toBeInTheDocument();
|
|
62
|
+
expect(screen.getByText('Service type')).toBeInTheDocument();
|
|
63
|
+
expect(screen.getByText('Service status')).toBeInTheDocument();
|
|
64
64
|
|
|
65
65
|
// Check service data
|
|
66
66
|
expect(screen.getByText('Service 1')).toBeInTheDocument();
|
|
@@ -114,7 +114,7 @@ const AddCashPointModal: React.FC<AddCashPointModalProps> = ({ closeModal, onCas
|
|
|
114
114
|
<TextInput
|
|
115
115
|
id="cash-point-name"
|
|
116
116
|
labelText={t('cashPointName', 'Cash Point Name')}
|
|
117
|
-
placeholder={t('cashPointNamePlaceholder', '
|
|
117
|
+
placeholder={t('cashPointNamePlaceholder', 'For example, Pharmacy Cash Point')}
|
|
118
118
|
invalid={!!errors.name}
|
|
119
119
|
invalidText={errors.name?.message}
|
|
120
120
|
{...field}
|
|
@@ -61,9 +61,9 @@ const CashPointConfiguration: React.FC = () => {
|
|
|
61
61
|
return (
|
|
62
62
|
<div className={styles.container}>
|
|
63
63
|
<div className={styles.card}>
|
|
64
|
-
<CardHeader title={t('cashPointHistory', 'Cash
|
|
64
|
+
<CardHeader title={t('cashPointHistory', 'Cash point history')}>
|
|
65
65
|
<Button renderIcon={Add} onClick={handleAddCashPoint} kind="ghost">
|
|
66
|
-
{t('addNewCashPoint', 'Add
|
|
66
|
+
{t('addNewCashPoint', 'Add new cash point')}
|
|
67
67
|
</Button>
|
|
68
68
|
</CardHeader>
|
|
69
69
|
<div>
|
|
@@ -79,7 +79,7 @@ const createBillableServiceSchema = (t: TFunction) => {
|
|
|
79
79
|
if (isNaN(numValue) || numValue <= 0) {
|
|
80
80
|
ctx.addIssue({
|
|
81
81
|
code: z.ZodIssueCode.custom,
|
|
82
|
-
message: t('
|
|
82
|
+
message: t('priceMustBePositive', 'Price must be greater than 0'),
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
}),
|
|
@@ -246,7 +246,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
|
|
|
246
246
|
<InlineLoading
|
|
247
247
|
status="active"
|
|
248
248
|
iconDescription={t('loadingDescription', 'Loading')}
|
|
249
|
-
description={t('
|
|
249
|
+
description={t('loading', 'Loading data') + '...'}
|
|
250
250
|
/>
|
|
251
251
|
);
|
|
252
252
|
}
|
|
@@ -256,8 +256,8 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
|
|
|
256
256
|
<Stack gap={5}>
|
|
257
257
|
<h4>
|
|
258
258
|
{serviceToEdit
|
|
259
|
-
? t('
|
|
260
|
-
: t('
|
|
259
|
+
? t('editBillableService', 'Edit billable service')
|
|
260
|
+
: t('addBillableService', 'Add billable service')}
|
|
261
261
|
</h4>
|
|
262
262
|
<section>
|
|
263
263
|
{serviceToEdit ? (
|
|
@@ -294,7 +294,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
|
|
|
294
294
|
value={field.value || ''}
|
|
295
295
|
id="serviceShortName"
|
|
296
296
|
type="text"
|
|
297
|
-
labelText={t('
|
|
297
|
+
labelText={t('shortName', 'Short name')}
|
|
298
298
|
placeholder={t('enterServiceShortName', 'Enter service short name')}
|
|
299
299
|
maxLength={MAX_NAME_LENGTH}
|
|
300
300
|
invalid={!!errors.shortName}
|
|
@@ -310,7 +310,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
|
|
|
310
310
|
<Search
|
|
311
311
|
ref={searchInputRef}
|
|
312
312
|
id="conceptsSearch"
|
|
313
|
-
labelText={t('
|
|
313
|
+
labelText={t('associatedConcept', 'Associated concept')}
|
|
314
314
|
placeholder={t('searchConcepts', 'Search associated concept')}
|
|
315
315
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setSearchTerm(e.target.value)}
|
|
316
316
|
onClear={() => {
|
|
@@ -349,9 +349,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
|
|
|
349
349
|
return (
|
|
350
350
|
<Layer>
|
|
351
351
|
<Tile className={styles.emptyResults}>
|
|
352
|
-
<span>
|
|
353
|
-
{t('noResultsFor', 'No results for')} <strong>"{debouncedSearchTerm}"</strong>
|
|
354
|
-
</span>
|
|
352
|
+
<span>{t('noResultsFor', 'No results for {searchTerm}', { searchTerm: debouncedSearchTerm })}</span>
|
|
355
353
|
</Tile>
|
|
356
354
|
</Layer>
|
|
357
355
|
);
|
|
@@ -413,7 +411,7 @@ const AddBillableService: React.FC<AddBillableServiceProps> = ({
|
|
|
413
411
|
id={`price-${index}`}
|
|
414
412
|
invalid={!!errors?.payment?.[index]?.price}
|
|
415
413
|
invalidText={errors?.payment?.[index]?.price?.message}
|
|
416
|
-
label={t('sellingPrice', 'Selling
|
|
414
|
+
label={t('sellingPrice', 'Selling price')}
|
|
417
415
|
placeholder={t('enterSellingPrice', 'Enter selling price')}
|
|
418
416
|
min={0}
|
|
419
417
|
step={0.01}
|
|
@@ -85,10 +85,10 @@ const fillRequiredFields = async (user, options: FillOptions = {}) => {
|
|
|
85
85
|
const { serviceName = 'Test Service Name', shortName = 'Test Short Name', skipPrice = false } = options;
|
|
86
86
|
|
|
87
87
|
if (serviceName) {
|
|
88
|
-
await user.type(screen.getByRole('textbox', { name: /Service
|
|
88
|
+
await user.type(screen.getByRole('textbox', { name: /Service name/i }), serviceName);
|
|
89
89
|
}
|
|
90
90
|
if (shortName) {
|
|
91
|
-
await user.type(screen.getByRole('textbox', { name: /Short
|
|
91
|
+
await user.type(screen.getByRole('textbox', { name: /Short name/i }), shortName);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
await user.click(screen.getByRole('combobox', { name: /Service type/i }));
|
|
@@ -114,7 +114,7 @@ describe('AddBillableService', () => {
|
|
|
114
114
|
const mockOnClose = jest.fn();
|
|
115
115
|
renderAddBillableService({ onClose: mockOnClose });
|
|
116
116
|
|
|
117
|
-
const formTitle = screen.getByRole('heading', { name: /Add
|
|
117
|
+
const formTitle = screen.getByRole('heading', { name: /Add billable service/i });
|
|
118
118
|
expect(formTitle).toBeInTheDocument();
|
|
119
119
|
|
|
120
120
|
await fillRequiredFields(user);
|
|
@@ -188,7 +188,7 @@ describe('AddBillableService', () => {
|
|
|
188
188
|
renderAddBillableService();
|
|
189
189
|
|
|
190
190
|
// Fill all fields except service name
|
|
191
|
-
await user.type(screen.getByRole('textbox', { name: /Short
|
|
191
|
+
await user.type(screen.getByRole('textbox', { name: /Short name/i }), 'Test Short Name');
|
|
192
192
|
|
|
193
193
|
await user.click(screen.getByRole('combobox', { name: /Service type/i }));
|
|
194
194
|
await user.click(screen.getByRole('option', { name: /Lab service/i }));
|
|
@@ -20,7 +20,7 @@ const EditBillableServiceModal: React.FC<EditBillableServiceModalProps> = ({
|
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
22
|
<>
|
|
23
|
-
<ModalHeader closeModal={closeModal} title={t('billableService', 'Billable
|
|
23
|
+
<ModalHeader closeModal={closeModal} title={t('billableService', 'Billable service')} />
|
|
24
24
|
<ModalBody>
|
|
25
25
|
<AddBillableService
|
|
26
26
|
serviceToEdit={serviceToEdit}
|
|
@@ -2,6 +2,7 @@ import React, { useMemo } from 'react';
|
|
|
2
2
|
import { InlineLoading } from '@carbon/react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { ErrorState } from '@openmrs/esm-patient-common-lib';
|
|
5
|
+
import { getCoreTranslation } from '@openmrs/esm-framework';
|
|
5
6
|
import { useBillableServices } from '../billable-service.resource';
|
|
6
7
|
import Card from '../../metrics-cards/card.component';
|
|
7
8
|
import styles from '../../metrics-cards/metrics-cards.scss';
|
|
@@ -22,7 +23,11 @@ export default function ServiceMetrics() {
|
|
|
22
23
|
if (isLoading) {
|
|
23
24
|
return (
|
|
24
25
|
<section className={styles.container}>
|
|
25
|
-
<InlineLoading
|
|
26
|
+
<InlineLoading
|
|
27
|
+
status="active"
|
|
28
|
+
iconDescription={getCoreTranslation('loading')}
|
|
29
|
+
description={t('loadingServiceMetrics', 'Loading service metrics') + '...'}
|
|
30
|
+
/>
|
|
26
31
|
</section>
|
|
27
32
|
);
|
|
28
33
|
}
|
|
@@ -81,8 +81,8 @@ const AddPaymentModeModal: React.FC<AddPaymentModeModalProps> = ({ closeModal, o
|
|
|
81
81
|
render={({ field }) => (
|
|
82
82
|
<TextInput
|
|
83
83
|
id="payment-mode-name"
|
|
84
|
-
labelText={t('
|
|
85
|
-
placeholder={t('paymentModeNamePlaceholder', '
|
|
84
|
+
labelText={t('paymentModeNameLabel', 'Payment Mode Name')}
|
|
85
|
+
placeholder={t('paymentModeNamePlaceholder', 'For example, Cash, Credit Card')}
|
|
86
86
|
invalid={!!errors.name}
|
|
87
87
|
invalidText={errors.name?.message}
|
|
88
88
|
{...field}
|
|
@@ -96,7 +96,7 @@ const AddPaymentModeModal: React.FC<AddPaymentModeModalProps> = ({ closeModal, o
|
|
|
96
96
|
<TextInput
|
|
97
97
|
id="payment-mode-description"
|
|
98
98
|
labelText={t('description', 'Description')}
|
|
99
|
-
placeholder={t('descriptionPlaceholder', '
|
|
99
|
+
placeholder={t('descriptionPlaceholder', 'For example, Used for all cash transactions')}
|
|
100
100
|
invalid={!!errors.description}
|
|
101
101
|
invalidText={errors.description?.message}
|
|
102
102
|
{...field}
|
|
@@ -71,9 +71,9 @@ const PaymentModesConfig: React.FC = () => {
|
|
|
71
71
|
return (
|
|
72
72
|
<div className={styles.container}>
|
|
73
73
|
<div className={styles.card}>
|
|
74
|
-
<CardHeader title={t('paymentModeHistory', 'Payment
|
|
74
|
+
<CardHeader title={t('paymentModeHistory', 'Payment mode history')}>
|
|
75
75
|
<Button renderIcon={Add} onClick={handleAddPaymentMode} kind="ghost">
|
|
76
|
-
{t('addNewPaymentMode', 'Add
|
|
76
|
+
{t('addNewPaymentMode', 'Add new payment mode')}
|
|
77
77
|
</Button>
|
|
78
78
|
</CardHeader>
|
|
79
79
|
<DataTable rows={rowData} headers={headerData} isSortable size="lg">
|
|
@@ -101,7 +101,7 @@ const BillingCheckInForm: React.FC<BillingCheckInFormProps> = ({ patientUuid, se
|
|
|
101
101
|
<InlineNotification
|
|
102
102
|
kind="error"
|
|
103
103
|
lowContrast
|
|
104
|
-
title={t('billErrorService', '
|
|
104
|
+
title={t('billErrorService', 'Billing service error')}
|
|
105
105
|
subtitle={t('errorLoadingBillServices', 'Error loading bill services')}
|
|
106
106
|
/>
|
|
107
107
|
);
|
|
@@ -132,8 +132,8 @@ describe('BillingCheckInForm', () => {
|
|
|
132
132
|
mockUseCashPoint.mockReturnValueOnce({ cashPoints: [], isLoading: false, error });
|
|
133
133
|
renderBillingCheckinForm();
|
|
134
134
|
|
|
135
|
-
expect(screen.getByText(
|
|
136
|
-
expect(screen.getByText(
|
|
135
|
+
expect(screen.getByText(/billing service error/i)).toBeInTheDocument();
|
|
136
|
+
expect(screen.getByText(/error loading bill services/i)).toBeInTheDocument();
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
test('should render the form correctly and generate the required payload', async () => {
|
|
@@ -95,8 +95,8 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
95
95
|
for (const item of selectedItems) {
|
|
96
96
|
if (item.availablePaymentMethods && item.availablePaymentMethods.length > 1 && !item.selectedPaymentMethod) {
|
|
97
97
|
showSnackbar({
|
|
98
|
-
title: t('validationError', 'Validation
|
|
99
|
-
subtitle: t('
|
|
98
|
+
title: t('validationError', 'Validation error'),
|
|
99
|
+
subtitle: t('paymentMethodRequired', 'Payment method is required for all items'),
|
|
100
100
|
kind: 'error',
|
|
101
101
|
});
|
|
102
102
|
return false;
|
|
@@ -138,8 +138,8 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
138
138
|
closeWorkspace();
|
|
139
139
|
mutate((key) => typeof key === 'string' && key.startsWith(url), undefined, { revalidate: true });
|
|
140
140
|
showSnackbar({
|
|
141
|
-
title: t('saveBill', 'Save
|
|
142
|
-
subtitle: t('
|
|
141
|
+
title: t('saveBill', 'Save bill'),
|
|
142
|
+
subtitle: t('billProcessedSuccessfully', 'Bill processed successfully'),
|
|
143
143
|
kind: 'success',
|
|
144
144
|
});
|
|
145
145
|
} catch (error) {
|
|
@@ -162,8 +162,8 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
162
162
|
<InlineNotification
|
|
163
163
|
kind="error"
|
|
164
164
|
lowContrast
|
|
165
|
-
title={t('
|
|
166
|
-
subtitle={
|
|
165
|
+
title={t('errorLoadingBillableServices', 'Error loading billable services')}
|
|
166
|
+
subtitle={error?.message}
|
|
167
167
|
/>
|
|
168
168
|
) : (
|
|
169
169
|
<ComboBox
|
|
@@ -176,7 +176,7 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
176
176
|
)}
|
|
177
177
|
{selectedItems && selectedItems.length > 0 && (
|
|
178
178
|
<div className={styles.selectedItemsContainer}>
|
|
179
|
-
<h4>{t('selectedItems', 'Selected
|
|
179
|
+
<h4>{t('selectedItems', 'Selected items')}</h4>
|
|
180
180
|
{selectedItems.map((item) => (
|
|
181
181
|
<div key={item.uuid} className={styles.itemCard}>
|
|
182
182
|
<div className={styles.itemHeader}>
|
|
@@ -218,7 +218,7 @@ const BillingForm: React.FC<BillingFormProps> = ({ patientUuid, closeWorkspace }
|
|
|
218
218
|
</div>
|
|
219
219
|
) : (
|
|
220
220
|
<div className={styles.controlSection}>
|
|
221
|
-
<label>{t('unitPrice', 'Unit
|
|
221
|
+
<label>{t('unitPrice', 'Unit price')}</label>
|
|
222
222
|
<span className={styles.priceDisplay}>{convertToCurrency(item.price, defaultCurrency)}</span>
|
|
223
223
|
</div>
|
|
224
224
|
)}
|
|
@@ -100,7 +100,7 @@ const VisitAttributesForm: React.FC<VisitAttributesFormProps> = ({ setAttributes
|
|
|
100
100
|
<InlineLoading
|
|
101
101
|
status="active"
|
|
102
102
|
iconDescription={t('loadingDescription', 'Loading')}
|
|
103
|
-
description={t('loading', 'Loading data...'
|
|
103
|
+
description={t('loading', 'Loading data') + '...'}
|
|
104
104
|
/>
|
|
105
105
|
);
|
|
106
106
|
}
|