Skip to content

Adds the prior authorisation event construction logic with documentation updates#282

Closed
Akila94 wants to merge 1 commit intomainfrom
prior-auth-event-construct
Closed

Adds the prior authorisation event construction logic with documentation updates#282
Akila94 wants to merge 1 commit intomainfrom
prior-auth-event-construct

Conversation

@Akila94
Copy link
Copy Markdown
Member

@Akila94 Akila94 commented Mar 31, 2026

Adds the prior authorisation event construction logic with documentation updates

Summary by CodeRabbit

  • New Features

    • Introduced Prior Authorisation Analytics with metrics for approval/denial rates and decision time tracking for standard and expedited claims.
    • Added claim priority, review action codes, and SLA violation detection for claim processing.
  • Documentation

    • Updated analytics documentation and Moesif dashboard guides to reflect Prior Authorisation analytics support.
  • Chores

    • Updated package dependencies and analytics dashboard template identifiers.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Walkthrough

This PR introduces prior authorization analytics support by adding new claim processing utilities, defined constants and enum types, updated service handlers to collect analytics data, dashboard templates for visualization, and comprehensive documentation updates describing both CMS and prior authorization metrics.

Changes

Cohort / File(s) Summary
Dependencies & Configuration
fhir-service/Dependencies.toml
Added duplicate version fields to multiple packages and updated ballerinax/health.fhir.r4 from 6.3.1 to 6.3.2.
Type Definitions & Constants
fhir-service/constants.bal, fhir-service/records.bal
Added two new string constants for FHIR review action URLs; introduced three new exported enums (ClaimPriority, X12ReviewActionCodes, ClaimResponseOutcome) and five module-level claim status/type mapping constants.
Service Handler Logic
fhir-service/service.bal
Modified ClaimResponse PUT handler to add error return type and implement analytics collection: extracts claim references, fetches claims, computes analytics fields (claim type, time to decide, status, SLA violation), creates prior authorization analytics events, and stores in FHIR context.
Utility Functions
fhir-service/utils.bal
Added six new isolated helper functions supporting claim processing: determineClaimType, determineClaimStatus, calculateTimeToDecide, isSlaViolated, normalizeDateTimeString, and formatTimeDifference (243 lines of new logic).
Analytics Dashboard Templates
fhir-service/resources/analytics/moesif/moesif-cms-dashboard-template.json, fhir-service/resources/analytics/moesif/prior-auth-analytics-moesif-dashboard-template.json
Updated CMS dashboard IDs and workspace field mappings; introduced comprehensive new Prior Authorisation Analytics dashboard template with nine workspaces covering total submitted requests, claim completion by priority, approval/denial rates, and SLA violations.
Analytics Documentation
fhir-service/resources/analytics/moesif/moesif_README.md, fhir-service/resources/analytics_README.md
Expanded README to cover both CMS and Prior Authorisation analytics; added dashboard import instructions; defined Prior Authorisation metrics (approval/denial percentages, mean decision times) for standard and expedited claims.

Sequence Diagram

sequenceDiagram
    actor Client
    participant ServiceHandler as ClaimResponse Handler
    participant ClaimProcessor as Claim Utils
    participant Database as FHIR Repository
    participant Analytics as Analytics Event
    participant FHIRContext as FHIR Context

    Client->>ServiceHandler: PUT ClaimResponse (outcome=COMPLETED)
    ServiceHandler->>ServiceHandler: Extract claimResponse.request.reference
    ServiceHandler->>ClaimProcessor: Parse Claim ID from reference
    ClaimProcessor-->>ServiceHandler: Claim ID
    ServiceHandler->>Database: Fetch referenced Claim
    Database-->>ServiceHandler: Claim data
    ServiceHandler->>ClaimProcessor: determineClaimType(claim.priority)
    ClaimProcessor-->>ServiceHandler: claimType (STANDARD=1/EXPEDITED=2)
    ServiceHandler->>ClaimProcessor: determineClaimStatus(claimResponse)
    ClaimProcessor-->>ServiceHandler: claimStatus (APPROVED=3/DENIED=5)
    ServiceHandler->>ClaimProcessor: calculateTimeToDecide(timestamps)
    ClaimProcessor-->>ServiceHandler: timeToDecide (hours)
    ServiceHandler->>ClaimProcessor: isSlaViolated(timeToDecide, claimType)
    ClaimProcessor-->>ServiceHandler: isSLAViolated (boolean)
    ServiceHandler->>Analytics: Construct PriorAuthorisationAnalyticsResponseEvent
    Analytics-->>ServiceHandler: Analytics event
    ServiceHandler->>FHIRContext: setProperty(analyticsEvent)
    FHIRContext-->>ServiceHandler: Stored
    ServiceHandler->>Database: Update ClaimResponse
    ServiceHandler-->>Client: ClaimResponse|OperationOutcome|FHIRError|error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 From claims come stories, each one analyzed,
Prior auth pathways now visualized,
Dashboard templates dance in Moesif's light,
SLA metrics computed, approval rates right!
Utils and handlers, a symphony bound,
Analytics rabbit hops all around! 🔍

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal, containing only a brief one-liner and an issue reference. It lacks most required template sections including Purpose, Goals, Approach, User stories, Release notes, and others. Complete the PR description using the repository template. Add sections for Purpose, Goals, Approach, documentation impact, test coverage, security checks, and other relevant template fields.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: adding prior authorisation event construction logic and documentation updates, which aligns with the substantial changes across multiple files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch prior-auth-event-construct

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@fhir-service/Dependencies.toml`:
- Line 80: The TOML file contains duplicate "version" keys inside several
[[package]] blocks causing parse errors; remove the extra "version" entries so
each [[package]] block has a single version key, and update the dependency
auto-generation logic (the code that emits [[package]] blocks) to ensure it
writes only one "version" assignment per package; after changes, validate by
parsing Dependencies.toml with a TOML parser to confirm no "Cannot overwrite a
value" errors remain.

In `@fhir-service/records.bal`:
- Around line 654-658: Remove the trailing semicolons from the enum declarations
to match the file's style; specifically update the ClaimPriority enum (and the
other enums referenced: BulkMatchStatus, DaVinciExportStatus, ResourceType) by
deleting the trailing ";" after the closing brace so the declarations end with
"}" only; ensure you only remove the semicolons and do not alter enum member
names or values.

In `@fhir-service/resources/analytics_README.md`:
- Around line 5-22: The document mixes British "Authorisation" and American
"Authorization"; pick one spelling and make it consistent by renaming the
heading "Prior Authorisation Analytics" and updating all occurrences of
"authorization"/"authorisation" in the section (including the lines listing
standard and expedited prior authorization requests and any mentions like "Prior
Authorization Metrics") and update any referenced Moesif docs links or text to
match the chosen variant so the section reads consistently.

In `@fhir-service/resources/analytics/moesif/moesif_README.md`:
- Around line 21-23: Replace the image-style Markdown for the dashboard
templates with normal links: change the two entries that use "![Sample
...](moesif-cms-dashboard-template.json)" and "![Sample
...](prior-auth-analytics-moesif-dashboard-template.json)" to standard link
syntax like "[Sample CMS Analytics Dashboard
Template](moesif-cms-dashboard-template.json)" and "[Sample Prior Authorisation
Analytics Dashboard
Template](prior-auth-analytics-moesif-dashboard-template.json)" so the JSON
files are clickable imports instead of attempted images.

In
`@fhir-service/resources/analytics/moesif/prior-auth-analytics-moesif-dashboard-template.json`:
- Around line 735-746: The dashboard widget currently has an empty es_query and
a urlQuery grouping by request.route.raw so it shows route volumes; update the
widget's es_query to include the same ClaimResponse/status filters used by the
other prior-auth widgets and add a clause to filter
metadata.priorAuth.isSLAViolated == true (or the equivalent JSON boolean path).
Ensure the es_query contains the ClaimResponse/status conditions and the SLA
boolean filter and leave the urlQuery grouping/metrics as-is so the widget now
only counts events where metadata.priorAuth.isSLAViolated is true and matches
the PA status filters.
- Around line 561-645: The widgets claim "hours" but
metadata.priorAuth.timeToDecide (produced by calculateTimeToDecide() in
fhir-service/utils.bal) is in minutes; update the aggregations named like
metadata__priorAuth__timeToDecide|weighted_avg to convert minutes→hours (divide
the value by 60 in the weighted_avg value via a scripted/value expression) or
alternatively change the widget names/labels to "minutes" consistently; apply
the same fix to the other affected widgets (e.g., the one around lines 648-732)
that use metadata.priorAuth.timeToDecide.
- Around line 203-288: The widget's scripted metrics for "% of approved standard
claims" and the other similar widgets only count statuses 3 (approved) and 5
(denied) and therefore exclude PARTIALLY_APPROVED (value 4) from the
denominator, causing percentages to be overstated; update the aggregation
scripts and any formula/denominator references that use
metadata.priorAuth.claimStatus to include status 4 in the total (or explicitly
document intentional exclusion) — search for the scripted metrics named like
"scripted__1221885305|sum" / "scripted__404236855|sum" and the script strings
comparing [metadata.priorAuth.claimStatus] == 3 or == 5 and change them so the
denominator sums include records where claimStatus == 3 OR 4 OR 5 (or adjust the
percentage formula to use sum(approved + partially_approved + denied) as the
denominator), and apply the same change to the other affected widgets referenced
in the comment.

In `@fhir-service/service.bal`:
- Around line 720-728: The timeToDecide is being derived from the incoming
claimResponse.meta?.lastUpdated before persistence; instead compute it from the
server-side persisted completion timestamp returned by updateClaimResponse() (or
the updated ClaimResponse's meta.lastUpdated) after the update succeeds. Move
the call to calculateTimeToDecide to after updateClaimResponse(), pass the
updated/persisted lastUpdated value (not the incoming payload), then build the
r4:PriorAuthorisationAnalyticsResponseEvent and call
fhirContext.setProperty(r4:PRIOR_AUTH_ANALYTICS_EVENT, event) using that
server-derived timeToDecide; ensure you still call isSlaViolated(claimType,
timeToDecide) with the new value.
- Around line 706-728: The analytics enrichment (calls to getById and
claimResource.cloneWithType) must not abort the PUT; wrap the linked-Claim
lookup and clone in a non-throwing guard (e.g., use a var assignment and
type-check or trap) so failures are logged and skipped instead of propagating
via check — locate the isolated resource function put and replace the lines
using check getById(fhirConnector, CLAIM, claimId) and check
claimResource.cloneWithType() with a safe path that on error logs the problem
and skips building/setting the r4:PRIOR_AUTH_ANALYTICS_EVENT (or continues
without calling fhirContext.setProperty), leaving updateClaimResponse() to run
and return its normal result.

In `@fhir-service/utils.bal`:
- Around line 1624-1628: The formatTimeDifference function currently truncates
elapsed seconds to whole hours (int cast), causing near-hour overages to be
lost; change formatTimeDifference to compute hours by dividing diffSeconds by
3600 and rounding up (ceiling) so partial hours count as a full hour (e.g., use
math:ceil on diffSeconds/3600 and return as int); update any callers such as
isSlaViolated to rely on the new behavior.
- Around line 1596-1601: The log message in the SLA branch using the
timeToDecide check incorrectly labels the standard-claim path as "Claim type:
Expedited"; update the debug log in the else branch that returns true to use
"Claim type: Standard" (keep the same template with timeToDecide) so the two
branches correctly report "Expedited" when timeToDecide <= 168 and "Standard"
when > 168; locate the branch using the timeToDecide variable and the existing
log:printDebug calls to make this change.
- Around line 1460-1514: The code counts A1 adjudications across adjudications
but compares to numberOfItems; change counting to be one approval per item:
inside the foreach davincipas:PASClaimResponseItem items loop initialize a local
boolean (e.g., itemApproved) false, then when iterating adjudications/extensions
and you hit a code equal to A1 (within the reviewActionCoding.code check that
uses REVIEW_ACTION_URL and REVIEW_ACTION_CODE_URL), set itemApproved = true,
increment numberOfApprovedAdjudications once for that item, and break out of the
inner adjudication/extension loops so you don’t double-count; ensure
numberOfApprovedAdjudications is only incremented at most once per
davincipas:PASClaimResponseItem.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50329df7-ef50-4653-b7bd-d39e457de65d

📥 Commits

Reviewing files that changed from the base of the PR and between e0570d6 and c6bc69d.

⛔ Files ignored due to path filters (1)
  • fhir-service/resources/analytics/moesif/prior_auth_analytics_sample_moesif_dashboard.png is excluded by !**/*.png
📒 Files selected for processing (9)
  • fhir-service/Dependencies.toml
  • fhir-service/constants.bal
  • fhir-service/records.bal
  • fhir-service/resources/analytics/moesif/moesif-cms-dashboard-template.json
  • fhir-service/resources/analytics/moesif/moesif_README.md
  • fhir-service/resources/analytics/moesif/prior-auth-analytics-moesif-dashboard-template.json
  • fhir-service/resources/analytics_README.md
  • fhir-service/service.bal
  • fhir-service/utils.bal

@Akila94
Copy link
Copy Markdown
Member Author

Akila94 commented Apr 2, 2026

Closing this PR. Please refer to #286

@Akila94 Akila94 closed this Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant