@kenyaemr/esm-billing-app 5.4.1-pre.1998 → 5.4.1-pre.2000

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/routes.json CHANGED
@@ -1 +1 @@
1
- {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"}},{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","slot":"patient-chart-dashboard-slot","meta":{"name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot","path":"insurance-benefits","columns":1,"columnSpan":1},"featureFlag":"healthInformationExchange"},{"component":"benefitsPackage","name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"component":"benefitsEligibilyRequestForm","name":"benefits-eligibility-request-form"},{"component":"benefitsPreAuthForm","name":"benefits-pre-auth-form"},{"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","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"initiate-payment-modal","component":"initiatePaymentDialog"},{"name":"delete-billableservice-modal","component":"deleteBillableServiceModal"},{"name":"refund-bill-modal","component":"refundBillModal"},{"name":"delete-bill-modal","component":"deleteBillModal"},{"name":"lab-order-billable-item","component":"labOrder","slot":"top-of-lab-order-form-slot"},{"name":"procedure-order-billable-item","component":"procedureOrder","slot":"top-of-procedure-order-form-slot"},{"name":"imaging-order-billable-item","component":"imagingOrder","slot":"top-of-imaging-order-form-slot"},{"name":"price-info-order","component":"priceInfoOrder"},{"name":"drug-order-billable-item","component":"drugOrder","slot":"medication-info-slot"},{"name":"order-action-button","component":"orderActionButton","slots":["prescription-action-button-slot","imaging-orders-action","procedure-orders-action","tests-ordered-actions-slot"],"order":0},{"component":"billingOverviewLink","name":"billing-overview-link","order":0,"slot":"billing-dashboard-link-slot"},{"component":"paymentHistoryLink","name":"payment-history-link","slot":"billing-dashboard-link-slot"},{"component":"paymentPointsLink","name":"payment-points-link","slot":"billing-dashboard-link-slot"},{"component":"paymentModesLink","name":"payment-modes-link","slot":"billing-dashboard-link-slot"},{"component":"billManagerLink","name":"bill-manager-link","slot":"billing-dashboard-link-slot"},{"component":"chargeableItemsLink","name":"chargeable-items-link","slot":"billing-dashboard-link-slot"},{"component":"billableExemptionsLink","name":"billable-exemptions-link","slot":"billing-dashboard-link-slot"},{"component":"claimsManagementSideNavGroup","name":"claims-management-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"claims-management","title":"Claims management Overview","slot":"case-management-slot"},"featureFlag":"healthInformationExchange"},{"component":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","order":0,"slot":"claims-management-dashboard-link-slot"},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slot":"claims-management-dashboard-link-slot"},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"component":"waiveBillActionButton","name":"waive-bill-action-button","slot":"bill-actions-slot"},{"component":"deleteBillActionButton","name":"delete-bill-action-button","slot":"bill-actions-slot"},{"component":"refundLineItem","name":"refund-line-item","slot":"bill-actions-overflow-menu-slot"},{"name":"edit-line-item","component":"editLineItem","slot":"bill-actions-overflow-menu-slot"},{"name":"cancel-line-item","component":"cancelLineItem","slot":"bill-actions-overflow-menu-slot"}],"workspaces":[{"name":"create-bill-workspace","component":"createBillWorkspace","title":"Create Bill Workspace","type":"other-form"},{"name":"waive-bill-form","component":"waiveBillForm","title":"Waive Bill Form","type":"other-form"},{"name":"edit-bill-form","component":"editBillForm","title":"Edit Bill Form","type":"other-form"},{"name":"billable-service-form","component":"addServiceForm","title":"Create Charge Item Form","type":"other-form"},{"name":"commodity-form","component":"addCommodityForm","title":"Create Charge Item Form","type":"other-form"},{"name":"billing-form","component":"billingForm","title":"Billing Form","type":"other-form","width":"extra-wide"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","title":"Payment Mode Workspace","type":"other-form"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","title":"Cancel Bill Workspace","type":"other-form"},{"name":"bill-deposit-workspace","component":"billDepositWorkspace","title":"Bill Deposit Workspace","type":"other-form"}],"modals":[{"name":"create-payment-point","component":"createPaymentPoint"},{"name":"clock-out-modal","component":"clockOut"},{"name":"bulk-import-billable-services-modal","component":"bulkImportBillableServicesModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"retry-claim-request-modal","component":"retryClaimRequestModal"},{"name":"paid-bill-receipt-print-preview-modal","component":"paidBillReceiptPrintPreviewModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"create-bill-item-modal","component":"createBillItemModal"}],"version":"5.4.1-pre.1998"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false}],"extensions":[{"component":"billingDashboardLink","name":"billing-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"billing","title":"billing","slot":"billing-dashboard-slot"}},{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","slot":"patient-chart-dashboard-slot","meta":{"name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot","path":"insurance-benefits","columns":1,"columnSpan":1},"featureFlag":"healthInformationExchange"},{"component":"benefitsPackage","name":"benefits-package","slot":"patient-chart-benefits-dashboard-slot"},{"component":"root","name":"billing-dashboard-root","slot":"billing-dashboard-slot"},{"component":"benefitsEligibilyRequestForm","name":"benefits-eligibility-request-form"},{"component":"benefitsPreAuthForm","name":"benefits-pre-auth-form"},{"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","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"extra-visit-attribute-slot","component":"billingCheckInForm"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"patient-banner-billing-tags","component":"visitAttributeTags","slot":"patient-banner-tags-slot","order":2},{"name":"initiate-payment-modal","component":"initiatePaymentDialog"},{"name":"delete-billableservice-modal","component":"deleteBillableServiceModal"},{"name":"refund-bill-modal","component":"refundBillModal"},{"name":"delete-bill-modal","component":"deleteBillModal"},{"name":"lab-order-billable-item","component":"labOrder","slot":"top-of-lab-order-form-slot"},{"name":"procedure-order-billable-item","component":"procedureOrder","slot":"top-of-procedure-order-form-slot"},{"name":"imaging-order-billable-item","component":"imagingOrder","slot":"top-of-imaging-order-form-slot"},{"name":"price-info-order","component":"priceInfoOrder"},{"name":"drug-order-billable-item","component":"drugOrder","slot":"medication-info-slot"},{"name":"order-action-button","component":"orderActionButton","slots":["prescription-action-button-slot","imaging-orders-action","procedure-orders-action","tests-ordered-actions-slot"],"order":0},{"component":"billingOverviewLink","name":"billing-overview-link","order":0,"slot":"billing-dashboard-link-slot"},{"component":"paymentHistoryLink","name":"payment-history-link","slot":"billing-dashboard-link-slot"},{"component":"paymentPointsLink","name":"payment-points-link","slot":"billing-dashboard-link-slot"},{"component":"paymentModesLink","name":"payment-modes-link","slot":"billing-dashboard-link-slot"},{"component":"billManagerLink","name":"bill-manager-link","slot":"billing-dashboard-link-slot"},{"component":"chargeableItemsLink","name":"chargeable-items-link","slot":"billing-dashboard-link-slot"},{"component":"billableExemptionsLink","name":"billable-exemptions-link","slot":"billing-dashboard-link-slot"},{"component":"claimsManagementSideNavGroup","name":"claims-management-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"claims-management","title":"Claims management Overview","slot":"case-management-slot"},"featureFlag":"healthInformationExchange"},{"component":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","order":0,"slot":"claims-management-dashboard-link-slot"},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slot":"claims-management-dashboard-link-slot"},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"component":"waiveBillActionButton","name":"waive-bill-action-button","slot":"bill-actions-slot"},{"component":"deleteBillActionButton","name":"delete-bill-action-button","slot":"bill-actions-slot"},{"component":"refundLineItem","name":"refund-line-item","slot":"bill-actions-overflow-menu-slot"},{"name":"edit-line-item","component":"editLineItem","slot":"bill-actions-overflow-menu-slot"},{"name":"cancel-line-item","component":"cancelLineItem","slot":"bill-actions-overflow-menu-slot"}],"workspaces":[{"name":"create-bill-workspace","component":"createBillWorkspace","title":"Create Bill Workspace","type":"other-form"},{"name":"waive-bill-form","component":"waiveBillForm","title":"Waive Bill Form","type":"other-form"},{"name":"edit-bill-form","component":"editBillForm","title":"Edit Bill Form","type":"other-form"},{"name":"billable-service-form","component":"addServiceForm","title":"Create Charge Item Form","type":"other-form"},{"name":"commodity-form","component":"addCommodityForm","title":"Create Charge Item Form","type":"other-form"},{"name":"billing-form","component":"billingForm","title":"Billing Form","type":"other-form","width":"extra-wide"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","title":"Payment Mode Workspace","type":"other-form"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","title":"Cancel Bill Workspace","type":"other-form"},{"name":"bill-deposit-workspace","component":"billDepositWorkspace","title":"Bill Deposit Workspace","type":"other-form"}],"modals":[{"name":"create-payment-point","component":"createPaymentPoint"},{"name":"clock-out-modal","component":"clockOut"},{"name":"bulk-import-billable-services-modal","component":"bulkImportBillableServicesModal"},{"name":"delete-payment-mode-modal","component":"deletePaymentModeModal"},{"name":"retry-claim-request-modal","component":"retryClaimRequestModal"},{"name":"paid-bill-receipt-print-preview-modal","component":"paidBillReceiptPrintPreviewModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"create-bill-item-modal","component":"createBillItemModal"}],"version":"5.4.1-pre.2000"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-billing-app",
3
- "version": "5.4.1-pre.1998",
3
+ "version": "5.4.1-pre.2000",
4
4
  "description": "Billing app for KenyaEMR",
5
5
  "browser": "dist/kenyaemr-esm-billing-app.js",
6
6
  "main": "src/index.ts",
@@ -25,6 +25,7 @@ export interface BillingConfig {
25
25
  patientBillsUrl: string;
26
26
  nationalIdUUID: string;
27
27
  isPDSLFacility: boolean;
28
+ mobileMoneyPaymentModeUUID: string;
28
29
  concepts: {
29
30
  emergencyPriorityConceptUuid: string;
30
31
  };
@@ -41,6 +42,11 @@ export const configSchema: ConfigSchema = {
41
42
  _description: 'A flag for PDSL facilities',
42
43
  _default: false,
43
44
  },
45
+ mobileMoneyPaymentModeUUID: {
46
+ _type: Type.UUID,
47
+ _description: 'Mobile money payment method uuid',
48
+ _default: '28989582-e8c3-46b0-96d0-c249cb06d5c6',
49
+ },
44
50
  shaIdentificationNumberUUID: {
45
51
  _type: Type.String,
46
52
  _description: 'Social Health Authority Identification Number',
@@ -82,6 +82,7 @@ const Invoice: React.FC = () => {
82
82
  const dispose = showModal('initiate-payment-modal', {
83
83
  closeModal: () => dispose(),
84
84
  bill: bill,
85
+ selectedLineItems,
85
86
  });
86
87
  };
87
88
 
@@ -1,12 +1,16 @@
1
1
  import {
2
2
  Button,
3
+ ButtonSet,
4
+ ContentSwitcher,
3
5
  Form,
4
6
  InlineNotification,
5
7
  Layer,
6
8
  Loading,
7
9
  ModalBody,
10
+ ModalFooter,
8
11
  ModalHeader,
9
12
  NumberInputSkeleton,
13
+ Switch,
10
14
  TextInput,
11
15
  } from '@carbon/react';
12
16
  import { zodResolver } from '@hookform/resolvers/zod';
@@ -20,7 +24,8 @@ import { useSystemSetting } from '../../../hooks/getMflCode';
20
24
  import { usePatientAttributes } from '../../../hooks/usePatientAttributes';
21
25
  import { useRequestStatus } from '../../../hooks/useRequestStatus';
22
26
  import { initiateStkPush } from '../../../m-pesa/mpesa-resource';
23
- import { MappedBill } from '../../../types';
27
+ import { LineItem, MappedBill } from '../../../types';
28
+ import PaymentStatusCheckerModal from '../payment-status-ckecker.modal';
24
29
  import { formatKenyanPhoneNumber } from '../utils';
25
30
  import styles from './initiate-payment.scss';
26
31
 
@@ -37,15 +42,17 @@ type FormData = z.infer<typeof initiatePaymentSchema>;
37
42
  export interface InitiatePaymentDialogProps {
38
43
  closeModal: () => void;
39
44
  bill: MappedBill;
45
+ selectedLineItems: Array<LineItem>;
40
46
  }
41
47
 
42
- const InitiatePaymentDialog: React.FC<InitiatePaymentDialogProps> = ({ closeModal, bill }) => {
48
+ const InitiatePaymentDialog: React.FC<InitiatePaymentDialogProps> = ({ closeModal, bill, selectedLineItems }) => {
43
49
  const { t } = useTranslation();
44
50
  const { phoneNumber, isLoading: isLoadingPhoneNumber } = usePatientAttributes(bill.patientUuid);
45
51
  const { mpesaAPIBaseUrl, isPDSLFacility } = useConfig<BillingConfig>();
46
52
  const { mflCodeValue } = useSystemSetting('facility.mflcode');
47
53
  const [notification, setNotification] = useState<{ type: 'error' | 'success'; message: string } | null>(null);
48
54
  const [isLoading, setIsLoading] = useState(false);
55
+ const [hasMadePayment, setHasMadepayment] = useState(false);
49
56
  const [{ requestStatus }, pollingTrigger] = useRequestStatus(setNotification, closeModal, bill);
50
57
 
51
58
  const pendingAmount = bill.totalAmount - bill.tenderedAmount;
@@ -91,12 +98,35 @@ const InitiatePaymentDialog: React.FC<InitiatePaymentDialogProps> = ({ closeModa
91
98
  setIsLoading(false);
92
99
  };
93
100
 
101
+ if (isPDSLFacility && hasMadePayment) {
102
+ return (
103
+ <PaymentStatusCheckerModal
104
+ onClose={closeModal}
105
+ paymentMade={hasMadePayment}
106
+ onPaymentMadestatusChange={setHasMadepayment}
107
+ bill={bill}
108
+ selectedLineItems={selectedLineItems}
109
+ />
110
+ );
111
+ }
112
+
94
113
  return (
95
- <div>
96
- <ModalHeader closeModal={closeModal} />
114
+ <Form>
115
+ <ModalHeader className={styles.heading} closeModal={closeModal}>
116
+ {t('paymentPayment', 'Bill Payment')}
117
+ </ModalHeader>
97
118
  <ModalBody>
98
- <Form className={styles.form}>
99
- <h4>{t('paymentPayment', 'Bill Payment')}</h4>
119
+ {isPDSLFacility && (
120
+ <ContentSwitcher
121
+ selectedIndex={hasMadePayment ? 1 : 0}
122
+ onChange={({ name }) => {
123
+ setHasMadepayment(name === 'paymentMade');
124
+ }}>
125
+ <Switch name="paymentNotMade" text={t('paymentNotMade', 'Payment not made')} />
126
+ <Switch name="paymentMade" text={t('paymentMade', 'Payments already made')} />
127
+ </ContentSwitcher>
128
+ )}
129
+ <div className={styles.form}>
100
130
  {notification && (
101
131
  <InlineNotification
102
132
  kind={notification.type}
@@ -144,28 +174,30 @@ const InitiatePaymentDialog: React.FC<InitiatePaymentDialogProps> = ({ closeModa
144
174
  )}
145
175
  />
146
176
  </section>
147
- <section>
148
- <Button kind="secondary" className={styles.buttonLayout} onClick={closeModal}>
149
- {t('cancel', 'Cancel')}
150
- </Button>
151
- <Button
152
- type="submit"
153
- className={styles.button}
154
- onClick={handleSubmit(onSubmit)}
155
- disabled={!isValid || isLoading || requestStatus === 'INITIATED'}>
156
- {isLoading ? (
157
- <>
158
- <Loading className={styles.button_spinner} withOverlay={false} small />{' '}
159
- {t('processingPayment', 'Processing Payment')}
160
- </>
161
- ) : (
162
- t('initiatePay', 'Initiate Payment')
163
- )}
164
- </Button>
165
- </section>
166
- </Form>
177
+ </div>
167
178
  </ModalBody>
168
- </div>
179
+ <ModalFooter>
180
+ <ButtonSet className={styles.buttonSet}>
181
+ <Button kind="secondary" onClick={closeModal} className={styles.button}>
182
+ {t('cancel', 'Cancel')}
183
+ </Button>
184
+ <Button
185
+ type="submit"
186
+ className={styles.button}
187
+ onClick={handleSubmit(onSubmit)}
188
+ disabled={!isValid || isLoading || requestStatus === 'INITIATED'}>
189
+ {isLoading ? (
190
+ <>
191
+ <Loading className={styles.button_spinner} withOverlay={false} small />{' '}
192
+ {t('processingPayment', 'Processing Payment')}
193
+ </>
194
+ ) : (
195
+ t('initiatePayment', 'Initiate Payment')
196
+ )}
197
+ </Button>
198
+ </ButtonSet>
199
+ </ModalFooter>
200
+ </Form>
169
201
  );
170
202
  };
171
203
 
@@ -21,18 +21,28 @@
21
21
  margin-bottom: spacing.$spacing-04;
22
22
  }
23
23
 
24
- .buttonLayout {
25
- margin-top: layout.$spacing-05;
26
- margin-bottom: layout.$spacing-01;
24
+ .button_spinner {
25
+ padding: 0;
26
+ margin-right: layout.$spacing-04;
27
27
  }
28
28
 
29
29
  .button {
30
- margin-left: layout.$spacing-04;
30
+ height: layout.$spacing-10;
31
+ display: flex;
32
+ align-content: flex-start;
33
+ align-items: baseline;
34
+ min-width: 20%;
35
+ }
36
+
37
+ .buttonSet {
38
+ padding: 0rem;
31
39
  margin-top: layout.$spacing-05;
32
- margin-bottom: layout.$spacing-01;
40
+ display: flex;
41
+ justify-content: space-between;
42
+ width: 100%;
43
+ margin-bottom: layout.$spacing-05;
33
44
  }
34
45
 
35
- .button_spinner {
36
- padding: 0;
37
- margin-right: 12px;
46
+ .heading {
47
+ @include type.type-style('heading-02');
38
48
  }
@@ -0,0 +1,136 @@
1
+ import {
2
+ Button,
3
+ ButtonSet,
4
+ ContentSwitcher,
5
+ InlineLoading,
6
+ ModalBody,
7
+ ModalFooter,
8
+ ModalHeader,
9
+ Switch,
10
+ TextInput,
11
+ } from '@carbon/react';
12
+ import { showSnackbar, useConfig } from '@openmrs/esm-framework';
13
+ import React, { useCallback, useMemo, useState } from 'react';
14
+ import { useTranslation } from 'react-i18next';
15
+ import { mutate } from 'swr';
16
+ import { processBillPayment, usePaymentModes } from '../../billing.resource';
17
+ import { BillingConfig } from '../../config-schema';
18
+ import { useClockInStatus } from '../../payment-points/use-clock-in-status';
19
+ import { LineItem, MappedBill } from '../../types';
20
+ import { checkPaymentStatus } from './payments.resource';
21
+ import styles from './payments.scss';
22
+ import { createPaymentPayload } from './utils';
23
+ type PaymentStatusCheckerModalProps = {
24
+ onClose: () => void;
25
+ paymentMade?: boolean;
26
+ onPaymentMadestatusChange?: (paid: boolean) => void;
27
+ bill: MappedBill;
28
+ selectedLineItems: Array<LineItem>;
29
+ };
30
+ const PaymentStatusCheckerModal: React.FC<PaymentStatusCheckerModalProps> = ({
31
+ onClose,
32
+ onPaymentMadestatusChange,
33
+ paymentMade,
34
+ bill,
35
+ selectedLineItems,
36
+ }) => {
37
+ const { t } = useTranslation();
38
+ const [transactionid, setTransactionid] = useState<string>();
39
+ const { globalActiveSheet } = useClockInStatus();
40
+ const { mobileMoneyPaymentModeUUID } = useConfig<BillingConfig>();
41
+ const { paymentModes, isLoading } = usePaymentModes();
42
+ const [checking, setChecking] = useState(false);
43
+ const mobilemoneypaymentMethod = useMemo(
44
+ () => paymentModes.find((mode) => mode.uuid === mobileMoneyPaymentModeUUID),
45
+ [paymentModes, mobileMoneyPaymentModeUUID],
46
+ );
47
+
48
+ const handleCheckPaymentStatus = useCallback(async () => {
49
+ try {
50
+ setChecking(true);
51
+ const res = await checkPaymentStatus(transactionid);
52
+ if (res?.data?.success) {
53
+ const totalAmountTendered = Number(res.data.data.TransAmount) || 0;
54
+ const amountDue = Number(bill.totalAmount) - (Number(bill.tenderedAmount) + Number(totalAmountTendered));
55
+ const paymentPayload = createPaymentPayload(
56
+ bill,
57
+ bill.patientUuid,
58
+ [{ referenceCode: transactionid, amount: totalAmountTendered, method: mobilemoneypaymentMethod }],
59
+ amountDue,
60
+ selectedLineItems,
61
+ globalActiveSheet,
62
+ );
63
+ await processBillPayment(paymentPayload, bill.uuid);
64
+ showSnackbar({
65
+ title: t('success', 'Success'),
66
+ kind: 'success',
67
+ subtitle: t('paymentReceived', 'Payment received'),
68
+ });
69
+ const url = `/ws/rest/v1/cashier/bill/${bill.uuid}`;
70
+ mutate((key) => typeof key === 'string' && key.startsWith(url), undefined, { revalidate: true });
71
+ onClose?.();
72
+ } else {
73
+ showSnackbar({
74
+ title: t('paymentFailure', 'Payment Failure'),
75
+ kind: 'error',
76
+ subtitle: res?.data?.message || t('paymentNotSettled', 'Payment not settled'),
77
+ });
78
+ }
79
+ } catch (error: any) {
80
+ showSnackbar({ title: t('error', 'Error'), kind: 'error', subtitle: error?.message });
81
+ } finally {
82
+ setChecking(false);
83
+ }
84
+ }, [transactionid, t]);
85
+ return (
86
+ <React.Fragment>
87
+ <ModalHeader className={styles.heading} closeModal={onClose}>
88
+ {t('checkpaymentStatus', 'Check payment status')}
89
+ </ModalHeader>
90
+ <ModalBody>
91
+ <ContentSwitcher
92
+ selectedIndex={paymentMade ? 1 : 0}
93
+ onChange={({ name }) => {
94
+ onPaymentMadestatusChange?.(name === 'paymentMade');
95
+ }}>
96
+ <Switch name="paymentNotMade" text={t('paymentNotMade', 'Payment not made')} />
97
+ <Switch name="paymentMade" text={t('paymentMade', 'Payments already made')} />
98
+ </ContentSwitcher>
99
+ <TextInput
100
+ value={transactionid}
101
+ defaultWidth={300}
102
+ id="text-input-1"
103
+ labelText={t('transactionId', 'Transaction Id')}
104
+ placeholder={t('exampletransactionId', 'e.g TRMEWECEDD')}
105
+ size="md"
106
+ type="text"
107
+ helperText={t('mpesaTransactionId', 'Mpesa transaction Id')}
108
+ onChange={({ target: { value } }) => setTransactionid(value)}
109
+ />
110
+ </ModalBody>
111
+ <ModalFooter>
112
+ <ButtonSet className={styles.buttonSet}>
113
+ <Button kind="secondary" onClick={onClose} className={styles.button}>
114
+ {t('cancel', 'Cancel')}
115
+ </Button>
116
+ <Button
117
+ kind="primary"
118
+ disabled={!transactionid?.length || isLoading || checking}
119
+ onClick={handleCheckPaymentStatus}
120
+ className={styles.button}>
121
+ {isLoading || checking ? (
122
+ <InlineLoading
123
+ description={t('checkingPaymentStatus', 'Check payment status') + '...'}
124
+ iconDescription={t('loading', 'Loading')}
125
+ />
126
+ ) : (
127
+ t('check', 'Check')
128
+ )}
129
+ </Button>
130
+ </ButtonSet>
131
+ </ModalFooter>
132
+ </React.Fragment>
133
+ );
134
+ };
135
+
136
+ export default PaymentStatusCheckerModal;
@@ -1,5 +1,5 @@
1
1
  import useSWR from 'swr';
2
- import { openmrsFetch, useConfig } from '@openmrs/esm-framework';
2
+ import { openmrsFetch, restBaseUrl, useConfig } from '@openmrs/esm-framework';
3
3
  import { BillingConfig } from '../../config-schema';
4
4
 
5
5
  type PaymentMethod = {
@@ -13,6 +13,32 @@ const swrOption = {
13
13
  errorRetryCount: 2,
14
14
  };
15
15
 
16
+ export interface PaymentStatusResponse {
17
+ success: boolean;
18
+ message: string;
19
+ data?: Data;
20
+ }
21
+
22
+ export interface Data {
23
+ id: number;
24
+ TransactionType: string;
25
+ TransID: string;
26
+ TransTime: string;
27
+ TransAmount: string;
28
+ BusinessShortCode: string;
29
+ BillRefNumber: string;
30
+ InvoiceNumber?: string;
31
+ OrgAccountBalance: string;
32
+ ThirdPartyTransID?: string;
33
+ MSISDN: string;
34
+ FirstName: string;
35
+ MiddleName?: string;
36
+ LastName?: string;
37
+ status: string;
38
+ created_at: string;
39
+ updated_at: string;
40
+ }
41
+
16
42
  export const usePaymentModes = () => {
17
43
  const { excludedPaymentMode } = useConfig<BillingConfig>();
18
44
  const url = `/ws/rest/v1/cashier/paymentMode`;
@@ -32,3 +58,8 @@ export const usePaymentModes = () => {
32
58
  error,
33
59
  };
34
60
  };
61
+
62
+ export const checkPaymentStatus = (transactionId: string) => {
63
+ const url = `${restBaseUrl}/rmsdataexchange/api/rmsmpesachecker?transactionId=${transactionId}`;
64
+ return openmrsFetch<PaymentStatusResponse>(url);
65
+ };
@@ -48,3 +48,24 @@
48
48
  .paymentError {
49
49
  margin: layout.$spacing-05 0;
50
50
  }
51
+
52
+ .heading {
53
+ @include type.type-style('heading-02');
54
+ }
55
+
56
+ .button {
57
+ height: layout.$spacing-10;
58
+ display: flex;
59
+ align-content: flex-start;
60
+ align-items: baseline;
61
+ min-width: 20%;
62
+ }
63
+
64
+ .buttonSet {
65
+ padding: 0rem;
66
+ margin-top: layout.$spacing-05;
67
+ display: flex;
68
+ justify-content: space-between;
69
+ width: 100%;
70
+ margin-bottom: layout.$spacing-05;
71
+ }