@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/.turbo/turbo-build.log +1 -1
- package/dist/2032.js +1 -0
- package/dist/2032.js.map +1 -0
- package/dist/2929.js +1 -0
- package/dist/2929.js.map +1 -0
- package/dist/3294.js +1 -1
- package/dist/3294.js.map +1 -1
- package/dist/3642.js +1 -0
- package/dist/3642.js.map +1 -0
- package/dist/4206.js +1 -1
- package/dist/4206.js.map +1 -1
- package/dist/477.js +1 -0
- package/dist/477.js.map +1 -0
- package/dist/5284.js +1 -1
- package/dist/5284.js.map +1 -1
- package/dist/kenyaemr-esm-billing-app.js.buildmanifest.json +108 -36
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/claims/claims-wrap/claim-workspaces/attachements/claim-attachements-workspace.tsx +17 -0
- package/src/claims/claims-wrap/claim-workspaces/attachements/claim-attachments-resource.ts +91 -0
- package/src/claims/claims-wrap/claim-workspaces/attachements/replace-attachment.modal.tsx +62 -0
- package/src/claims/claims-wrap/claim-workspaces/claim-submission/ClaimSubmitWorkspace.tsx +48 -4
- package/src/claims/claims-wrap/claim-workspaces/claim-submission/resubmit-confirm.modal.tsx +73 -0
- package/src/claims/claims-wrap/claims-main-component.tsx +190 -22
- package/src/index.ts +10 -0
- package/src/routes.json +8 -0
- package/dist/1947.js +0 -1
- package/dist/1947.js.map +0 -1
|
@@ -39,11 +39,17 @@ import {
|
|
|
39
39
|
launchWorkspace2,
|
|
40
40
|
restBaseUrl,
|
|
41
41
|
useVisit,
|
|
42
|
+
showModal,
|
|
43
|
+
showSnackbar,
|
|
42
44
|
} from '@openmrs/esm-framework';
|
|
43
45
|
import { BillingConfig } from '../../config-schema';
|
|
44
46
|
import { useCurrencyFormatting } from '../../helpers/currency';
|
|
45
47
|
import { TFunction } from 'i18next';
|
|
46
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
useClaimAttachments,
|
|
50
|
+
retireClaimAttachment,
|
|
51
|
+
moveClaimToResubmit,
|
|
52
|
+
} from './claim-workspaces/attachements/claim-attachments-resource';
|
|
47
53
|
import { useClaimDoctors } from './claim-workspaces/doctors/claim-doctors-resource';
|
|
48
54
|
|
|
49
55
|
interface ClaimsMainProps {
|
|
@@ -242,7 +248,6 @@ const ClaimsTable: React.FC<{
|
|
|
242
248
|
const totalItems = claims.length;
|
|
243
249
|
const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
|
|
244
250
|
|
|
245
|
-
// Keep the page in range when the claim set shrinks (e.g. after a sync/mutate).
|
|
246
251
|
useEffect(() => {
|
|
247
252
|
if (currentPage > totalPages) {
|
|
248
253
|
setCurrentPage(totalPages);
|
|
@@ -287,6 +292,7 @@ const ClaimsTable: React.FC<{
|
|
|
287
292
|
interventions: (claim.interventions ?? []).map((i) => i.intervention_code),
|
|
288
293
|
paymentMechanism: claim.interventions?.[0]?.payment_mechanism,
|
|
289
294
|
isResubmission: isResubmit,
|
|
295
|
+
providerWorkflowState: claim.provider_workflow_state,
|
|
290
296
|
totalAmount,
|
|
291
297
|
mutate,
|
|
292
298
|
},
|
|
@@ -452,6 +458,33 @@ const ClaimDetailsPanel: React.FC<{
|
|
|
452
458
|
mutateAttachments();
|
|
453
459
|
mutateDoctors();
|
|
454
460
|
}, [mutate, mutateAttachments, mutateDoctors]);
|
|
461
|
+
const isEditable = claim.provider_workflow_state === 'DRAFT' || claim.provider_workflow_state === 'DRAFT_RESUBMIT';
|
|
462
|
+
const canMoveToResubmit = claim.provider_workflow_state === 'SUBMITTED' && claim.payer_workflow_state === 'SENT_BACK';
|
|
463
|
+
const handleMoveToResubmit = useCallback(async () => {
|
|
464
|
+
const result = await moveClaimToResubmit({
|
|
465
|
+
consentToken: claim.authorization_code,
|
|
466
|
+
t,
|
|
467
|
+
});
|
|
468
|
+
if (!result.ok) {
|
|
469
|
+
showSnackbar({
|
|
470
|
+
title: t('moveToResubmitFailed', 'Could not open claim for changes'),
|
|
471
|
+
subtitle: result.error,
|
|
472
|
+
kind: 'error',
|
|
473
|
+
});
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
combinedMutate();
|
|
477
|
+
showSnackbar({
|
|
478
|
+
title: result.alreadyOpenForEdit
|
|
479
|
+
? t('claimAlreadyOpen', 'Claim is already open for changes')
|
|
480
|
+
: t('claimOpenedForChanges', 'Claim opened for changes'),
|
|
481
|
+
subtitle: t(
|
|
482
|
+
'claimOpenedForChangesSubtitle',
|
|
483
|
+
'You can now replace or add attachments, edit lines, and submit back to SHA when ready.',
|
|
484
|
+
),
|
|
485
|
+
kind: 'success',
|
|
486
|
+
});
|
|
487
|
+
}, [claim.authorization_code, combinedMutate, t]);
|
|
455
488
|
|
|
456
489
|
const preauthsByIntervention = useMemo(() => {
|
|
457
490
|
const map = new Map<string, Array<(typeof claim.preauths)[number]>>();
|
|
@@ -510,6 +543,85 @@ const ClaimDetailsPanel: React.FC<{
|
|
|
510
543
|
[claim.authorization_code, attachmentsByCode, combinedMutate, t],
|
|
511
544
|
);
|
|
512
545
|
|
|
546
|
+
const handleReplaceAttachment = useCallback(
|
|
547
|
+
(iv: PatientClaimIntervention, attachment: { uuid: string; document_type: string; filename?: string }) => {
|
|
548
|
+
const dispose = showModal('replace-claim-attachment-modal', {
|
|
549
|
+
documentType: attachment.document_type,
|
|
550
|
+
filename: attachment.filename,
|
|
551
|
+
onConfirm: async () => {
|
|
552
|
+
const retireResult = await retireClaimAttachment({
|
|
553
|
+
consentToken: claim.authorization_code,
|
|
554
|
+
attachmentUuid: attachment.uuid,
|
|
555
|
+
interventionCode: iv.intervention_code,
|
|
556
|
+
t,
|
|
557
|
+
});
|
|
558
|
+
if (!retireResult.ok) {
|
|
559
|
+
showSnackbar({
|
|
560
|
+
title: t('retireFailed', 'Could not retire attachment'),
|
|
561
|
+
subtitle: retireResult.error,
|
|
562
|
+
kind: 'error',
|
|
563
|
+
});
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
combinedMutate();
|
|
568
|
+
|
|
569
|
+
showSnackbar({
|
|
570
|
+
title: t('attachmentRetired', 'Attachment retired'),
|
|
571
|
+
subtitle: t(
|
|
572
|
+
'attachmentRetiredSubtitle',
|
|
573
|
+
'SHA has cleared the previous {{type}}. Upload the replacement to complete.',
|
|
574
|
+
{ type: attachment.document_type.replace(/_/g, ' ') },
|
|
575
|
+
),
|
|
576
|
+
kind: 'info',
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
launchWorkspace2(
|
|
580
|
+
'claim-attachments-workspace',
|
|
581
|
+
{
|
|
582
|
+
workspaceTitle: t('uploadReplacementAttachment', 'Upload replacement attachment'),
|
|
583
|
+
consentToken: claim.authorization_code,
|
|
584
|
+
interventionCode: iv.intervention_code,
|
|
585
|
+
interventionName: iv.intervention_name,
|
|
586
|
+
applicableDocumentTypes: [attachment.document_type],
|
|
587
|
+
alreadyUploadedTypes: [],
|
|
588
|
+
preselectedDocumentType: attachment.document_type,
|
|
589
|
+
replacementNotice: {
|
|
590
|
+
documentType: attachment.document_type,
|
|
591
|
+
filename: attachment.filename,
|
|
592
|
+
},
|
|
593
|
+
mutate: combinedMutate,
|
|
594
|
+
},
|
|
595
|
+
{},
|
|
596
|
+
{},
|
|
597
|
+
);
|
|
598
|
+
},
|
|
599
|
+
closeModal: () => dispose(),
|
|
600
|
+
});
|
|
601
|
+
},
|
|
602
|
+
[claim.authorization_code, combinedMutate, t],
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
const handleAddDocumentForIntervention = useCallback(
|
|
606
|
+
(iv: PatientClaimIntervention, remainingDocTypes: ReadonlyArray<string>) => {
|
|
607
|
+
launchWorkspace2(
|
|
608
|
+
'claim-attachments-workspace',
|
|
609
|
+
{
|
|
610
|
+
workspaceTitle: t('addMissingDocument', 'Add missing document'),
|
|
611
|
+
consentToken: claim.authorization_code,
|
|
612
|
+
interventionCode: iv.intervention_code,
|
|
613
|
+
interventionName: iv.intervention_name,
|
|
614
|
+
applicableDocumentTypes: remainingDocTypes,
|
|
615
|
+
alreadyUploadedTypes: [],
|
|
616
|
+
mutate: combinedMutate,
|
|
617
|
+
},
|
|
618
|
+
{},
|
|
619
|
+
{},
|
|
620
|
+
);
|
|
621
|
+
},
|
|
622
|
+
[claim.authorization_code, combinedMutate, t],
|
|
623
|
+
);
|
|
624
|
+
|
|
513
625
|
return (
|
|
514
626
|
<div className={styles.expandedContent}>
|
|
515
627
|
{claim.sync_status === 'ERROR' && claim.sync_error_message && (
|
|
@@ -522,19 +634,39 @@ const ClaimDetailsPanel: React.FC<{
|
|
|
522
634
|
className={styles.syncErrorNotification}
|
|
523
635
|
/>
|
|
524
636
|
)}
|
|
637
|
+
{claim.provider_workflow_state === 'DRAFT_RESUBMIT' && (
|
|
638
|
+
<InlineNotification
|
|
639
|
+
kind="info"
|
|
640
|
+
lowContrast
|
|
641
|
+
hideCloseButton
|
|
642
|
+
title={t('claimOpenForChanges', 'Claim is open for changes')}
|
|
643
|
+
subtitle={t('claimOpenForChangesSubtitle', 'You can do edits, and submit back to SHA when ready')}
|
|
644
|
+
className={styles.payerNotice}
|
|
645
|
+
/>
|
|
646
|
+
)}
|
|
647
|
+
|
|
525
648
|
{(claim.payer_workflow_state ||
|
|
526
649
|
(claim.payer_notes?.length ?? 0) > 0 ||
|
|
527
650
|
(claim.payer_transitions?.length ?? 0) > 0) && (
|
|
528
651
|
<section className={styles.payerActivitySection}>
|
|
529
652
|
{claim.payer_workflow_state === 'SENT_BACK' && (
|
|
530
|
-
<
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
653
|
+
<div className={styles.payerNoticeWrap}>
|
|
654
|
+
<InlineNotification
|
|
655
|
+
kind="error"
|
|
656
|
+
lowContrast
|
|
657
|
+
hideCloseButton
|
|
658
|
+
title={t('shaBouncedClaim', 'SHA returned this claim for action')}
|
|
659
|
+
subtitle={claim.payer_workflow_display_name ?? ''}
|
|
660
|
+
className={styles.payerNotice}
|
|
661
|
+
/>
|
|
662
|
+
{canMoveToResubmit && (
|
|
663
|
+
<div className={styles.payerNoticeActions}>
|
|
664
|
+
<Button size="sm" kind="danger--tertiary" renderIcon={Renew} onClick={handleMoveToResubmit}>
|
|
665
|
+
{t('openForChanges', 'Open for changes')}
|
|
666
|
+
</Button>
|
|
667
|
+
</div>
|
|
668
|
+
)}
|
|
669
|
+
</div>
|
|
538
670
|
)}
|
|
539
671
|
|
|
540
672
|
<div className={styles.payerActivityCard}>
|
|
@@ -744,6 +876,24 @@ const ClaimDetailsPanel: React.FC<{
|
|
|
744
876
|
{t('uploadAttachments', 'Upload attachments')}
|
|
745
877
|
</Button>
|
|
746
878
|
)}
|
|
879
|
+
{tab === 'resubmission' &&
|
|
880
|
+
isEditable &&
|
|
881
|
+
(() => {
|
|
882
|
+
const remaining = requiredDocs.filter((d) => !uploadedTypes.has(d));
|
|
883
|
+
if (remaining.length === 0) {
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
return (
|
|
887
|
+
<Button
|
|
888
|
+
size="sm"
|
|
889
|
+
kind="tertiary"
|
|
890
|
+
renderIcon={DocumentAdd}
|
|
891
|
+
className={styles.addDocBtn}
|
|
892
|
+
onClick={() => handleAddDocumentForIntervention(iv, remaining)}>
|
|
893
|
+
{t('addDocumentN', '+ Add document ({{count}})', { count: remaining.length })}
|
|
894
|
+
</Button>
|
|
895
|
+
);
|
|
896
|
+
})()}
|
|
747
897
|
</div>
|
|
748
898
|
|
|
749
899
|
{requiredDocs.length > 0 && (
|
|
@@ -766,18 +916,36 @@ const ClaimDetailsPanel: React.FC<{
|
|
|
766
916
|
</div>
|
|
767
917
|
{uploadedAttachments.map((a) => (
|
|
768
918
|
<li key={a.uuid} className={styles.ivAttachmentRow}>
|
|
769
|
-
{a.document_type}
|
|
770
|
-
{
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
919
|
+
<span>{a.document_type}</span>
|
|
920
|
+
<div className={styles.attachmentActions}>
|
|
921
|
+
{a.uuid ? (
|
|
922
|
+
<a
|
|
923
|
+
href={`/openmrs${restBaseUrl}/virtualclaims/billing/attachments/${a.uuid}/file`}
|
|
924
|
+
target="_blank"
|
|
925
|
+
rel="noopener noreferrer"
|
|
926
|
+
className={styles.viewLink}>
|
|
927
|
+
{t('view', 'View')} ↗
|
|
928
|
+
</a>
|
|
929
|
+
) : (
|
|
930
|
+
<span className={styles.muted}>—</span>
|
|
931
|
+
)}
|
|
932
|
+
{tab === 'resubmission' && isEditable && a.uuid && (
|
|
933
|
+
<Button
|
|
934
|
+
size="sm"
|
|
935
|
+
kind="ghost"
|
|
936
|
+
renderIcon={Renew}
|
|
937
|
+
className={styles.replaceBtn}
|
|
938
|
+
onClick={() =>
|
|
939
|
+
handleReplaceAttachment(iv, {
|
|
940
|
+
uuid: a.uuid,
|
|
941
|
+
document_type: a.document_type ?? '',
|
|
942
|
+
filename: (a as { filename?: string }).filename,
|
|
943
|
+
})
|
|
944
|
+
}>
|
|
945
|
+
{t('replace', 'Replace')}
|
|
946
|
+
</Button>
|
|
947
|
+
)}
|
|
948
|
+
</div>
|
|
781
949
|
</li>
|
|
782
950
|
))}
|
|
783
951
|
</ul>
|
package/src/index.ts
CHANGED
|
@@ -259,6 +259,16 @@ export const claimDeleteLineModal = getAsyncLifecycle(
|
|
|
259
259
|
options,
|
|
260
260
|
);
|
|
261
261
|
|
|
262
|
+
export const replaceAttachmentModal = getAsyncLifecycle(
|
|
263
|
+
() => import('./claims/claims-wrap/claim-workspaces/attachements/replace-attachment.modal'),
|
|
264
|
+
options,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
export const resubmitConfirmModal = getAsyncLifecycle(
|
|
268
|
+
() => import('./claims/claims-wrap/claim-workspaces/claim-submission/resubmit-confirm.modal'),
|
|
269
|
+
options,
|
|
270
|
+
);
|
|
271
|
+
|
|
262
272
|
// Print Preview Components
|
|
263
273
|
export const printPreviewModal = getAsyncLifecycle(() => import('./print-preview/print-preview.modal'), options);
|
|
264
274
|
export const patientBannerShaStatus = getAsyncLifecycle(
|
package/src/routes.json
CHANGED
|
@@ -392,6 +392,14 @@
|
|
|
392
392
|
{
|
|
393
393
|
"name": "require-billing-modal",
|
|
394
394
|
"component": "requirePaymentModal"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"name": "replace-claim-attachment-modal",
|
|
398
|
+
"component": "replaceAttachmentModal"
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
"name": "resubmit-confirm-modal",
|
|
402
|
+
"component": "resubmitConfirmModal"
|
|
395
403
|
}
|
|
396
404
|
],
|
|
397
405
|
"workspaces2": [
|