CheckVisitGFEComplianceBatch
Overview
CheckVisitGFEComplianceBatchTask calculates Good Faith Estimate (GFE) compliance status for all visits in the VisitBatch table. It determines whether visits requiring GFEs have had compliant estimates sent on time, calculates due dates based on federal regulations, and identifies visits that need GFE letter resends due to changes after the initial letter was sent.
Use this task when: You need to audit GFE compliance for a batch of visits, identify visits requiring GFE letter resends due to changes, or prepare compliance data before running AutoSendLetters tasks.
Don't use this task when: Processing individual visit compliance in real-time (use VisitGFEComplianceCalculator directly), working with visits not in the batch table, or when GFE functionality is not enabled for the customer.
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| None | - | - | - | This task has no configurable parameters. It processes all visits in the VisitBatch table using the customer's GFEConfig settings. |
Note: The task behavior is controlled by:
- Customer.GFEConfig: Defines which visit types and insurances require GFEs (configured at customer level)
- VisitBatch table contents: Only visits loaded into VisitBatch are processed
- Federal GFE regulations: Hard-coded rules for due date calculation (1 business day for 3-10 day notice, 3 business days for 10+ day notice)
Execution Flow
flowchart TD
A[Start CheckVisitGFEComplianceBatch] --> B[Clear VisitGFEComplianceBatch table]
B --> C[Get all visits from VisitBatch]
C --> D[Load related data for all visits]
D --> E[Create dictionaries: VisitChangeEvents, PatientLetterSendEvents, PatientLetters]
E --> F{Any visits in batch?}
F -->|No| Z[Exit - No compliance records created]
F -->|Yes| G[Loop through each visit]
G --> H[Create VisitGFECalculationItem for visit]
H --> I[Get most recent GFE-specific VisitChangeEvent]
I --> J[Get GFE letters for visit]
J --> K[Filter to letters created after most recent change]
K --> L[Get compliant send events with no errors]
L --> M[Calculate compliance for visit]
M --> N{Does visit require GFE?}
N -->|No - Less than 3 business days notice| O[Set IsGFERequired=false, IsGFECompliant=true]
N -->|No - Not configured in GFEConfig| O
N -->|Yes| P[Calculate GFE due date]
P --> Q{Letters sent before due date?}
Q -->|Yes, after last change| R[Set IsGFECompliant=true, IsResendRequired=false]
Q -->|No or not after last change| S{GFE letters exist?}
S -->|Yes| T[Set IsGFECompliant=false, IsResendRequired=true]
S -->|No| U[Set IsGFECompliant=false, IsResendRequired=false]
O --> V[Add to calculated compliances list]
R --> V
T --> V
U --> V
V --> W{More visits?}
W -->|Yes| G
W -->|No| X[Bulk save all VisitGFECompliances to batch table]
X --> Y[End]
style B fill:#ffe1e1
style M fill:#e1f5ff
style X fill:#e1f5ff
Processing Algorithm
The task uses federal GFE regulations to determine compliance:
GFE Requirement Rules
A visit requires a GFE if ALL of the following are true:
- Advance notice: Visit scheduled 3+ business days after creation (using
SourceCreatedOnorCreatedOn) - Configuration match: Visit's insurance and/or visit type matches customer's
GFEConfig.InsurancesandGFEConfig.VisitTypes- If both lists are empty: ALL visits require GFE
- If only insurances configured: Match on insurance only
- If only visit types configured: Match on visit type only
- If both configured: Must match both insurance AND visit type
Due Date Calculation
Business days between creation and scheduled time:
- 3-9 business days: Due date = Creation date + 1 business day
- 10+ business days: Due date = Creation date + 3 business days
- Less than 3 business days: No GFE required
Federal holidays are excluded from business day calculations using FederalHolidayCalendar.
Compliance Determination
IsGFECompliant = true IF:
- Visit does not require GFE, OR
- At least one PatientLetterSendEvent exists where:
* SendEvent.CreatedOn <= DueDate
* Letter.IsGoodFaithEstimate = true
* Letter was created after most recent GFE-specific change
* SendEvent has no errors (LetterSendErrors.Count = 0)
IsResendRequired = true IF:
- Visit requires GFE, AND
- GFE letters exist for the visit, AND
- No compliant send events exist before due date
GFE-Specific Visit Changes
Only these change types trigger GFE resend requirements:
InsuranceChangedChargesChangedProviderChangedFacilityChangedDepositAmountChanged
Other changes (like PatientNameChanged) do NOT require GFE resends.
Example Execution
Scenario: Visit created on July 18, scheduled for October 18
- Business days calculation: 10+ business days between creation and scheduled time
- Due date: July 18 + 3 business days = July 21
- Letter sent: July 20 with successful send event
- Result:
IsGFECompliant = true,IsResendRequired = false
Scenario: Same visit, but charges changed on July 22
- Most recent change: July 22 (ChargesChanged)
- Existing letter: Created July 18 (before change)
- Compliant send events: None after July 22
- Result:
IsGFECompliant = false,IsResendRequired = true,VisitChangeEventKey = "VCE-XYZ"
Usage Examples
Example 1: Basic compliance calculation
// No parameters needed - processes entire VisitBatch
var task = new CheckVisitGFEComplianceBatchTask();
task.Execute(dataStore);
// Results are written to VisitGFEComplianceBatch table
// Query to see compliance results:
// SELECT * FROM VisitGFEComplianceBatch WHERE IsGFECompliant = 0
Example 2: Part of a visit processing pipeline
// Step 1: Load visits into batch
var loadVisitsTask = new LoadVisitsTask { /* query configuration */ };
loadVisitsTask.Execute(dataStore);
// Step 2: Calculate compliance
var complianceTask = new CheckVisitGFEComplianceBatchTask();
complianceTask.Execute(dataStore);
// Step 3: Send letters to non-compliant visits
var autoSendTask = new AutoSendLettersTask();
autoSendTask.Execute(dataStore);
Example 3: Compliance auditing after visit changes
// After logging visit changes with LogVisitChangeEventsBatchTask,
// recalculate compliance to identify resend requirements
var changeEventsTask = new LogVisitChangeEventsBatchTask();
changeEventsTask.Execute(dataStore);
var complianceTask = new CheckVisitGFEComplianceBatchTask();
complianceTask.Execute(dataStore);
// Query visits requiring resends
string sql = @"
SELECT v.Key, v.PatientName, v.ScheduledTime,
gfe.DueDate, gfe.VisitChangeEventKey
FROM VisitBatch v
INNER JOIN VisitGFEComplianceBatch gfe ON v.Key = gfe.Key
WHERE gfe.IsResendRequired = 1";
Example 4: Checking compliance before SyncBatch
// Calculate compliance for visits in batch
var complianceTask = new CheckVisitGFEComplianceBatchTask();
complianceTask.Execute(dataStore);
// Sync batch data to production tables
// (This promotes VisitGFEComplianceBatch → VisitGFECompliance)
var syncTask = new SyncBatchTask();
syncTask.Execute(dataStore);
Related Tasks Comparison
| Task | Use Case | Data Source | Writes To | Real-Time |
|---|---|---|---|---|
| CheckVisitGFEComplianceBatch | Batch compliance calculation for all visits in batch table | VisitBatch | VisitGFEComplianceBatch | No (batch only) |
LogVisitChangeEventsBatch |
Track changes to visits that may require GFE resends | VisitBatch vs Visit comparison | VisitChangeEventBatch | No (batch only) |
AutoSendLetters |
Generate and send GFE letters for compliant visits | VisitBatch + AutoSendLetterConfig | PatientLetter, PatientLetterSendEvent | No (batch only) |
AutoSendLettersForFutureVisits |
Generate GFE letters for future visits | Visit table (future scheduled) | PatientLetter, PatientLetterSendEvent | No (scheduled task) |
SyncBatch |
Promote batch compliance data to production | VisitGFEComplianceBatch | VisitGFECompliance | No (batch only) |
When to use which:
- Use CheckVisitGFEComplianceBatch after loading visits to batch and before sending letters
- Use LogVisitChangeEventsBatch before CheckVisitGFEComplianceBatch if you need to track what changed
- Use AutoSendLetters after CheckVisitGFEComplianceBatch to act on compliance results
- Use SyncBatch after all batch processing to promote results to production tables
Performance Considerations
Database Impact
Tables Read:
VisitBatch- All visits (primary data source)VisitChangeEventBatch- All change events for visits in batchPatientLetter- All GFE letters (filtered byIsGoodFaithEstimate = 1)PatientLetterSendEvent- All send events for visits in batch
Tables Written:
VisitGFEComplianceBatch- Truncated then bulk inserted with all compliance records
Query Patterns:
- Initial data loading uses
GetAllBatchVisits(),GetVisitChangeEventsForVisitBatch(), etc. - Data loaded once and processed in memory using dictionaries for O(1) lookups
- Bulk save operation for all compliance records at end
Optimization Tips
| Scenario | Recommendation | Rationale |
|---|---|---|
| Large batch sizes (10K+ visits) | Consider breaking into smaller batches or running during off-hours | Memory usage grows with batch size; dictionaries hold all related data in memory |
| First-time GFE enablement | Run for historical visits separately from daily processing | Initial run processes all visits; subsequent runs only process new/changed visits |
| Frequent visit changes | Run LogVisitChangeEventsBatch before this task | Ensures most recent changes are captured for resend determination |
| Performance monitoring | Track execution time and batch size | Typical performance: 1,000 visits processed in < 5 seconds |
Memory Considerations
The task loads all related data into memory dictionaries:
- VisitChangeEvents: One list per visit key
- PatientLetters: One list per visit key
- PatientLetterSendEvents: One list per visit key
For a batch of 10,000 visits with average of 2 change events, 3 letters, and 3 send events each:
- Estimated memory: ~50-100 MB for object graphs
Concurrent Execution
Not Safe: Do not run multiple instances concurrently
- Truncates
VisitGFEComplianceBatchtable at start - No locking mechanism for batch table access
- Risk of data loss if two instances run simultaneously
Error Handling
The task uses a fail-fast approach:
public void Execute()
{
// Truncates batch table
visitGFEComplianceRepo.ClearVisitGFEComplianceBatch();
// Get all data (throws on database errors)
List<VisitGFECalculationItem> items =
batchVisitGFECalculationItemFactory.GetForVisitBatch();
// Calculate compliance for all visits
List<VisitGFECompliance> compliances =
visitGFEComplianceCalculator.CalculateVisitGFECompliances(items);
// Bulk save (throws on database errors)
visitGFEComplianceRepo.SaveManyBatch(compliances);
}
Error Behavior:
- Database connection errors: Task fails immediately, no partial results
- Data loading errors: Task fails before any calculations
- Calculation errors: Not expected - calculation logic is deterministic
- Save errors: Task fails after calculations but before commit
Important: The task does NOT:
- Continue processing on individual visit errors (no try-catch per visit)
- Log partial failures to database
- Retry failed operations
- Preserve previous batch table data on failure (truncated at start)
Rollback Behavior:
- If task fails after truncation but before save,
VisitGFEComplianceBatchtable will be empty - No transaction wrapping means partial failure leaves table empty
- Recommended: Run task as part of larger transactional job if needed
Common Pitfalls
| Issue | Problem | Solution |
|---|---|---|
| Empty VisitGFEComplianceBatch table | VisitBatch table is empty or not populated | Run LoadVisitsTask or SyncBatchTask to populate VisitBatch before running compliance check |
| All visits show IsGFERequired=false | Customer.GFEConfig not configured | Verify Customer.GFEConfig.Insurances and Customer.GFEConfig.VisitTypes are populated with appropriate values |
| Due dates are null | Visit.ScheduledTime is null | Ensure visits have scheduled times; visits without scheduled times cannot have due dates calculated |
| Compliance always false | PatientLetterSendEvent records missing or have errors | Check that AutoSendLetters task successfully sent letters; verify LetterSendErrors collection is empty |
| IsResendRequired not triggering | VisitChangeEventBatch not populated | Run LogVisitChangeEventsBatchTask before compliance task to capture visit changes |
| Wrong business day calculations | Federal holidays not recognized | Task uses FederalHolidayCalendar; verify holiday calendar is up to date for current year |
| Resend logic not considering changes | GFE-specific change types not logged | Only specific change types trigger resends (InsuranceChanged, ChargesChanged, etc.); verify change events include these types |
| Compliance data not in production | SyncBatch not run after compliance task | Run SyncBatchTask to promote VisitGFEComplianceBatch → VisitGFECompliance for production use |
| SourceCreatedOn vs CreatedOn confusion | Visit creation date affects due date calculation | Task prefers SourceCreatedOn (from source system) over CreatedOn (MDClarity import time) for due date calculation |
Code References
- Task Definition:
MDClarityCore/Backend/Visits/Implementations/CheckVisitGFEComplianceBatchTask.cs:12 - Task Field Definition:
MDClarityCore/Backend/Visits/Implementations/CheckVisitGFEComplianceBatchTask.cs:38 - Execute Method:
MDClarityCore/Backend/Visits/Implementations/CheckVisitGFEComplianceBatchTask.cs:19 - Executor Logic:
MDClarityCore/Backend/Visits/Implementations/CheckVisitGFEComplianceBatchExecutor.cs:14 - Executor Execute Method:
MDClarityCore/Backend/Visits/Implementations/CheckVisitGFEComplianceBatchExecutor.cs:30 - Compliance Calculator:
MDClarityCore/Backend/Visits/Implementations/VisitGFEComplianceCalculator.cs:11 - Batch Calculation Item Creator:
MDClarityCore/Backend/Visits/Implementations/BatchVisitGFECalculationItemCreator.cs:11 - Calculation Item Factory Method:
MDClarityCore/Backend/Visits/Implementations/BatchVisitGFECalculationItemCreator.cs:26 - Compliance Calculation Logic:
MDClarityCore/Backend/Visits/Implementations/VisitGFEComplianceCalculator.cs:44 - GFE Requirement Logic:
MDClarityCore/Backend/Visits/Implementations/VisitGFEComplianceCalculator.cs:138 - Due Date Calculation:
MDClarityCore/Backend/Visits/Implementations/VisitGFEComplianceCalculator.cs:123 - Resend Required Logic:
MDClarityCore/Backend/Visits/Implementations/VisitGFEComplianceCalculator.cs:84 - VisitGFECompliance Entity:
MDClarityCore/Models/Entities/VisitGFECompliance.cs:12 - VisitGFECalculationItem:
MDClarityCore/Backend/Visits/VisitGFECalculationItem.cs:12 - GFEConfig Model:
MDClarityCore/Backend/GFE/DataModel/GFEConfig.cs:12 - Integration Tests:
MDClarityCore/MDClarityTest/Tests/IntegrationTests/Backend/General Tasks/CheckVisitGFEComplianceBatchTests.cs:14