AutoApplyBundlesToVisitBatch
Overview
AutoApplyBundlesToVisitBatchTask automatically identifies and applies matching charge bundles to all visits in the batch table. It matches each visit to a bundle based on facility, visit type, insurance, and custom properties, then replaces visit charges with bundle charges and generates corresponding quotes for each service type.
Use this task when: You need to bulk-apply standardized charge bundles to visits loaded in batch mode, ensuring consistent pricing across visits that match bundle criteria.
Don't use this task when:
- Processing individual visits interactively (use the UI or real-time bundle application)
- Visits already have manually entered charges that shouldn't be replaced
- No bundles are configured for the visit combinations in your batch
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| None | - | - | - | This task has no configurable parameters. It operates on all visits in the VisitBatch table. |
Execution Flow
flowchart TD
A[Start AutoApplyBundlesToVisitBatchTask] --> B[Get all visits from VisitBatch]
B --> C[Get all quotes from QuoteBatch]
C --> D[Join visits to their quotes]
D --> E[Get custom properties for all batch visits]
E --> F{Any visits?}
F -->|No| Z[End]
F -->|Yes| G[Get all configured bundles for customer]
G --> H[For each visit in batch]
H --> I{Visit has charges but no bundle?}
I -->|Yes| P[Skip - preserve manual charges]
I -->|No| J[Find bundles matching visit criteria]
J --> K{Matching bundles found?}
K -->|No| P
K -->|Yes| L{Multiple matching bundles?}
L -->|Yes| M[Log warning - overlapping criteria detected]
L -->|No| N[Take first matching bundle]
M --> N
N --> O{Should apply bundle?}
O -->|No - bundle already applied and unchanged| P
O -->|Yes| Q[Clear existing charges from visit]
Q --> R[Add zero charge type if needed]
R --> S[Copy charges from bundle to visit]
S --> T[Generate quotes for each service type]
T --> U[Set BundleKey and BundleApplicationTime]
U --> V[Log bundle application activity]
V --> P[Next visit]
P --> W{More visits?}
W -->|Yes| H
W -->|No| X[Save all visits to VisitBatch in bulk]
X --> Y[Assign keys and save all quotes to QuoteBatch]
Y --> Z
style G fill:#e1f5ff
style J fill:#fff4e1
style S fill:#fff4e1
style X fill:#e1f5ff
style Y fill:#e1f5ff
Processing Algorithm
The task uses a rule-based bundle matching algorithm to apply appropriate charge bundles to each visit:
Bundle Matching Process
- Load Data: Retrieve all visits from VisitBatch, quotes from QuoteBatch, custom properties, and all configured bundles
- For Each Visit:
- Skip if has manual charges: If visit has charges but no BundleKey, preserve the manual charges and skip
- Find Matching Bundles: Use BundleFinder to identify bundles where:
- Bundle.Facilities includes visit's facility (or is empty/matches all)
- Bundle.VisitTypes includes visit's visit type
- Bundle.Insurances includes visit's insurance
- Bundle custom property criteria match visit's custom properties
- Handle Multiple Matches: If multiple bundles match, log a warning about overlapping criteria and use the first match
- Check if Should Apply:
- Apply if visit has no bundle assigned yet
- Apply if bundle has changed (different BundleKey)
- Apply if bundle was updated since last application (Bundle.UpdatedOn > visit.BundleApplicationTime)
- Skip if same bundle already applied and unchanged
- Apply Bundle:
- Clear all existing charges from visit
- Add zero charge type if bundle doesn't start with one
- Copy all charges from bundle to visit
- Create quotes for each unique service type in the charges
- Set visit.BundleKey and visit.BundleApplicationTime
- Log the bundle application activity
- Save in Bulk: Save all modified visits to VisitBatch and all quotes to QuoteBatch using bulk operations
Example Execution
For a batch with 3 visits:
Visit V-1: Facility=FAC-001, VisitType=OP, Insurance=Aetna
- Find bundles matching FAC-001, OP, Aetna
- Match found: Bundle B-100 (Outpatient Physical Therapy Bundle)
- B-100 has 3 charges: Zero charge + PT eval (service type 98) + PT treatment (service type 98)
- Clear V-1 charges, copy B-100 charges
- Create 1 quote for service type 98
- Set V-1.BundleKey = "B-100", V-1.BundleApplicationTime = now
Visit V-2: Facility=FAC-001, VisitType=OP, Insurance=Medicare, BundleKey=B-101
- Find bundles matching FAC-001, OP, Medicare
- Match found: Bundle B-101 (unchanged since last application)
- Skip - bundle already applied and not updated
Visit V-3: Facility=FAC-002, VisitType=IP, Insurance=BCBS, Charges=[manual charge]
- Has charges but no BundleKey (manual entry)
- Skip - preserve manual charges
Result: V-1 updated with bundle, V-2 unchanged, V-3 unchanged
Usage Examples
Example 1: Basic batch processing
// After loading visits from an external source into VisitBatch
var task = new AutoApplyBundlesToVisitBatchTask();
// No parameters needed - automatically processes all VisitBatch records
Example 2: Part of a visit import pipeline
// Step 1: Load visits from HL7 or data file into VisitBatch
var loadTask = new LoadHL7FilesTask { ... };
// Step 2: Apply bundles to standardize charges
var applyBundlesTask = new AutoApplyBundlesToVisitBatchTask();
// Step 3: Calculate estimates
// (Visit calculation task or EstimationProcessor)
// Step 4: Send patient letters
var sendLettersTask = new AutoSendLettersTask();
Example 3: Reapplying updated bundles
// Scenario: User updated Bundle B-100 configuration in UI
// The Bundle.UpdatedOn timestamp is now newer than existing visit.BundleApplicationTime values
// Load affected visits back into VisitBatch (via SQL or ReprocessChangedConfigurations)
// Then run AutoApplyBundlesToVisitBatchTask
var task = new AutoApplyBundlesToVisitBatchTask();
// Task will detect Bundle.UpdatedOn > visit.BundleApplicationTime and reapply the updated bundle
Example 4: Scheduled nightly bundle application
// Run nightly to apply bundles to new visits loaded during the day
// Assumes an upstream process loads new visits into VisitBatch
var task = new AutoApplyBundlesToVisitBatchTask();
// Automatically handles:
// - New visits with no bundle → applies matching bundle
// - Visits with unchanged bundles → skips
// - Visits with updated bundles → reapplies
// - Visits with manual charges → preserves them
Related Tasks Comparison
| Task | Use Case | Scope | Bundle Handling | Quote Generation |
|---|---|---|---|---|
| AutoApplyBundlesToVisitBatch | Bulk bundle application to batch visits | All VisitBatch records | Automatic matching and application | Creates quotes for bundle service types |
BundleRecomputeTask |
Recalculate estimates for visits with bundles already applied | Visits with existing bundles | Reprocesses existing bundle assignments | Maintains existing quotes, recalculates estimates |
ReprocessChangedConfigurationsTask |
Queue visits affected by bundle configuration changes | Visits matching changed bundle criteria | Identifies visits needing reprocessing | Queues visits for later processing (doesn't apply bundles) |
When to use each:
- Use AutoApplyBundlesToVisitBatch for initial bundle application to new visits in batch mode
- Use BundleRecomputeTask when bundles are already applied but estimates need recalculation (pricing changes, etc.)
- Use ReprocessChangedConfigurationsTask first to identify affected visits, then AutoApplyBundlesToVisitBatch to reapply
Performance Considerations
Database Impact
- Tables Read:
VisitBatch- all recordsQuoteBatch- all recordsBundle- all configured bundlesCustomPropertyMember- batch visit custom properties
- Tables Written:
VisitBatch- bulk update of modified visitsQuoteBatch- bulk insert/update of generated quotesActivityLog- activity logging for bundle applications
Optimization Tips
| Scenario | Recommendation | Rationale |
|---|---|---|
| Large batches (>10,000 visits) | Process in smaller batch chunks | Reduces memory usage and transaction time; consider splitting into multiple batch loads |
| Many bundle configurations (>100) | Review bundle criteria for overlaps | Multiple matching bundles cause warnings and slow down matching; ensure mutually exclusive criteria |
| Frequent bundle updates | Use ReprocessChangedConfigurationsTask first |
Only queue affected visits rather than reprocessing entire batch |
| Mixed manual and bundle visits | Separate batch loads | Process manual-charge visits separately to avoid unnecessary matching logic |
Bulk Operations
The task uses bulk save operations for performance:
- All visit updates are saved in a single bulk operation to VisitBatch
- All quote updates are saved in a single bulk operation to QuoteBatch
- This minimizes database round trips for large batches
Concurrent Execution
- Safe: Multiple instances can run on different customer databases simultaneously
- Unsafe: Do NOT run multiple instances on the same customer database's VisitBatch concurrently
- Batch table isolation prevents conflicts with real-time visit processing
Error Handling
The task uses a continue-on-error approach for individual visit processing:
// For each visit in batch:
// - If bundle matching fails for one visit, continues to next visit
// - If bundle application fails, error is logged but processing continues
// - All successfully processed visits are saved at the end
Important behaviors:
- Overlapping bundle criteria: Logs a warning when multiple bundles match a single visit but continues processing using the first match
- Missing bundle data: If a bundle is deleted after being referenced by a visit, the visit is skipped
- Custom property errors: If custom property loading fails, matching continues without custom property criteria
- Partial batch success: Successfully processed visits are saved even if some visits encounter errors
Error exposure:
- Errors are logged to the customer's logger (console or database log)
- Activity logs record successful bundle applications
- No exceptions are thrown for individual visit failures; task completes successfully
Common Pitfalls
| Issue | Problem | Solution |
|---|---|---|
| Bundles not applying despite matching criteria | Visit already has charges but no BundleKey (manual entry) | Task preserves manual charges. Either clear charges first or don't set charges before running task |
| Multiple bundles match same visit | Overlapping bundle criteria (same facility, visit type, insurance) | Review bundle configurations to ensure mutually exclusive matching criteria using custom properties or narrower facility/insurance lists |
| Bundle reapplies every run | Bundle.UpdatedOn is always newer than visit.BundleApplicationTime | Check if something is updating Bundle.UpdatedOn unintentionally; bundles should only update when user changes configuration |
| Quotes not generated | Bundle charges don't have service type codes | Ensure bundle charges have EligibilityServiceType dimension member specified in charge codes |
| Performance degradation with large batches | Processing 50,000+ visits in single batch | Split into smaller batches of 5,000-10,000 visits or run multiple executions with filtered batch loads |
| Zero charge type missing | Bundle starts with non-zero charge | Task automatically adds zero charge type if bundle doesn't start with one; if you see duplicates, check bundle definition |
Code References
- Task Definition:
MDClarityCore/Backend/PricingEngine/AutoApplyBundlesToVisitBatchTask.cs:9 - Execution Logic:
MDClarityCore/Backend/PricingEngine/Implmentations/AutoApplyBundlesExecutor.cs:32 - Bundle Matching Algorithm:
MDClarityCore/Backend/Visits/VisitManager.cs:50(ApplyBundles method) - Bundle Application Logic:
MDClarityCore/Backend/Visits/VisitManager.cs:317(ApplyBundle method) - Bulk Save Operations:
MDClarityCore/Backend/Visits/VisitManager.cs:105(ApplyAndSaveBundles method) - Bundle Finder:
MDClarityCore/Backend/PricingEngine/BundleFinder.cs(matching criteria implementation) - Integration Tests:
MDClarityCore/MDClarityTest/Tests/IntegrationTests/Backend/General Tasks/AutoApplyBundlesTests.cs:25