@ampath/esm-dha-workflow-app 4.0.0-claim-workflows.310 → 4.0.0-claim-workflows.312
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/1362.js +1 -1
- package/dist/1362.js.map +1 -1
- package/dist/1925.js +1 -1
- package/dist/1927.js +1 -1
- package/dist/2021.js +1 -1
- package/dist/2054.js +1 -1
- package/dist/2092.js +1 -1
- package/dist/2210.js +1 -1
- package/dist/2230.js +1 -1
- package/dist/2493.js +1 -1
- package/dist/262.js +2 -0
- package/dist/262.js.map +1 -0
- package/dist/3202.js +1 -1
- package/dist/347.js +1 -1
- package/dist/3771.js +1 -1
- package/dist/3771.js.map +1 -1
- package/dist/4003.js +1 -1
- package/dist/4205.js +1 -1
- package/dist/4231.js +1 -1
- package/dist/4454.js +1 -1
- package/dist/4674.js +1 -1
- package/dist/4986.js +1 -1
- package/dist/5225.js +1 -1
- package/dist/5344.js +1 -1
- package/dist/5344.js.map +1 -1
- package/dist/5576.js +1 -1
- package/dist/5851.js +1 -1
- package/dist/6028.js +1 -1
- package/dist/6182.js +1 -1
- package/dist/6264.js +1 -1
- package/dist/6730.js +1 -0
- package/dist/6730.js.map +1 -0
- package/dist/6824.js +1 -1
- package/dist/7521.js +1 -1
- package/dist/7549.js +1 -1
- package/dist/7557.js +1 -1
- package/dist/7830.js +1 -1
- package/dist/7941.js +1 -1
- package/dist/8558.js +1 -1
- package/dist/9043.js +1 -1
- package/dist/9091.js +1 -1
- package/dist/9093.js +1 -1
- package/dist/9338.js +1 -1
- package/dist/9428.js +1 -1
- package/dist/9428.js.map +1 -1
- package/dist/esm-dha-workflow-app.js +1 -1
- package/dist/esm-dha-workflow-app.js.buildmanifest.json +102 -102
- package/dist/esm-dha-workflow-app.js.map +1 -1
- 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/billing/billing-claims.resource.ts +31 -1
- package/src/billing/dashboard/v2/patient-bill-details/patient-bill-details.tsx +2 -2
- package/src/billing/dashboard/v2/patient-bill-details/payment-mode.ts +10 -3
- package/src/billing/dashboard/v3/claim-visits/claim-intervention-details/claim-intervention-details.component.tsx +100 -71
- package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.tsx +27 -1
- package/src/billing/dashboard/v3/patient-bill-details/bill-details/bill-details.tsx +1 -0
- package/src/billing/dashboard/v3/patient-bill-details/claim-details/patient-claim-details.component.tsx +1 -0
- package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx +10 -2
- package/src/billing/dashboard/v3/patient-bill-details/patient-bill-details.tsx +2 -1
- package/src/billing/dashboard/v3/preauth/preauth-list.component.tsx +8 -3
- package/src/billing/dashboard/v3/preauth/preauth.resource.ts +5 -0
- package/src/billing/dashboard/v3/preauth/preauth.workspace.tsx +10 -6
- package/src/billing/types/index.ts +5 -0
- package/src/claims/claims.resource.ts +33 -6
- package/dist/1234.js +0 -1
- package/dist/1234.js.map +0 -1
- package/dist/5555.js +0 -2
- package/dist/5555.js.map +0 -1
- package/src/billing/dashboard/v3/claim-visits/claim-intervention-details/claim-intervention-details.component.scss +0 -5
- /package/dist/{5555.js.LICENSE.txt → 262.js.LICENSE.txt} +0 -0
|
@@ -1,34 +1,52 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { type PatientFacilityBillDetails, type VisitIntervention } from '../../types';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
MenuButton,
|
|
5
|
+
MenuItem,
|
|
6
|
+
Table,
|
|
7
|
+
TableBody,
|
|
8
|
+
TableCell,
|
|
9
|
+
TableHead,
|
|
10
|
+
TableHeader,
|
|
11
|
+
TableRow,
|
|
12
|
+
Tag,
|
|
13
|
+
} from '@carbon/react';
|
|
4
14
|
import { launchWorkspace, showSnackbar, useSession } from '@openmrs/esm-framework';
|
|
5
15
|
|
|
6
|
-
import styles from './claim-intervention-details.component.scss';
|
|
7
16
|
import { invalidatePreauthPreview, parseDocTypes, readSpecialtyFlags } from '../../../v2/preauth/preauth.resource';
|
|
17
|
+
import {
|
|
18
|
+
interventionHasBlockingPreauth,
|
|
19
|
+
interventionHasFailedPreauth,
|
|
20
|
+
usePreauthPreview,
|
|
21
|
+
} from '../../../../../claims/claims.resource';
|
|
8
22
|
|
|
9
23
|
interface claimInterventionDetailsProps {
|
|
10
24
|
claimInterventions: VisitIntervention[];
|
|
11
25
|
patientBillDetails: PatientFacilityBillDetails;
|
|
12
26
|
consentToken: string;
|
|
13
27
|
visitUuid: string;
|
|
28
|
+
canSwitchIntervention?: boolean;
|
|
29
|
+
onSwitchSuccess?: () => void;
|
|
14
30
|
}
|
|
31
|
+
|
|
32
|
+
const isActiveIntervention = (iv: VisitIntervention) => (iv.workflow_state ?? '').toUpperCase() === 'ACTIVE';
|
|
33
|
+
|
|
15
34
|
const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
16
35
|
claimInterventions,
|
|
17
36
|
patientBillDetails,
|
|
18
37
|
consentToken,
|
|
19
38
|
visitUuid,
|
|
39
|
+
canSwitchIntervention = false,
|
|
40
|
+
onSwitchSuccess,
|
|
20
41
|
}) => {
|
|
42
|
+
const session = useSession();
|
|
43
|
+
const locationUuid = session?.sessionLocation?.uuid;
|
|
44
|
+
const { preview: preauthPreview } = usePreauthPreview(consentToken, locationUuid);
|
|
45
|
+
|
|
21
46
|
if (!claimInterventions || claimInterventions.length === 0) {
|
|
22
47
|
return <>No Intervention data</>;
|
|
23
48
|
}
|
|
24
|
-
|
|
25
|
-
if (preAuth) {
|
|
26
|
-
return 'YES';
|
|
27
|
-
}
|
|
28
|
-
return 'NO';
|
|
29
|
-
}
|
|
30
|
-
const session = useSession();
|
|
31
|
-
const locationUuid = session?.sessionLocation?.uuid;
|
|
49
|
+
|
|
32
50
|
const handleAddAttachment = (ci: any) => {
|
|
33
51
|
launchWorkspace('upload-intervention-attachments-workspace', {
|
|
34
52
|
consentToken: consentToken,
|
|
@@ -44,10 +62,31 @@ const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
|
44
62
|
bill: patientBillDetails,
|
|
45
63
|
});
|
|
46
64
|
};
|
|
65
|
+
|
|
66
|
+
const canActOnIntervention = (intervention: VisitIntervention) =>
|
|
67
|
+
canSwitchIntervention && isActiveIntervention(intervention);
|
|
68
|
+
|
|
69
|
+
const hasBlockingPreauth = (intervention: VisitIntervention) =>
|
|
70
|
+
interventionHasBlockingPreauth(preauthPreview, intervention.intervention_code);
|
|
71
|
+
|
|
72
|
+
/** Switch stays locked while a non-resubmittable preauth is in flight / finalised. */
|
|
73
|
+
const canSwitchFor = (intervention: VisitIntervention) =>
|
|
74
|
+
canActOnIntervention(intervention) && !hasBlockingPreauth(intervention);
|
|
75
|
+
|
|
76
|
+
const canRaisePreauthFor = (intervention: VisitIntervention) => {
|
|
77
|
+
return canActOnIntervention(intervention) && Boolean(intervention.needs_preauth) && !hasBlockingPreauth(intervention);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const isResubmitPreauth = (intervention: VisitIntervention) =>
|
|
81
|
+
interventionHasFailedPreauth(preauthPreview, intervention.intervention_code);
|
|
82
|
+
|
|
83
|
+
const raisePreauthLabel = (intervention: VisitIntervention) =>
|
|
84
|
+
isResubmitPreauth(intervention) ? 'Resubmit preauth' : 'Raise preauth';
|
|
85
|
+
|
|
47
86
|
const handleSwitchIntervention = (intervention: VisitIntervention) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
87
|
+
if (!canSwitchFor(intervention)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
51
90
|
launchWorkspace('switch-intervention-workspace', {
|
|
52
91
|
consentToken: consentToken,
|
|
53
92
|
currentInterventions: [intervention],
|
|
@@ -56,16 +95,14 @@ const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
|
56
95
|
visitUuid: visitUuid,
|
|
57
96
|
billDate: patientBillDetails?.bill_date,
|
|
58
97
|
onSwitchSuccess: () => {
|
|
59
|
-
|
|
98
|
+
onSwitchSuccess?.();
|
|
60
99
|
},
|
|
61
100
|
});
|
|
62
101
|
};
|
|
63
|
-
|
|
64
102
|
const handleRaisePreauth = (intervention: VisitIntervention) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// const consentToken = claimsVisit.authorization_code;
|
|
103
|
+
if (!canSwitchIntervention) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
69
106
|
if (!consentToken) {
|
|
70
107
|
showSnackbar({
|
|
71
108
|
kind: 'error',
|
|
@@ -74,9 +111,9 @@ const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
|
74
111
|
});
|
|
75
112
|
return;
|
|
76
113
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
114
|
+
if (!canRaisePreauthFor(intervention)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
80
117
|
|
|
81
118
|
const requiredDocs = parseDocTypes(
|
|
82
119
|
Array.isArray(intervention.required_preauth_document_types)
|
|
@@ -87,6 +124,7 @@ const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
|
87
124
|
? intervention.applicable_document_types.map(String)
|
|
88
125
|
: parseDocTypes(intervention.applicable_document_types as string | null | undefined);
|
|
89
126
|
|
|
127
|
+
// Fresh raise and failure-state resubmit both reopen the same preauth form.
|
|
90
128
|
launchWorkspace('preauth-form-workspace', {
|
|
91
129
|
consentToken,
|
|
92
130
|
patientUuid: patientBillDetails?.patient_uuid,
|
|
@@ -110,10 +148,11 @@ const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
|
110
148
|
},
|
|
111
149
|
onSuccess: async () => {
|
|
112
150
|
await invalidatePreauthPreview(consentToken, locationUuid!);
|
|
113
|
-
|
|
151
|
+
onSwitchSuccess?.();
|
|
114
152
|
},
|
|
115
153
|
});
|
|
116
154
|
};
|
|
155
|
+
|
|
117
156
|
return (
|
|
118
157
|
<>
|
|
119
158
|
<Table size="sm">
|
|
@@ -133,55 +172,45 @@ const ClaimInterventionDetails: React.FC<claimInterventionDetailsProps> = ({
|
|
|
133
172
|
</TableHead>
|
|
134
173
|
<TableBody>
|
|
135
174
|
{claimInterventions &&
|
|
136
|
-
claimInterventions.map((ci
|
|
175
|
+
claimInterventions.map((ci) => {
|
|
176
|
+
const canSwitch = canSwitchFor(ci);
|
|
177
|
+
const canRaise = canRaisePreauthFor(ci);
|
|
178
|
+
const hasAttachments = (ci.applicable_document_types ?? []).length > 0;
|
|
137
179
|
return (
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
</Button>
|
|
173
|
-
<Button
|
|
174
|
-
size="sm"
|
|
175
|
-
onClick={() => {
|
|
176
|
-
handleSwitchIntervention(ci);
|
|
177
|
-
}}
|
|
178
|
-
>
|
|
179
|
-
Switch intervention
|
|
180
|
-
</Button>
|
|
181
|
-
</div>
|
|
182
|
-
</TableCell>
|
|
183
|
-
</TableRow>
|
|
184
|
-
</>
|
|
180
|
+
<TableRow key={ci.id}>
|
|
181
|
+
<TableCell>{ci.intervention_code}</TableCell>
|
|
182
|
+
<TableCell>{ci.intervention_payment_mechanism}</TableCell>
|
|
183
|
+
<TableCell>{ci.intervention_name}</TableCell>
|
|
184
|
+
<TableCell>{ci.accrued_per_diem_amount}</TableCell>
|
|
185
|
+
<TableCell>{ci.accrued_per_diem_days}</TableCell>
|
|
186
|
+
<TableCell>{ci.workflow_state}</TableCell>
|
|
187
|
+
<TableCell>{ci.sub_benefit_code}</TableCell>
|
|
188
|
+
<TableCell>{ci.intervention_fund}</TableCell>
|
|
189
|
+
<TableCell>
|
|
190
|
+
{hasAttachments ? (
|
|
191
|
+
<MenuButton label="Attachments" kind="ghost" size="sm">
|
|
192
|
+
<MenuItem label="Generate" onClick={() => handleGenerateAttachment(ci)} />
|
|
193
|
+
<MenuItem label="Upload" onClick={() => handleAddAttachment(ci)} />
|
|
194
|
+
</MenuButton>
|
|
195
|
+
) : (
|
|
196
|
+
<Tag type="gray">Not Required</Tag>
|
|
197
|
+
)}
|
|
198
|
+
</TableCell>
|
|
199
|
+
<TableCell>
|
|
200
|
+
<MenuButton label="Actions" kind="ghost" size="sm">
|
|
201
|
+
<MenuItem
|
|
202
|
+
label={raisePreauthLabel(ci)}
|
|
203
|
+
onClick={() => handleRaisePreauth(ci)}
|
|
204
|
+
disabled={!canRaise}
|
|
205
|
+
/>
|
|
206
|
+
<MenuItem
|
|
207
|
+
label="Switch intervention"
|
|
208
|
+
onClick={() => handleSwitchIntervention(ci)}
|
|
209
|
+
disabled={!canSwitch}
|
|
210
|
+
/>
|
|
211
|
+
</MenuButton>
|
|
212
|
+
</TableCell>
|
|
213
|
+
</TableRow>
|
|
185
214
|
);
|
|
186
215
|
})}
|
|
187
216
|
</TableBody>
|
package/src/billing/dashboard/v3/claim-visits/claim-visit-details/claim-visit-details.component.tsx
CHANGED
|
@@ -14,17 +14,23 @@ import ClaimDoctors from '../claim-doctors/claim-doctors';
|
|
|
14
14
|
import AddClaimDoctorModal from '../modal/claim-doctors/add-claim-doctor/add-claim-doctor.modal';
|
|
15
15
|
import { VisitTypeUuids } from '../../../../../shared/constants/visit-types';
|
|
16
16
|
import { VisitType } from '../../../../../claims';
|
|
17
|
+
import { canEditClaimContent } from '../../../v2/claim-statuses';
|
|
18
|
+
import { interventionHasBlockingPreauth, usePreauthPreview } from '../../../../../claims/claims.resource';
|
|
19
|
+
|
|
17
20
|
interface claimVisitDetailsProps {
|
|
18
21
|
claimsVisit: ClaimsVisit;
|
|
19
22
|
locationUuid: string;
|
|
20
23
|
patientBillDetails?: PatientFacilityBillDetails;
|
|
21
24
|
onBillDetailsChange?: () => void;
|
|
25
|
+
/** True while claim preview is revalidating — stand down content edits. */
|
|
26
|
+
claimRefreshing?: boolean;
|
|
22
27
|
}
|
|
23
28
|
const ClaimVisitDetails: React.FC<claimVisitDetailsProps> = ({
|
|
24
29
|
claimsVisit,
|
|
25
30
|
locationUuid,
|
|
26
31
|
patientBillDetails,
|
|
27
32
|
onBillDetailsChange,
|
|
33
|
+
claimRefreshing = false,
|
|
28
34
|
}) => {
|
|
29
35
|
const [showCloseClaimModal, setShowCloseClaimModal] = useState<boolean>();
|
|
30
36
|
const [showSubmitClaimModal, setSubmitCloseClaimModal] = useState<boolean>(false);
|
|
@@ -76,6 +82,7 @@ const ClaimVisitDetails: React.FC<claimVisitDetailsProps> = ({
|
|
|
76
82
|
}, [activeVisit, VisitTypeUuids]);
|
|
77
83
|
|
|
78
84
|
const invalidateProviderClaimPreview = useInvalidateProviderClaimPreview();
|
|
85
|
+
const { preview: preauthPreview } = usePreauthPreview(claimsVisit?.authorization_code, locationUuid);
|
|
79
86
|
|
|
80
87
|
if (!claimsVisit) {
|
|
81
88
|
return <>No Data</>;
|
|
@@ -127,7 +134,21 @@ const ClaimVisitDetails: React.FC<claimVisitDetailsProps> = ({
|
|
|
127
134
|
});
|
|
128
135
|
};
|
|
129
136
|
|
|
137
|
+
// Same gates as v2: content edits only while claim is DRAFT / DRAFT_RESUBMIT and not refreshing.
|
|
138
|
+
const canSwitchIntervention = canEditClaimContent(claimsVisit.workflow_state) && !claimRefreshing;
|
|
139
|
+
const hasSwitchableIntervention = Boolean(
|
|
140
|
+
claimsVisit.interventions?.some((iv) => {
|
|
141
|
+
const active = (iv.workflow_state ?? '').toUpperCase() === 'ACTIVE';
|
|
142
|
+
if (!active) return false;
|
|
143
|
+
// Match row Actions: blocking preauth locks Switch together with Raise/Resubmit.
|
|
144
|
+
return !interventionHasBlockingPreauth(preauthPreview, iv.intervention_code);
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
|
|
130
148
|
const handleSwitchIntervention = () => {
|
|
149
|
+
if (!canSwitchIntervention || !hasSwitchableIntervention) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
131
152
|
launchWorkspace('switch-intervention-workspace', {
|
|
132
153
|
consentToken: claimsVisit.authorization_code,
|
|
133
154
|
currentInterventions: claimsVisit.interventions,
|
|
@@ -158,7 +179,7 @@ const ClaimVisitDetails: React.FC<claimVisitDetailsProps> = ({
|
|
|
158
179
|
<Button
|
|
159
180
|
kind="tertiary"
|
|
160
181
|
onClick={handleSwitchIntervention}
|
|
161
|
-
disabled={!
|
|
182
|
+
disabled={!canSwitchIntervention || !hasSwitchableIntervention}
|
|
162
183
|
>
|
|
163
184
|
Switch Intervention
|
|
164
185
|
</Button>
|
|
@@ -231,6 +252,11 @@ const ClaimVisitDetails: React.FC<claimVisitDetailsProps> = ({
|
|
|
231
252
|
claimInterventions={claimsVisit.interventions}
|
|
232
253
|
consentToken={claimsVisit.authorization_code}
|
|
233
254
|
visitUuid={activeVisit?.uuid}
|
|
255
|
+
canSwitchIntervention={canSwitchIntervention}
|
|
256
|
+
onSwitchSuccess={() => {
|
|
257
|
+
invalidateProviderClaimPreview();
|
|
258
|
+
onBillDetailsChange?.();
|
|
259
|
+
}}
|
|
234
260
|
/>
|
|
235
261
|
)}
|
|
236
262
|
</div>
|
package/src/billing/dashboard/v3/patient-bill-details/modals/add-claim-line/add-claim-line.modal.tsx
CHANGED
|
@@ -11,8 +11,16 @@ interface addClaimLineModalProps {
|
|
|
11
11
|
onSuccess: () => void;
|
|
12
12
|
billItem: PatientFacilityBillDetails;
|
|
13
13
|
locationUuid: string;
|
|
14
|
+
consentToken?: string;
|
|
14
15
|
}
|
|
15
|
-
const AddClaimLineModal: React.FC<addClaimLineModalProps> = ({
|
|
16
|
+
const AddClaimLineModal: React.FC<addClaimLineModalProps> = ({
|
|
17
|
+
open,
|
|
18
|
+
onClose,
|
|
19
|
+
onSuccess,
|
|
20
|
+
billItem,
|
|
21
|
+
locationUuid,
|
|
22
|
+
consentToken: consentTokenProp,
|
|
23
|
+
}) => {
|
|
16
24
|
const [loading,setLoading] = useState<boolean>(false);
|
|
17
25
|
async function handleAddClaimLineItem() {
|
|
18
26
|
setLoading(true);
|
|
@@ -46,7 +54,7 @@ const AddClaimLineModal: React.FC<addClaimLineModalProps> = ({ open, onClose, on
|
|
|
46
54
|
}
|
|
47
55
|
function getClaimLineDto(): AddClaimLineDto {
|
|
48
56
|
return {
|
|
49
|
-
consentToken: billItem.consent_token,
|
|
57
|
+
consentToken: (consentTokenProp || billItem.consent_token || '').trim(),
|
|
50
58
|
interventionCode: billItem.intervention_code,
|
|
51
59
|
unitPrice: String(billItem.item_price),
|
|
52
60
|
quantity: String(billItem.item_quantity),
|
|
@@ -18,6 +18,7 @@ import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
|
|
|
18
18
|
import BillDetails from './bill-details/bill-details';
|
|
19
19
|
import PatientClaimDetails from './claim-details/patient-claim-details.component';
|
|
20
20
|
import { type AmrsVisitDiagnosisDto, type AmrsVisitDiagnosis,type AmrsMaternityDiagnosisDto } from '../../../types';
|
|
21
|
+
import { resolveConsentTokenFromBillLines } from '../../v2/patient-bill-details/payment-mode';
|
|
21
22
|
interface patientBillDetailsProps {
|
|
22
23
|
patientUuid: string;
|
|
23
24
|
locationUuid: string;
|
|
@@ -60,7 +61,7 @@ const PatientBillDetails: React.FC<patientBillDetailsProps> = ({ patientUuid, lo
|
|
|
60
61
|
const data = await fetchPatientFacilityBillDetails(patientBillPayload);
|
|
61
62
|
if (data) {
|
|
62
63
|
setPatientBillDetails(data);
|
|
63
|
-
setConsentToken(data
|
|
64
|
+
setConsentToken(resolveConsentTokenFromBillLines(data));
|
|
64
65
|
}
|
|
65
66
|
} catch (error) {
|
|
66
67
|
showSnackbar({
|
|
@@ -15,6 +15,7 @@ import { launchWorkspace, showSnackbar } from '@openmrs/esm-framework';
|
|
|
15
15
|
import {
|
|
16
16
|
checkPreauthStatus,
|
|
17
17
|
invalidatePreauthPreview,
|
|
18
|
+
isPreauthNeedsClarification,
|
|
18
19
|
type PreauthCheckKind,
|
|
19
20
|
} from '../../../../claims/claims.resource';
|
|
20
21
|
import EmptyState from '../shared/empty-state.component';
|
|
@@ -222,12 +223,14 @@ const PreauthList: React.FC<PreauthListProps> = ({ locationUuid, billingDate, on
|
|
|
222
223
|
const flags = interventionFlagsFromBillItem(item);
|
|
223
224
|
const meta = rowMeta[key];
|
|
224
225
|
const elective = needsElectivePreauth(item);
|
|
225
|
-
//
|
|
226
|
+
// Not raised, terminal failure, or clarification → Raise / Resubmit.
|
|
227
|
+
// Other pending / finalised states stay blocked.
|
|
226
228
|
const canRaise =
|
|
227
229
|
meta?.kind === 'not_raised' ||
|
|
228
230
|
meta?.kind === 'failed' ||
|
|
231
|
+
isPreauthNeedsClarification(meta?.status ?? '') ||
|
|
229
232
|
(elective && meta?.kind === 'no_token');
|
|
230
|
-
const showNotes = Boolean(meta?.notes?.trim()) &&
|
|
233
|
+
const showNotes = Boolean(meta?.notes?.trim()) && meta?.kind !== 'not_raised';
|
|
231
234
|
return (
|
|
232
235
|
<TableRow key={key}>
|
|
233
236
|
<TableCell>
|
|
@@ -257,7 +260,9 @@ const PreauthList: React.FC<PreauthListProps> = ({ locationUuid, billingDate, on
|
|
|
257
260
|
<TableCell>
|
|
258
261
|
{canRaise ? (
|
|
259
262
|
<Button kind="ghost" size="sm" onClick={() => handleRaise(item)}>
|
|
260
|
-
|
|
263
|
+
{meta?.kind === 'failed' || isPreauthNeedsClarification(meta?.status ?? '')
|
|
264
|
+
? 'Resubmit preauth'
|
|
265
|
+
: 'Raise preauth'}
|
|
261
266
|
</Button>
|
|
262
267
|
) : (
|
|
263
268
|
'—'
|
|
@@ -1060,6 +1060,11 @@ export {
|
|
|
1060
1060
|
usePreauthPreview,
|
|
1061
1061
|
isPreauthFinalised,
|
|
1062
1062
|
isPreauthTerminalFailure,
|
|
1063
|
+
isPreauthNeedsClarification,
|
|
1064
|
+
isPreauthResubmittable,
|
|
1065
|
+
interventionHasBlockingPreauth,
|
|
1066
|
+
interventionHasFailedPreauth,
|
|
1067
|
+
interventionAllowsPreauthResubmit,
|
|
1063
1068
|
invalidatePreauthPreview,
|
|
1064
1069
|
preauthPreviewSwrKey,
|
|
1065
1070
|
type PreauthCheckKind,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
type PreauthFormPayload,
|
|
28
28
|
} from '../../../../claims/claims.resource';
|
|
29
29
|
import { cancelAllPendingAuthorizations, sendClaimsOTP, authorizeClaimsWithOtp } from '../../../../registry/hie.resource';
|
|
30
|
-
import { addClaimDiagnosis, fetchPatientDiagnosesForBilling } from '../../../billing-claims.resource';
|
|
30
|
+
import { addClaimDiagnosis, fetchPatientDiagnosesForBilling, preferredDiagnosisForPreauth } from '../../../billing-claims.resource';
|
|
31
31
|
import { ensureInterventionOnVisit } from '../../../../claims/interventions.resource';
|
|
32
32
|
import { type AmrsVisitDiagnosis } from '../../../types';
|
|
33
33
|
import { type PatientFacilityBillDetails } from '../types';
|
|
@@ -75,7 +75,9 @@ const diagnosisPickLabel = (item: DiagnosisPick | null) => {
|
|
|
75
75
|
if (!item) return '';
|
|
76
76
|
if (item.kind === 'visit') {
|
|
77
77
|
const d = item.dx;
|
|
78
|
-
|
|
78
|
+
const rank =
|
|
79
|
+
d.dx_rank != null && Number.isFinite(Number(d.dx_rank)) ? ` · Rank ${Number(d.dx_rank)}` : '';
|
|
80
|
+
return `${d.icd11_code ?? '—'} · ${d.concept_source_name || d.encounter_type || 'Visit diagnosis'}${rank}`;
|
|
79
81
|
}
|
|
80
82
|
return `${item.hit.icd11Code} · ${item.hit.display}`;
|
|
81
83
|
};
|
|
@@ -428,9 +430,11 @@ const PreauthForm: React.FC<PreauthWorkspaceProps> = ({
|
|
|
428
430
|
});
|
|
429
431
|
if (!cancelled) {
|
|
430
432
|
setVisitDiagnoses(results ?? []);
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
433
|
+
// Prefer dx_rank === 1; otherwise best-ranked ICD-coded row. Multiple options
|
|
434
|
+
// stay available in the ComboBox (already ordered by rank from the fetch).
|
|
435
|
+
const preferred = preferredDiagnosisForPreauth(results ?? []);
|
|
436
|
+
if (preferred) {
|
|
437
|
+
applyDiagnosisPick(visitDxPick(preferred), { fromUser: false });
|
|
434
438
|
}
|
|
435
439
|
}
|
|
436
440
|
} catch {
|
|
@@ -1231,7 +1235,7 @@ const PreauthForm: React.FC<PreauthWorkspaceProps> = ({
|
|
|
1231
1235
|
|
|
1232
1236
|
<div className={styles.searchBlock}>
|
|
1233
1237
|
<p className={styles.fieldHint}>
|
|
1234
|
-
Diagnosis (ICD-11)
|
|
1238
|
+
Diagnosis (ICD-11). Prefills rank 1 when available; choose another if needed.
|
|
1235
1239
|
</p>
|
|
1236
1240
|
{loadingDx ? (
|
|
1237
1241
|
<InlineLoading description="Loading patient diagnoses…" />
|
|
@@ -93,6 +93,11 @@ export type AmrsVisitDiagnosis = {
|
|
|
93
93
|
value_coded?: number | null;
|
|
94
94
|
/** Encounter diagnosis coded concept (/patient/encounter-diagnosis). */
|
|
95
95
|
diagnosis_coded?: number | null;
|
|
96
|
+
/**
|
|
97
|
+
* Diagnosis rank from encounter-diagnosis ETL (1 = primary / preferred for preauth).
|
|
98
|
+
* Lower ranks are preferred when multiple diagnoses are present.
|
|
99
|
+
*/
|
|
100
|
+
dx_rank?: number | null;
|
|
96
101
|
concept_source_name: string;
|
|
97
102
|
hl7_code: string;
|
|
98
103
|
icd11_code: string;
|
|
@@ -876,7 +876,7 @@ export async function fetchPreauthPreviewRowsForTokens(
|
|
|
876
876
|
return rows;
|
|
877
877
|
}
|
|
878
878
|
|
|
879
|
-
const PREAUTH_TERMINAL_FAILURE = new Set(['REJECTED', 'CANCELLED', 'FAILED', 'DECLINED']);
|
|
879
|
+
const PREAUTH_TERMINAL_FAILURE = new Set(['REJECTED', 'CANCELLED', 'CANCELED', 'FAILED', 'DECLINED']);
|
|
880
880
|
|
|
881
881
|
const PREAUTH_SUBMITTED = new Set([
|
|
882
882
|
'ACTIVE',
|
|
@@ -960,15 +960,33 @@ export function extractPreauthCodeForIntervention(
|
|
|
960
960
|
}
|
|
961
961
|
|
|
962
962
|
/**
|
|
963
|
-
* True when preview already has a non-failed preauth for this
|
|
964
|
-
* Raise should be hidden
|
|
963
|
+
* True when preview already has a non-failed, non-clarification preauth for this
|
|
964
|
+
* intervention — Raise should be hidden. Terminal failure and clarification allow
|
|
965
|
+
* reopening the form to resubmit.
|
|
965
966
|
*/
|
|
966
967
|
export function interventionHasBlockingPreauth(preview: unknown, interventionCode: string): boolean {
|
|
967
968
|
const item = findPreauthPreviewForIntervention(preview, interventionCode);
|
|
968
969
|
if (!item) return false;
|
|
969
970
|
const status = statusFromPreviewItem(item);
|
|
970
971
|
if (!status) return true; // row exists but status blank — treat as already raised
|
|
971
|
-
return !
|
|
972
|
+
return !isPreauthResubmittable(status);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* True when this intervention's preauth failed or needs clarification —
|
|
977
|
+
* UI can offer Resubmit and reopen the preauth form.
|
|
978
|
+
*/
|
|
979
|
+
export function interventionHasFailedPreauth(preview: unknown, interventionCode: string): boolean {
|
|
980
|
+
const status = extractPreauthStatusForIntervention(preview, interventionCode);
|
|
981
|
+
return Boolean(status) && isPreauthResubmittable(status);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/** Alias for clarity at call sites that mean "resubmit", not only hard failure. */
|
|
985
|
+
export function interventionAllowsPreauthResubmit(
|
|
986
|
+
preview: unknown,
|
|
987
|
+
interventionCode: string,
|
|
988
|
+
): boolean {
|
|
989
|
+
return interventionHasFailedPreauth(preview, interventionCode);
|
|
972
990
|
}
|
|
973
991
|
|
|
974
992
|
export function extractPreauthStatus(preview: unknown): string {
|
|
@@ -1014,7 +1032,15 @@ export function isPreauthFinalised(status: string): boolean {
|
|
|
1014
1032
|
}
|
|
1015
1033
|
|
|
1016
1034
|
export function isPreauthTerminalFailure(status: string): boolean {
|
|
1017
|
-
|
|
1035
|
+
const s = (status || '').toUpperCase();
|
|
1036
|
+
if (PREAUTH_TERMINAL_FAILURE.has(s)) return true;
|
|
1037
|
+
// HIE sometimes returns prefixed / alternate spellings (e.g. PREAUTH_CANCELLED).
|
|
1038
|
+
return s.includes('CANCEL');
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/** Failure, cancellation, or clarification — provider may reopen the preauth form and resubmit. */
|
|
1042
|
+
export function isPreauthResubmittable(status: string): boolean {
|
|
1043
|
+
return isPreauthTerminalFailure(status) || isPreauthNeedsClarification(status);
|
|
1018
1044
|
}
|
|
1019
1045
|
|
|
1020
1046
|
/** Statuses that mean the preauth was accepted by HIE — form can close. */
|
|
@@ -1085,7 +1111,8 @@ export async function checkPreauthStatus(
|
|
|
1085
1111
|
if (isPreauthTerminalFailure(status)) {
|
|
1086
1112
|
return { status, preview, kind: 'failed', preauthCode, notes };
|
|
1087
1113
|
}
|
|
1088
|
-
//
|
|
1114
|
+
// Clarification stays `pending` for status-tag colouring ("Needs clarification"),
|
|
1115
|
+
// but is not a blocking preauth — callers use isPreauthNeedsClarification / resubmit helpers.
|
|
1089
1116
|
return { status, preview, kind: 'pending', preauthCode, notes };
|
|
1090
1117
|
} catch (e: unknown) {
|
|
1091
1118
|
const message = e instanceof Error ? e.message : String(e ?? 'Failed to get preauth preview');
|