@kenyaemr/esm-billing-app 5.4.4-pre.430 → 5.4.4-pre.435

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","kenyaemr.cashier":"^4.2.6-SNAPSHOT"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false},{"component":"billingAdmin","route":"billing-admin"},{"component":"resubmitClaimPage","route":"billing/resubmit-claim"}],"extensions":[{"component":"accountingDashboardLink","name":"accounting-dashboard-link","slots":["homepage-dashboard-slot"],"meta":{"name":"accounting","slot":"accounting-dashboard-slot","title":"Accounting"}},{"name":"billing-dashboard","component":"billingDashboard","slot":"accounting-dashboard-slot"},{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","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","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"visit-form-bottom-slot","component":"billingCheckInForm","order":1},{"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":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","slots":["claims-management-dashboard-link-slot"]},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slots":["claims-management-dashboard-link-slot"]},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"name":"patient-preauth-widget","component":"patientPreauthWidget","slot":"ewf-preauth-dashboard-slot","meta":{"columnSpan":4}},{"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"},{"name":"patient-info-sha-status","component":"patientBannerShaStatus","slot":"patient-banner-tags-slot"},{"name":"payments-points-dashboard-link","component":"paymentPointDashboardLink","slot":"billing-admin-dashboard-slot","meta":{"name":"cashier-points","title":"Payment Point","slot":"payment-point-dashboard-slot"}},{"name":"payment-points-dashboard","component":"paymentPoints","slot":"payment-point-dashboard-slot"},{"name":"payment-mode-dashboard-link","component":"paymentModeLink","slot":"billing-admin-dashboard-slot","meta":{"name":"payment-modes","title":"Payment Mode","slot":"payment-mode-dashboard-slot"}},{"name":"payment-mode-dashboard","component":"paymentModeDashboard","slot":"payment-mode-dashboard-slot"},{"name":"bill-deposit-dashboard-link","component":"billDepositDashboardLink","slot":"billing-admin-dashboard-slot","meta":{"name":"bill-deposit","title":"Bill Deposit","slot":"billing-deposit-dashboard-slot"}},{"name":"bill-deposit-dashboard","component":"billDepositDashboard","slot":"billing-deposit-dashboard-slot"},{"name":"billable-exemptions-dashboard-link","component":"billableExemptionsLink","slot":"billing-admin-dashboard-slot","meta":{"name":"billable-exemptions","title":"Billable Exemptions","slot":"billing-exemptions-dashboard-slot"}},{"name":"billable-exemptions-dashboard","component":"billableExemptions","slot":"billing-exemptions-dashboard-slot"},{"name":"clinical-charges-dashboard-link","component":"clinicalChargesLink","slot":"billing-admin-dashboard-slot","meta":{"name":"clinical-charges","title":"Clinical Charges","slot":"clinical-charges-dashboard-slot"}},{"name":"clinical-charges-dashboard","component":"clinicalCharges","slot":"clinical-charges-dashboard-slot"},{"name":"payment-history-dashboard-link","component":"paymentHistoryLink","slot":"billing-admin-dashboard-slot","meta":{"name":"payment-history","title":"Payment History","slot":"payment-history-dashboard-slot"}},{"name":"payment-history-dashboard","component":"paymentHistoryDashboard","slot":"payment-history-dashboard-slot"},{"name":"patient-billing-dashboard-link","component":"patientBillingLink","slot":"billing-admin-dashboard-slot","meta":{"name":"patient-billing","title":"Patient Billing","slot":"patient-billing-dashboard-slot"}},{"name":"patient-billing-dashboard","component":"patientBilling","slot":"patient-billing-dashboard-slot"}],"workspaces":[],"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":"manage-claim-request-modal","component":"manageClaimRequestModal"},{"name":"claim-preview-modal","component":"claimPreviewModal"},{"name":"close-claim-modal","component":"claimCloseModal"},{"name":"resubmit-claim-line-modal","component":"claimResubmitModal"},{"name":"edit-claim-line-modal","component":"claimEditLineModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"delete-claim-line-modal","component":"claimDeleteLineModal"},{"name":"create-bill-item-modal","component":"createBillItemModal"},{"name":"delete-deposit-modal","component":"deleteDepositModal"},{"name":"reverse-transaction-modal","component":"reverseTransactionModal"},{"name":"print-preview-modal","component":"printPreviewModal"},{"name":"bill-action-modal","component":"billActionModal"},{"name":"require-billing-modal","component":"requirePaymentModal"}],"workspaces2":[{"name":"create-bill-workspace","component":"createBillWorkspace","window":"billing-workspace-window"},{"name":"waive-bill-form","component":"waiveBillForm","window":"billing-workspace-window"},{"name":"edit-bill-form","component":"editBillForm","window":"billing-workspace-window"},{"name":"billable-service-form","component":"addServiceForm","window":"billing-workspace-window"},{"name":"commodity-form","component":"commodityForm","window":"billing-workspace-window"},{"name":"billing-form","component":"billingForm","window":"billing-extra-wide-workspace-window"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","window":"billing-workspace-window"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","window":"billing-workspace-window"},{"name":"add-deposit-workspace","component":"addDepositWorkspace","window":"billing-workspace-window"},{"name":"deposit-transaction-workspace","component":"depositTransactionWorkspace","window":"billing-workspace-window"},{"name":"payment-workspace","component":"paymentWorkspace","window":"billing-workspace-window"},{"name":"claim-attachments-workspace","component":"claimAttachmentsWorkspace","window":"billing-workspace-window"},{"name":"claim-doctors-workspace","component":"claimDoctorsWorkspace","window":"billing-workspace-window"},{"name":"claim-submission-workspace","component":"claimSubmissionWorkspace","window":"billing-workspace-window"},{"name":"edit-drug-order","component":"@openmrs/esm-patient-medications-app#exportedAddDrugOrderWorkspace","window":"billing-workspace-window"},{"name":"preauth-form-workspace","component":"preauthFormWorkspace","window":"billing-workspace-window"},{"name":"elective-preauth-form-workspace","component":"electivePreauthFormWorkspace","window":"billing-workspace-window"},{"name":"preauth-operation-workspace","component":"preauthOperationWorkspace","window":"billing-workspace-window"}],"workspaceWindows2":[{"name":"billing-workspace-window","group":"billing-workspace-group","canMaximize":true},{"name":"billing-extra-wide-workspace-window","group":"billing-workspace-group","canMaximize":true,"width":"extra-wide"}],"workspaceGroups2":[{"name":"billing-workspace-group","persistence":"closeable","closeable":true}],"version":"5.4.4-pre.430"}
1
+ {"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0","kenyaemr.cashier":"^4.2.6-SNAPSHOT"},"pages":[{"component":"billableServicesHome","route":"billable-services"},{"component":"requirePaymentModal","routeRegex":"^patient/.+/chart","online":true,"offline":false},{"component":"billingAdmin","route":"billing-admin"},{"component":"resubmitClaimPage","route":"billing/resubmit-claim"}],"extensions":[{"component":"accountingDashboardLink","name":"accounting-dashboard-link","slots":["homepage-dashboard-slot"],"meta":{"name":"accounting","slot":"accounting-dashboard-slot","title":"Accounting"}},{"name":"billing-dashboard","component":"billingDashboard","slot":"accounting-dashboard-slot"},{"component":"benefitsPackageDashboardLink","name":"benefits-package-dashboard-link","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","order":11,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-billing-dashboard-slot","path":"Billing","layoutMode":"anchored"}},{"name":"billing-check-in-form","slot":"visit-form-bottom-slot","component":"billingCheckInForm","order":1},{"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":"claimsManagementOverviewDashboardLink","name":"claims-management-overview-link","slots":["claims-management-dashboard-link-slot"]},{"component":"preAuthRequestsDashboardLink","name":"preauthrequest-overview-link","slots":["claims-management-dashboard-link-slot"]},{"component":"claimsOverview","name":"claims-overview-dashboard-link","slot":"claims-management-overview-slot"},{"name":"patient-preauth-widget","component":"patientPreauthWidget","slot":"ewf-preauth-dashboard-slot","meta":{"columnSpan":4}},{"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"},{"name":"patient-info-sha-status","component":"patientBannerShaStatus","slot":"patient-banner-tags-slot"},{"name":"payments-points-dashboard-link","component":"paymentPointDashboardLink","slot":"billing-admin-dashboard-slot","meta":{"name":"cashier-points","title":"Payment Point","slot":"payment-point-dashboard-slot"}},{"name":"payment-points-dashboard","component":"paymentPoints","slot":"payment-point-dashboard-slot"},{"name":"payment-mode-dashboard-link","component":"paymentModeLink","slot":"billing-admin-dashboard-slot","meta":{"name":"payment-modes","title":"Payment Mode","slot":"payment-mode-dashboard-slot"}},{"name":"payment-mode-dashboard","component":"paymentModeDashboard","slot":"payment-mode-dashboard-slot"},{"name":"bill-deposit-dashboard-link","component":"billDepositDashboardLink","slot":"billing-admin-dashboard-slot","meta":{"name":"bill-deposit","title":"Bill Deposit","slot":"billing-deposit-dashboard-slot"}},{"name":"bill-deposit-dashboard","component":"billDepositDashboard","slot":"billing-deposit-dashboard-slot"},{"name":"billable-exemptions-dashboard-link","component":"billableExemptionsLink","slot":"billing-admin-dashboard-slot","meta":{"name":"billable-exemptions","title":"Billable Exemptions","slot":"billing-exemptions-dashboard-slot"}},{"name":"billable-exemptions-dashboard","component":"billableExemptions","slot":"billing-exemptions-dashboard-slot"},{"name":"clinical-charges-dashboard-link","component":"clinicalChargesLink","slot":"billing-admin-dashboard-slot","meta":{"name":"clinical-charges","title":"Clinical Charges","slot":"clinical-charges-dashboard-slot"}},{"name":"clinical-charges-dashboard","component":"clinicalCharges","slot":"clinical-charges-dashboard-slot"},{"name":"payment-history-dashboard-link","component":"paymentHistoryLink","slot":"billing-admin-dashboard-slot","meta":{"name":"payment-history","title":"Payment History","slot":"payment-history-dashboard-slot"}},{"name":"payment-history-dashboard","component":"paymentHistoryDashboard","slot":"payment-history-dashboard-slot"},{"name":"patient-billing-dashboard-link","component":"patientBillingLink","slot":"billing-admin-dashboard-slot","meta":{"name":"patient-billing","title":"Patient Billing","slot":"patient-billing-dashboard-slot"}},{"name":"patient-billing-dashboard","component":"patientBilling","slot":"patient-billing-dashboard-slot"}],"workspaces":[],"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":"manage-claim-request-modal","component":"manageClaimRequestModal"},{"name":"claim-preview-modal","component":"claimPreviewModal"},{"name":"close-claim-modal","component":"claimCloseModal"},{"name":"resubmit-claim-line-modal","component":"claimResubmitModal"},{"name":"edit-claim-line-modal","component":"claimEditLineModal"},{"name":"clock-in-modal","component":"clockIn"},{"name":"delete-claim-line-modal","component":"claimDeleteLineModal"},{"name":"create-bill-item-modal","component":"createBillItemModal"},{"name":"delete-deposit-modal","component":"deleteDepositModal"},{"name":"reverse-transaction-modal","component":"reverseTransactionModal"},{"name":"print-preview-modal","component":"printPreviewModal"},{"name":"bill-action-modal","component":"billActionModal"},{"name":"require-billing-modal","component":"requirePaymentModal"},{"name":"replace-claim-attachment-modal","component":"replaceAttachmentModal"},{"name":"resubmit-confirm-modal","component":"resubmitConfirmModal"}],"workspaces2":[{"name":"create-bill-workspace","component":"createBillWorkspace","window":"billing-workspace-window"},{"name":"waive-bill-form","component":"waiveBillForm","window":"billing-workspace-window"},{"name":"edit-bill-form","component":"editBillForm","window":"billing-workspace-window"},{"name":"billable-service-form","component":"addServiceForm","window":"billing-workspace-window"},{"name":"commodity-form","component":"commodityForm","window":"billing-workspace-window"},{"name":"billing-form","component":"billingForm","window":"billing-extra-wide-workspace-window"},{"name":"payment-mode-workspace","component":"paymentModeWorkspace","window":"billing-workspace-window"},{"name":"cancel-bill-workspace","component":"cancelBillWorkspace","window":"billing-workspace-window"},{"name":"add-deposit-workspace","component":"addDepositWorkspace","window":"billing-workspace-window"},{"name":"deposit-transaction-workspace","component":"depositTransactionWorkspace","window":"billing-workspace-window"},{"name":"payment-workspace","component":"paymentWorkspace","window":"billing-workspace-window"},{"name":"claim-attachments-workspace","component":"claimAttachmentsWorkspace","window":"billing-workspace-window"},{"name":"claim-doctors-workspace","component":"claimDoctorsWorkspace","window":"billing-workspace-window"},{"name":"claim-submission-workspace","component":"claimSubmissionWorkspace","window":"billing-workspace-window"},{"name":"edit-drug-order","component":"@openmrs/esm-patient-medications-app#exportedAddDrugOrderWorkspace","window":"billing-workspace-window"},{"name":"preauth-form-workspace","component":"preauthFormWorkspace","window":"billing-workspace-window"},{"name":"elective-preauth-form-workspace","component":"electivePreauthFormWorkspace","window":"billing-workspace-window"},{"name":"preauth-operation-workspace","component":"preauthOperationWorkspace","window":"billing-workspace-window"}],"workspaceWindows2":[{"name":"billing-workspace-window","group":"billing-workspace-group","canMaximize":true},{"name":"billing-extra-wide-workspace-window","group":"billing-workspace-group","canMaximize":true,"width":"extra-wide"}],"workspaceGroups2":[{"name":"billing-workspace-group","persistence":"closeable","closeable":true}],"version":"5.4.4-pre.435"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kenyaemr/esm-billing-app",
3
- "version": "5.4.4-pre.430",
3
+ "version": "5.4.4-pre.435",
4
4
  "description": "Billing app for KenyaEMR",
5
5
  "keywords": [
6
6
  "openmrs"
@@ -33,6 +33,8 @@ type ClaimAttachmentsWorkspaceProps = {
33
33
  applicableDocumentTypes: ReadonlyArray<string>;
34
34
  alreadyUploadedTypes: ReadonlyArray<string>;
35
35
  mutate: () => void;
36
+ preselectedDocumentType?: string;
37
+ replacementNotice?: { documentType: string; filename?: string };
36
38
  };
37
39
 
38
40
  type RowStatus = 'pending' | 'uploading' | 'succeeded' | 'already_sent' | 'failed';
@@ -60,6 +62,7 @@ const ClaimAttachmentsWorkspace: React.FC<Workspace2DefinitionProps<ClaimAttachm
60
62
  }) => {
61
63
  const { consentToken, interventionCode, interventionName, applicableDocumentTypes, alreadyUploadedTypes, mutate } =
62
64
  workspaceProps ?? ({} as ClaimAttachmentsWorkspaceProps);
65
+ const { preselectedDocumentType, replacementNotice } = workspaceProps ?? ({} as ClaimAttachmentsWorkspaceProps);
63
66
 
64
67
  const { t } = useTranslation();
65
68
  const isTablet = useLayoutType() === 'tablet';
@@ -110,6 +113,20 @@ const ClaimAttachmentsWorkspace: React.FC<Workspace2DefinitionProps<ClaimAttachm
110
113
  [watchedAttachments, availableDocumentTypes],
111
114
  );
112
115
 
116
+ React.useEffect(() => {
117
+ if (!preselectedDocumentType) {
118
+ return;
119
+ }
120
+ const tid = setTimeout(() => {
121
+ const current = getValues('attachments.0.document_type');
122
+ if (!current) {
123
+ setValue('attachments.0.document_type', preselectedDocumentType);
124
+ }
125
+ }, 0);
126
+ return () => clearTimeout(tid);
127
+ // eslint-disable-next-line react-hooks/exhaustive-deps
128
+ }, [preselectedDocumentType, getValues, setValue]);
129
+
113
130
  const pendingRowsCount = useMemo(() => {
114
131
  return attachmentFields.filter((f) => {
115
132
  const status = rowResults.get(f.id)?.status;
@@ -104,3 +104,94 @@ export const useClaimAttachments = (consentToken: string | null) => {
104
104
  mutate,
105
105
  };
106
106
  };
107
+
108
+ export const moveClaimToResubmit = async (params: {
109
+ consentToken: string;
110
+ t: TFunction;
111
+ }): Promise<{ ok: boolean; error?: string; alreadyOpenForEdit?: boolean }> => {
112
+ const { consentToken, t } = params;
113
+ if (!consentToken) {
114
+ return { ok: false, error: t('noConsentToken', 'No consent token provided') };
115
+ }
116
+
117
+ try {
118
+ const response = await openmrsFetch(`${restBaseUrl}/virtualclaims/billing/resubmit`, {
119
+ method: 'POST',
120
+ headers: { 'Content-Type': 'application/json' },
121
+ body: { consent_token: consentToken },
122
+ });
123
+ if (!response.ok) {
124
+ const upstream = extractUpstreamError(response.data);
125
+ return {
126
+ ok: false,
127
+ error:
128
+ upstream ??
129
+ t('moveToResubmitHttpError', 'Could not move claim to resubmit (HTTP {{status}})', {
130
+ status: response.status,
131
+ }),
132
+ };
133
+ }
134
+ const data = response.data as {
135
+ success?: boolean;
136
+ already_open_for_edit?: boolean;
137
+ error?: string;
138
+ };
139
+ if (data?.success === false) {
140
+ return { ok: false, error: data.error ?? t('moveToResubmitFailed', 'Could not move claim to resubmit') };
141
+ }
142
+ return { ok: true, alreadyOpenForEdit: data?.already_open_for_edit };
143
+ } catch (err) {
144
+ return {
145
+ ok: false,
146
+ error: extractFetchError(err, t('moveToResubmitFailed', 'Could not move claim to resubmit. Please try again.')),
147
+ };
148
+ }
149
+ };
150
+
151
+ export const retireClaimAttachment = async (params: {
152
+ consentToken: string;
153
+ attachmentUuid: string;
154
+ interventionCode: string;
155
+ t: TFunction;
156
+ }): Promise<{ ok: boolean; error?: string; retrievalId?: string }> => {
157
+ const { consentToken, attachmentUuid, interventionCode, t } = params;
158
+ if (!consentToken) {
159
+ return { ok: false, error: t('noConsentToken', 'No consent token provided') };
160
+ }
161
+ if (!attachmentUuid) {
162
+ return { ok: false, error: t('noAttachmentUuid', 'No attachment selected') };
163
+ }
164
+ if (!interventionCode) {
165
+ return { ok: false, error: t('noInterventionCode', 'No intervention code provided') };
166
+ }
167
+
168
+ try {
169
+ const response = await openmrsFetch(`${restBaseUrl}/virtualclaims/billing/attachments`, {
170
+ method: 'PATCH',
171
+ headers: { 'Content-Type': 'application/json' },
172
+ body: {
173
+ consent_token: consentToken,
174
+ attachment_uuid: attachmentUuid,
175
+ intervention_code: interventionCode,
176
+ },
177
+ });
178
+ if (!response.ok) {
179
+ const upstream = extractUpstreamError(response.data);
180
+ return {
181
+ ok: false,
182
+ error:
183
+ upstream ?? t('retireAttachmentHttpError', 'Retire failed (HTTP {{status}})', { status: response.status }),
184
+ };
185
+ }
186
+ const data = response.data as { success?: boolean; retrieval_id?: string; error?: string };
187
+ if (data?.success === false) {
188
+ return { ok: false, error: data.error ?? t('retireFailed', 'Retire failed') };
189
+ }
190
+ return { ok: true, retrievalId: data?.retrieval_id };
191
+ } catch (err) {
192
+ return {
193
+ ok: false,
194
+ error: extractFetchError(err, t('retireFailed', 'Failed to retire attachment. Please try again.')),
195
+ };
196
+ }
197
+ };
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
4
+
5
+ interface ReplaceAttachmentModalProps {
6
+ documentType: string;
7
+ filename?: string;
8
+ closeModal: () => void;
9
+ onConfirm: () => Promise<void> | void;
10
+ }
11
+
12
+ const ReplaceAttachmentModal: React.FC<ReplaceAttachmentModalProps> = ({
13
+ documentType,
14
+ filename,
15
+ closeModal,
16
+ onConfirm,
17
+ }) => {
18
+ const { t } = useTranslation();
19
+ const prettyType = documentType.replace(/_/g, ' ');
20
+
21
+ const handleConfirm = async () => {
22
+ closeModal();
23
+ await onConfirm();
24
+ };
25
+
26
+ return (
27
+ <>
28
+ <ModalHeader
29
+ closeModal={closeModal}
30
+ title={t('replaceAttachmentTitle', 'Replace {{type}}?', { type: prettyType })}
31
+ />
32
+ <ModalBody>
33
+ <p>
34
+ {filename
35
+ ? t(
36
+ 'replaceAttachmentBodyWithFile',
37
+ 'The current file ({{filename}}) will be retired from SHA. You will then need to upload a new file to complete the replacement.',
38
+ { filename },
39
+ )
40
+ : t(
41
+ 'replaceAttachmentBody',
42
+ 'The current {{type}} will be retired from SHA. You will then need to upload a new file to complete the replacement.',
43
+ { type: prettyType },
44
+ )}
45
+ </p>
46
+ <p style={{ marginTop: '0.75rem', fontSize: '0.8125rem', color: 'var(--cds-text-secondary, #525252)' }}>
47
+ {t('replaceAttachmentWarning', 'Until the replacement is uploaded the claim will be missing this document.')}
48
+ </p>
49
+ </ModalBody>
50
+ <ModalFooter>
51
+ <Button kind="secondary" onClick={closeModal}>
52
+ {t('cancel', 'Cancel')}
53
+ </Button>
54
+ <Button kind="danger" onClick={handleConfirm}>
55
+ {t('retireAndUploadNew', 'Retire & upload new')}
56
+ </Button>
57
+ </ModalFooter>
58
+ </>
59
+ );
60
+ };
61
+
62
+ export default ReplaceAttachmentModal;
@@ -56,6 +56,7 @@ type ClaimSubmitWorkspaceProps = {
56
56
  isResubmission?: boolean;
57
57
  totalAmount?: number;
58
58
  mutate: () => void;
59
+ providerWorkflowState?: string;
59
60
  };
60
61
 
61
62
  const RequiredLabel: React.FC<{ children: React.ReactNode }> = ({ children }) => (
@@ -80,6 +81,7 @@ const ClaimSubmitWorkspace: React.FC<Workspace2DefinitionProps<ClaimSubmitWorksp
80
81
  interventions,
81
82
  paymentMechanism,
82
83
  isResubmission = false,
84
+ providerWorkflowState,
83
85
  totalAmount,
84
86
  mutate,
85
87
  } = workspaceProps ?? ({} as ClaimSubmitWorkspaceProps);
@@ -149,12 +151,15 @@ const ClaimSubmitWorkspace: React.FC<Workspace2DefinitionProps<ClaimSubmitWorksp
149
151
  }, []);
150
152
 
151
153
  const runSubmit = useCallback(
152
- async (auth: { otp: string } | { dischargeAuthGuid: string }) => {
154
+ async (auth: { otp: string } | { dischargeAuthGuid: string } | Record<string, never>) => {
153
155
  const params = {
154
156
  consentToken,
155
157
  invoiceNumber,
156
158
  dischargeReason: dischargeReasonRef.current,
157
- ...('otp' in auth ? { otp: auth.otp } : { dischargeAuthGuid: auth.dischargeAuthGuid }),
159
+ ...('otp' in auth ? { otp: (auth as { otp: string }).otp } : {}),
160
+ ...('dischargeAuthGuid' in auth
161
+ ? { dischargeAuthGuid: (auth as { dischargeAuthGuid: string }).dischargeAuthGuid }
162
+ : {}),
158
163
  };
159
164
 
160
165
  const result = isInpatient
@@ -383,14 +388,51 @@ const ClaimSubmitWorkspace: React.FC<Workspace2DefinitionProps<ClaimSubmitWorksp
383
388
  [dischargeReasonItems, dischargeReasonSelected],
384
389
  );
385
390
 
391
+ const launchResubmitConfirm = useCallback(() => {
392
+ setSubmitError(null);
393
+ const dispose = showModal('resubmit-confirm-modal', {
394
+ consentToken,
395
+ onConfirm: async () => {
396
+ setIsSubmitting(true);
397
+ try {
398
+ await runSubmit({});
399
+ setSubmitSucceeded(true);
400
+ showSnackbar({
401
+ title: t('claimResubmitted', 'Claim resubmitted'),
402
+ subtitle: t('claimSubmittedDesc', 'Claim {{code}} sent to payer for review', {
403
+ code: consentToken,
404
+ }),
405
+ kind: 'success',
406
+ isLowContrast: true,
407
+ });
408
+ mutate();
409
+ setTimeout(() => closeWorkspace(), 800);
410
+ } catch (err) {
411
+ const msg = err instanceof Error ? err.message : String(err);
412
+ setSubmitError(msg);
413
+ throw err;
414
+ } finally {
415
+ setIsSubmitting(false);
416
+ }
417
+ },
418
+ closeModal: () => dispose(),
419
+ });
420
+ }, [consentToken, runSubmit, mutate, t]);
421
+
386
422
  if (!workspaceProps) {
387
423
  return null;
388
424
  }
389
425
 
426
+ const shouldSkipOtp = isResubmission && providerWorkflowState === 'DRAFT_RESUBMIT';
427
+
390
428
  const onContinue = (data: ClaimSubmitFormData) => {
391
429
  dischargeReasonRef.current = data.discharge_reason;
392
430
  dischargeDateIsoRef.current = isInpatient ? buildDischargeDateIso() : '';
393
- launchAuthModal();
431
+ if (shouldSkipOtp) {
432
+ launchResubmitConfirm();
433
+ } else {
434
+ launchAuthModal();
435
+ }
394
436
  };
395
437
 
396
438
  const workspaceTitle = isResubmission
@@ -532,7 +574,9 @@ const ClaimSubmitWorkspace: React.FC<Workspace2DefinitionProps<ClaimSubmitWorksp
532
574
  <InlineLoading className={styles.spinner} description={t('verifying', 'Verifying…')} />
533
575
  ) : (
534
576
  <span>
535
- {isResubmission
577
+ {shouldSkipOtp
578
+ ? t('resubmitToSha', 'Resubmit to SHA')
579
+ : isResubmission
536
580
  ? t('continueResubmit', 'Continue to resubmit')
537
581
  : t('continueToSubmit', 'Continue to submit')}
538
582
  </span>
@@ -0,0 +1,73 @@
1
+ import React, { useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, InlineLoading, InlineNotification, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
4
+
5
+ interface ResubmitConfirmModalProps {
6
+ consentToken: string;
7
+ closeModal: () => void;
8
+ onConfirm: () => Promise<void> | void;
9
+ }
10
+
11
+ const ResubmitConfirmModal: React.FC<ResubmitConfirmModalProps> = ({ consentToken, closeModal, onConfirm }) => {
12
+ const { t } = useTranslation();
13
+ const [isSubmitting, setIsSubmitting] = useState(false);
14
+ const [error, setError] = useState<string | null>(null);
15
+
16
+ const handleConfirm = async () => {
17
+ setError(null);
18
+ setIsSubmitting(true);
19
+ try {
20
+ await onConfirm();
21
+ closeModal();
22
+ } catch (err) {
23
+ setError(err instanceof Error ? err.message : String(err));
24
+ } finally {
25
+ setIsSubmitting(false);
26
+ }
27
+ };
28
+
29
+ return (
30
+ <>
31
+ <ModalHeader closeModal={closeModal} title={t('resubmitConfirmTitle', 'Resubmit claim to SHA?')} />
32
+ <ModalBody>
33
+ <p>
34
+ {t(
35
+ 'resubmitConfirmBody',
36
+ 'Claim {{code}} will be sent back to the payer for re-review with the changes you made.',
37
+ { code: consentToken },
38
+ )}
39
+ </p>
40
+ <p style={{ marginTop: '0.75rem', fontSize: '0.8125rem', color: 'var(--cds-text-secondary, #525252)' }}>
41
+ {t(
42
+ 'resubmitConfirmNote',
43
+ 'The original consent token still authorizes this resubmission — no OTP or biometric verification is needed.',
44
+ )}
45
+ </p>
46
+ {error && (
47
+ <InlineNotification
48
+ kind="error"
49
+ lowContrast
50
+ hideCloseButton
51
+ title={t('resubmitFailed', 'Resubmit failed')}
52
+ subtitle={error}
53
+ style={{ marginTop: '1rem' }}
54
+ />
55
+ )}
56
+ </ModalBody>
57
+ <ModalFooter>
58
+ <Button kind="secondary" onClick={closeModal} disabled={isSubmitting}>
59
+ {t('cancel', 'Cancel')}
60
+ </Button>
61
+ <Button kind="danger" onClick={handleConfirm} disabled={isSubmitting}>
62
+ {isSubmitting ? (
63
+ <InlineLoading description={t('resubmitting', 'Resubmitting...')} />
64
+ ) : (
65
+ t('resubmitToSha', 'Resubmit to SHA')
66
+ )}
67
+ </Button>
68
+ </ModalFooter>
69
+ </>
70
+ );
71
+ };
72
+
73
+ export default ResubmitConfirmModal;