Calculation type

MedicareBilateralSurgeryAdjustment

Applies Medicare's bilateral-surgery payment adjustment via the shared generic BilateralSurgeryV2AdjustmentCalculator<T>: a charge with modifier 50, or the first-encountered line of a same-procedure-code RT/LT pair, is scaled to a percentage of its allowed amount keyed off the procedure's bilateral-surgery rollup indicator (default 150% for indicators 0/1/2, 200% for indicator 3); the second-encountered line of an RT/LT pair is zeroed and its billed (charged) amount is folded into the first line — but only if that second line's allowed amount was nonzero before this adjustment ran.

542
uses
14
customers
Adjustment
category
Charge
applies at

What it computes

potentialAffected = charges i=1..NumCharges-1, !IgnoreCharge, no ExclusionCodes match, whose bilateral rollup indicator (looked up via IBilateralSurgeryScheduleRepo, keyed with an EMPTY ScheduleType string since this class does not implement IScheduleTypeCalculation) resolves a percentage in BilateralPercentageMultipliers. Scanning potentialAffected in raw charge-index order (before any sort): a charge with modifier "50" becomes 'affected' immediately; otherwise, if it carries RT (or LT) and a LATER-scanned charge with the same procedure code carries the complementary LT (or RT), the earlier line becomes 'affected' (kept/scaled) and the later line becomes 'paired' (zeroed) — pairing outcome depends on original charge order, not on adjustment.SortBy. affected ∪ paired.Keys is then sorted by adjustment.SortBy purely for processing order. For each processed charge: if paired -> adjustedAmount = 0; if affected -> percentage = BilateralPercentageMultipliers[Code]/100 where Code comes from `rollups.Where(r => r?.Member == procedureCode).First().Code` (a fresh scan matching by procedure code across the WHOLE rollups array, not the charge's own indexed rollups[chargeIndex] record); adjustedAmount = MoneyMath.Multiply(originalAmount, percentage). If adjustedAmount != detail.Amount: detail.Adjust(adjustedAmount, adjustment), and if this charge is a paired/zeroed line, pairedChargePrimary.AmountCharged += charge.AmountCharged; charge.AmountCharged = 0.

Parameters

KeyMeaning
SortBySortChargesBy enum (default AmountAllowed) controlling only the ORDER charges are processed for Adjust() side effects — it does not decide which line of an RT/LT pair is primary.
BilateralPercentageMultipliersDictionary<indicator string, percentage> (default {"0":150,"1":150,"2":150,"3":200}) applied to a charge's allowed amount when its bilateral rollup indicator resolves via TryGetIndicatorPercentage.
ExclusionCodesList of DimensionMember that, if present on a charge, exclude it from the adjustment entirely.
ModifierDimensionDimension key (default "Modifier") used to detect the bilateral modifier "50" and RT/LT pairing modifiers.

Gotchas

AmountCharged transfer for a paired/zeroed charge is nested inside `if (adjustedAmount != detail.Amount)`. Since a paired charge's adjustedAmount is always 0, if that charge's detail.Amount was ALREADY 0 before this adjustment ran (e.g. zeroed by an earlier calc), the guard `0 != 0` is false, so detail.Adjust never fires AND the AmountCharged roll-up to the primary charge silently never happens — the paired line's billed amount is dropped rather than folded in. // Percentage lookup in GetAdjustedAmount re-scans the whole rollups array by procedure code with an unguarded `.First()` rather than reusing rollups[chargeIndex]; for an RT/LT pair (same procedure code, two lines), this always resolves to whichever line's rollup record appears FIRST in the array, which is usually equivalent but is not literally 'this charge's own record' — a reimplementer indexing directly by chargeIndex would coincidentally get the same answer in the normal case but diverge if the two lines' rollup records ever differ. // Primary-vs-paired assignment for RT/LT pairs is fixed by original charge-array scan order (index 1..N), decided in FindAffectedCharges BEFORE SortBy is applied — SortBy only reorders Adjust() side-effect processing. // ScheduleType is not a property on this class (unlike sibling BilateralSurgeryV2Adjustment, which implements IScheduleTypeCalculation); `(adjustment as IScheduleTypeCalculation)?.ScheduleType ?? ""` always evaluates to empty string here, relying on the Medicare rollup repo to ignore that key. // MoneyMath.Multiply(decimal,double) banker's/ToEven rounding, not decimal AwayFromZero.

In the source

class · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/MedicareBilateralSurgeryAdjustment.cs:8
calculator · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/Calculators/BilateralSurgeryV2AdjustmentCalculator.cs (generic BilateralSurgeryV2AdjustmentCalculator<MedicareBilateralSurgeryAdjustment>, instantiated at CalculationEngine.cs:809)
dispatch · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/CalculationEngine.cs:808

CORRECTED - re-read MedicareBilateralSurgeryAdjustment.cs and the shared generic BilateralSurgeryV2AdjustmentCalculator.cs in full, including FindAffectedCharges/ProcessChargeModifiers/GetAdjustedAmount/AdjustCharges, plus the dispatch case (CalculationEngine.cs:808-811). Draft's category, level, percentage defaults, and citations were correct, but its formula glossed over two things that would cause a wrong reimplementation: (1) which RT/LT line becomes primary vs. zeroed is fixed by raw charge order, not SortBy, and (2) the paired charge's AmountCharged roll-up is gated on the primary's Adjust firing and can be silently skipped if the paired line's allowed amount was already zero. Also added the unguarded re-scan-by-procedure-code lookup and rounding-mode gotchas the prior pass missed.