@kenyaemr/esm-billing-app 5.4.2-pre.2135 → 5.4.2-pre.2138

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.
Files changed (42) hide show
  1. package/.turbo/turbo-build.log +113 -85
  2. package/dist/574.js +1 -1
  3. package/dist/919.js +1 -0
  4. package/dist/919.js.map +1 -0
  5. package/dist/{746.js → 933.js} +3 -3
  6. package/dist/{746.js.map → 933.js.map} +1 -1
  7. package/dist/kenyaemr-esm-billing-app.js +1 -1
  8. package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +86 -86
  9. package/dist/main.js +3 -3
  10. package/dist/main.js.map +1 -1
  11. package/dist/routes.json +1 -1
  12. package/package.json +1 -1
  13. package/src/bill-deposit/components/dashboard/bill-deposit-dashboard.component.tsx +35 -0
  14. package/src/bill-deposit/components/forms/add-deposit.workspace.scss +26 -0
  15. package/src/bill-deposit/components/forms/add-deposit.workspace.tsx +212 -0
  16. package/src/{billing-form/bill-deposit/bill-deposit.scss → bill-deposit/components/forms/deposit-transactions/deposit-transaction.workspace.scss} +10 -17
  17. package/src/bill-deposit/components/forms/deposit-transactions/deposit-transaction.workspace.tsx +254 -0
  18. package/src/bill-deposit/components/modal/delete-deposit.modal.tsx +58 -0
  19. package/src/bill-deposit/components/modal/reverse-transaction.modal.tsx +59 -0
  20. package/src/bill-deposit/components/search/bill-deposit-search.component.tsx +106 -0
  21. package/src/bill-deposit/components/search/bill-deposit-search.scss +107 -0
  22. package/src/bill-deposit/components/search/components/deposit-table.tsx +150 -0
  23. package/src/bill-deposit/components/search/components/patient-info.tsx +38 -0
  24. package/src/bill-deposit/components/search/components/patient-search.tsx +24 -0
  25. package/src/bill-deposit/components/search/components/transaction-list/transaction-list.component.tsx +65 -0
  26. package/src/bill-deposit/components/search/components/transaction-list/transaction-list.scss +5 -0
  27. package/src/bill-deposit/constants/bill-deposit.constants.ts +25 -0
  28. package/src/bill-deposit/hooks/useBillDeposit.ts +43 -0
  29. package/src/bill-deposit/styles/bill-deposit-dashboard.scss +11 -0
  30. package/src/bill-deposit/types/bill-deposit.types.ts +61 -0
  31. package/src/bill-deposit/utils/bill-deposit.utils.ts +94 -0
  32. package/src/index.ts +23 -2
  33. package/src/past-patient-bills/patient-bills-dashboard/empty-patient-bill.component.tsx +29 -12
  34. package/src/past-patient-bills/patient-bills-dashboard/patient-bills-dashboard.scss +1 -0
  35. package/src/root.component.tsx +2 -0
  36. package/src/routes.json +22 -3
  37. package/src/types/index.ts +1 -0
  38. package/translations/en.json +3 -0
  39. package/dist/912.js +0 -1
  40. package/dist/912.js.map +0 -1
  41. package/src/billing-form/bill-deposit/bill-deposit.workspace.tsx +0 -236
  42. /package/dist/{746.js.LICENSE.txt → 933.js.LICENSE.txt} +0 -0
@@ -0,0 +1,61 @@
1
+ import { type Patient } from '@openmrs/esm-framework';
2
+
3
+ export interface BillDeposit {
4
+ uuid: string;
5
+ display: string;
6
+ patient: Patient;
7
+ amount: number;
8
+ depositType: string;
9
+ status: string;
10
+ referenceNumber: string;
11
+ description: string;
12
+ transactions: Array<BillDepositTransaction>;
13
+ dateCreated: string;
14
+ voided: boolean;
15
+ availableBalance: number;
16
+ }
17
+
18
+ export interface BillDepositTransaction {
19
+ uuid: string;
20
+ display: string;
21
+ amount: number;
22
+ transactionType: string;
23
+ dateCreated: string;
24
+ reason?: string;
25
+ voided: boolean;
26
+ }
27
+
28
+ export interface DepositFormData {
29
+ amount: number;
30
+ depositType: string;
31
+ referenceNumber: string;
32
+ description: string;
33
+ status: string;
34
+ }
35
+
36
+ export interface BillDepositWorkspaceProps {
37
+ patientUuid: string;
38
+ patient: Patient;
39
+ }
40
+
41
+ export interface CreateDepositPayload {
42
+ patient: string;
43
+ amount: number;
44
+ depositType: string;
45
+ referenceNumber: string;
46
+ description: string;
47
+ status: string;
48
+ }
49
+
50
+ export type FormattedDeposit = {
51
+ id: string;
52
+ depositType: string;
53
+ amount: number;
54
+ status: string;
55
+ dateCreated: string;
56
+ referenceNumber: string;
57
+ availableBalance: number;
58
+ patient: Patient;
59
+ description: string;
60
+ transactions: Array<BillDepositTransaction>;
61
+ };
@@ -0,0 +1,94 @@
1
+ import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
2
+ import { type BillDeposit, type CreateDepositPayload } from '../types/bill-deposit.types';
3
+ import { MAX_REFERENCE_NUMBER_COUNTER } from '../constants/bill-deposit.constants';
4
+
5
+ /**
6
+ * Generates a unique reference number for bill deposits
7
+ * Format: [Location Initials][YYMMDD][HHMMSS][Counter]
8
+ * Example: RDK240315143022001 for "Railways Dispensary (Kisumu)"
9
+ */
10
+ let counter = 0;
11
+
12
+ export const generateReferenceNumber = (locationDisplay: string): string => {
13
+ // Extract location initials including parenthetical part
14
+ // e.g., "Railways Dispensary (Kisumu)" -> "RDK"
15
+ const locationInitials = locationDisplay
16
+ .replace(/[()]/g, '')
17
+ .split(' ')
18
+ .map((word) => word[0])
19
+ .join('')
20
+ .toUpperCase();
21
+
22
+ // Get current date and time in format YYMMDDHHMMSS
23
+ const now = new Date();
24
+ const dateTime = now.toISOString().slice(2, 19).replace(/[-:]/g, '');
25
+
26
+ // Generate unique code using counter
27
+ counter = (counter + 1) % MAX_REFERENCE_NUMBER_COUNTER;
28
+ const uniqueCode = counter.toString().padStart(3, '0');
29
+
30
+ return `${locationInitials}${dateTime}${uniqueCode}`;
31
+ };
32
+
33
+ /**
34
+ * Saves a new bill deposit
35
+ */
36
+ export const saveDeposit = async (deposit: CreateDepositPayload | Partial<BillDeposit>, uuid?: string) => {
37
+ const url = `${restBaseUrl}/cashier/deposit` + (uuid ? `/${uuid}` : '');
38
+ return await openmrsFetch(url, {
39
+ method: 'POST',
40
+ body: deposit,
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ },
44
+ });
45
+ };
46
+
47
+ /**
48
+ * Deletes a bill deposit
49
+ */
50
+ export const deleteDeposit = async (uuid: string) => {
51
+ const url = `${restBaseUrl}/cashier/deposit/${uuid}`;
52
+ return await openmrsFetch(url, {
53
+ method: 'DELETE',
54
+ });
55
+ };
56
+
57
+ /**
58
+ * Formats a deposit amount with currency symbol
59
+ */
60
+ export const formatDepositAmount = (amount: number): string => {
61
+ return new Intl.NumberFormat('en-US', {
62
+ style: 'currency',
63
+ currency: 'KES',
64
+ }).format(amount);
65
+ };
66
+
67
+ /**
68
+ * Validates a deposit amount
69
+ */
70
+ export const validateDepositAmount = (amount: number): boolean => {
71
+ return amount > 0 && amount <= 100000000; // Assuming max deposit is 100M
72
+ };
73
+
74
+ /**
75
+ * Add a bill deposit transaction
76
+ */
77
+ export const addDepositTransaction = async (depositUuid: string, transaction: Record<string, string | number>) => {
78
+ const url = `${restBaseUrl}/cashier/deposit/${depositUuid}/transaction`;
79
+ return await openmrsFetch(url, {
80
+ method: 'POST',
81
+ body: JSON.stringify(transaction),
82
+ headers: {
83
+ 'Content-Type': 'application/json',
84
+ },
85
+ });
86
+ };
87
+
88
+ /**
89
+ * Reverses a bill deposit transaction
90
+ */
91
+ export const reverseTransaction = async (depositUuid: string, transactionUuid: string) => {
92
+ const url = `${restBaseUrl}/cashier/deposit/${depositUuid}/transaction/${transactionUuid}`;
93
+ return await openmrsFetch(url, { method: 'DELETE' });
94
+ };
package/src/index.ts CHANGED
@@ -17,7 +17,8 @@ import rootComponent from './root.component';
17
17
  import BillingForm from './billing-form/billing-form.component';
18
18
  import BillingCheckInForm from './billing-form/billing-checkin-form.component';
19
19
  import BillHistory from './bill-history/bill-history.component';
20
- import BillDepositWorkspace from './billing-form/bill-deposit/bill-deposit.workspace';
20
+
21
+ // Bill Deposit Components
21
22
 
22
23
  // Benefits Package Components
23
24
  import BenefitsPackage from './benefits-package/benefits-package.component';
@@ -66,6 +67,13 @@ import { CreatePaymentPoint } from './payment-points/create-payment-point.compon
66
67
  import { ClockIn } from './payment-points/payment-point/clock-in.modal';
67
68
  import { ClockOut } from './payment-points/payment-point/clock-out.modal';
68
69
 
70
+ // Bill Deposit Components
71
+ import BillDepositSearch from './bill-deposit/components/search/bill-deposit-search.component';
72
+ import AddDepositWorkspace from './bill-deposit/components/forms/add-deposit.workspace';
73
+ import DeleteDepositModal from './bill-deposit/components/modal/delete-deposit.modal';
74
+ import ReverseTransactionModal from './bill-deposit/components/modal/reverse-transaction.modal';
75
+ import DepositTransactionWorkspace from './bill-deposit/components/forms/deposit-transactions/deposit-transaction.workspace';
76
+
69
77
  // Translation
70
78
  export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
71
79
 
@@ -167,6 +175,14 @@ export const preAuthRequestsDashboardLink = getSyncLifecycle(
167
175
  options,
168
176
  );
169
177
 
178
+ // Bill Deposit Links
179
+ export const billDepositDashboardLink = getSyncLifecycle(
180
+ createLeftPanelLink({
181
+ name: 'bill-deposit',
182
+ title: 'Bill Deposit',
183
+ }),
184
+ options,
185
+ );
170
186
  export const benefitsPackageDashboardLink = getSyncLifecycle(
171
187
  createDashboardLink({
172
188
  ...benefitsPackageDashboardMeta,
@@ -181,7 +197,6 @@ export const root = getSyncLifecycle(rootComponent, options);
181
197
  export const billingPatientSummary = getSyncLifecycle(BillHistory, options);
182
198
  export const billingCheckInForm = getSyncLifecycle(BillingCheckInForm, options);
183
199
  export const billingForm = getSyncLifecycle(BillingForm, options);
184
- export const billDepositWorkspace = getSyncLifecycle(BillDepositWorkspace, options);
185
200
 
186
201
  // Bill Manager Components
187
202
  export const deleteBillableServiceModal = getSyncLifecycle(DeleteBillableServiceModal, options);
@@ -232,6 +247,12 @@ export const bulkImportBillableServicesModal = getSyncLifecycle(BulkImportBillab
232
247
  export const claimsOverview = getSyncLifecycle(ClaimsManagementOverview, options);
233
248
  export const manageClaimRequestModal = getSyncLifecycle(ManageClaimRequest, options);
234
249
 
250
+ // Bill Deposit Components
251
+ export const billDepositSearch = getSyncLifecycle(BillDepositSearch, options);
252
+ export const addDepositWorkspace = getSyncLifecycle(AddDepositWorkspace, options);
253
+ export const deleteDepositModal = getSyncLifecycle(DeleteDepositModal, options);
254
+ export const depositTransactionWorkspace = getSyncLifecycle(DepositTransactionWorkspace, options);
255
+ export const reverseTransactionModal = getSyncLifecycle(ReverseTransactionModal, options);
235
256
  // App Startup
236
257
  export function startupApp() {
237
258
  defineConfigSchema(moduleName, configSchema);
@@ -2,23 +2,40 @@ import React from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import styles from './patient-bills-dashboard.scss';
4
4
  import { EmptySvg } from './empty-svg.component';
5
-
6
- type EmptyPatientBillProps = {
5
+ import { Button } from '@carbon/react';
6
+ import { Add } from '@carbon/react/icons';
7
+ type BaseEmptyPatientBillProps = {
7
8
  title?: string;
8
9
  subTitle?: string;
9
10
  };
10
- const EmptyPatientBill: React.FC<EmptyPatientBillProps> = ({ title, subTitle }) => {
11
+
12
+ type WithLaunchForm = BaseEmptyPatientBillProps & {
13
+ launchForm: () => void;
14
+ buttonText: string;
15
+ };
16
+
17
+ type WithoutLaunchForm = BaseEmptyPatientBillProps & {
18
+ launchForm?: never;
19
+ buttonText?: never;
20
+ };
21
+
22
+ type EmptyPatientBillProps = WithLaunchForm | WithoutLaunchForm;
23
+
24
+ const EmptyPatientBill: React.FC<EmptyPatientBillProps> = ({ title, subTitle, launchForm, buttonText }) => {
11
25
  const { t } = useTranslation();
12
26
  return (
13
- <>
14
- <div className={styles.emptyStateContainer}>
15
- <EmptySvg />
16
- <p className={styles.title}>{title ?? t('searchForAPatient', 'Search for a patient')}</p>
17
- <p className={styles.subTitle}>
18
- {subTitle ?? t('enterAnIdNumberOrPatientName', 'Enter an ID number or patient name')}
19
- </p>
20
- </div>
21
- </>
27
+ <div className={styles.emptyStateContainer}>
28
+ <EmptySvg />
29
+ <p className={styles.title}>{title ?? t('searchForAPatient', 'Search for a patient')}</p>
30
+ <p className={styles.subTitle}>
31
+ {subTitle ?? t('enterAnIdNumberOrPatientName', 'Enter an ID number or patient name')}
32
+ </p>
33
+ {launchForm && buttonText && (
34
+ <Button onClick={launchForm} kind="ghost" renderIcon={Add}>
35
+ {buttonText}
36
+ </Button>
37
+ )}
38
+ </div>
22
39
  );
23
40
  };
24
41
 
@@ -24,6 +24,7 @@
24
24
  min-height: 300px;
25
25
  background-color: colors.$gray-10;
26
26
  row-gap: layout.$spacing-02;
27
+ border: 1px solid colors.$gray-20;
27
28
 
28
29
  & form {
29
30
  border: none;
@@ -13,6 +13,7 @@ import PaymentModeHome from './payment-modes/payment-mode-home.component';
13
13
  import { ClockInBoundary } from './payment-points/clock-in-boundary.component';
14
14
  import { PaymentPoint } from './payment-points/payment-point/payment-point.component';
15
15
  import { PaymentPoints } from './payment-points/payment-points.component';
16
+ import BillDepositDashboard from './bill-deposit/components/dashboard/bill-deposit-dashboard.component';
16
17
 
17
18
  const RootComponent: React.FC = () => {
18
19
  const baseName = window.getOpenmrsSpaBase() + 'home/billing';
@@ -46,6 +47,7 @@ const RootComponent: React.FC = () => {
46
47
  <Route path="/charge-items" element={<ChargeItemsDashboard />} />
47
48
  <Route path="/payment-modes" element={<PaymentModeHome />} />
48
49
  <Route path="/billable-exemptions" element={<BillableExemptions />} />
50
+ <Route path="/bill-deposit" element={<BillDepositDashboard />} />
49
51
  </Routes>
50
52
  </BrowserRouter>
51
53
  );
package/src/routes.json CHANGED
@@ -150,6 +150,11 @@
150
150
  "order": 0,
151
151
  "slot": "billing-dashboard-link-slot"
152
152
  },
153
+ {
154
+ "component": "billDepositDashboardLink",
155
+ "name": "bill-deposit-dashboard-link",
156
+ "slots": ["billing-dashboard-link-slot","billing-dashboard-group-nav-slot"]
157
+ },
153
158
  {
154
159
  "component": "paymentHistoryLink",
155
160
  "name": "payment-history-link",
@@ -284,9 +289,15 @@
284
289
  "type": "other-form"
285
290
  },
286
291
  {
287
- "name": "bill-deposit-workspace",
288
- "component": "billDepositWorkspace",
289
- "title": "Bill Deposit Workspace",
292
+ "name": "add-deposit-workspace",
293
+ "component": "addDepositWorkspace",
294
+ "title": "Add Deposit",
295
+ "type": "other-form"
296
+ },
297
+ {
298
+ "name":"deposit-transaction-workspace",
299
+ "component": "depositTransactionWorkspace",
300
+ "title": "Deposit Transaction",
290
301
  "type": "other-form"
291
302
  }
292
303
  ],
@@ -322,6 +333,14 @@
322
333
  {
323
334
  "name": "create-bill-item-modal",
324
335
  "component": "createBillItemModal"
336
+ },
337
+ {
338
+ "name": "delete-deposit-modal",
339
+ "component": "deleteDepositModal"
340
+ },
341
+ {
342
+ "name": "reverse-transaction-modal",
343
+ "component": "reverseTransactionModal"
325
344
  }
326
345
  ]
327
346
  }
@@ -85,6 +85,7 @@ export interface Patient {
85
85
  uuid: string;
86
86
  display: string;
87
87
  links: PatientLink[];
88
+ identifiers: Array<{ uuid: string; display: string }>;
88
89
  }
89
90
 
90
91
  interface AttributeType {
@@ -77,6 +77,7 @@
77
77
  "create": "Create",
78
78
  "createClaimError": "Create Claim error",
79
79
  "created": "Created",
80
+ "createNewDeposit": "Create a new deposit for this patient",
80
81
  "creating": "Creating",
81
82
  "date": "Date of Claim",
82
83
  "dateCreated": "Date Created",
@@ -163,6 +164,7 @@
163
164
  "mpesaPayment": "MPESA Payment",
164
165
  "name": "Name",
165
166
  "navigateBack": "Navigate back",
167
+ "newDeposit": "New Deposit",
166
168
  "nextPage": "Next page",
167
169
  "no": "No",
168
170
  "noBenefitFound": "No benefit found",
@@ -171,6 +173,7 @@
171
173
  "noBillsFoundDescription": "No bills found for this patient",
172
174
  "noCashPoints": "No Cash Points",
173
175
  "noCashPointsConfigured": "There are no cash points configured for this location",
176
+ "noDepositsFound": "No deposits found",
174
177
  "noItemsSelected": "No items selected",
175
178
  "noMatchingBillsToDisplay": "No matching bills to display",
176
179
  "noMatchingItemsToDisplay": "No matching items to display",