Calculation type
Reduces payment on charges whose Medicare rollup code (from MedicareDataRVU.MultiProcedureCategoryCode, keyed by procedure code + TC/26 modifier) is in BaseCodes (default "2") by ranking them and paying each successive ranked unit at a configured percentage of its per-unit amount, per Medicare Claims Processing Manual Ch.12 40.6; with UseAdditionalBilateralRules/MultiEndoscopyRules/MultiRadRules all defaulted true, charges that already carry a bilateral/multi-endoscopy/multi-radiology adjustment share a single rank position with their LT/RT, base-code, or TC/26 counterpart instead of getting their own.
affected = charges (i=1..NumCharges-1) whose rollups[i].Code is in BaseCodes and not IgnoreCharge()'d, ordered by calculationEngine.GetChargeOrder(context, affected, SortBy) (or by a per-base-code-summed 'aggregated endo context' when UseAdditionalMultiEndoscopyRules and any affected charge already has an endoscopy adjustment). Then, with adjustedIndex and p as state shared across ALL affected charges (not reset per charge): for each affected charge, x = detail.Amount/charge.Units (or detail.Amount if Units==0, but this branch is effectively unused — see gotchas); for each unit j in charge.Units: chargeAdjustmentIndex = adjustedIndex, unless the charge carries a bilateral/endo/rad adjustment and UseAdditional*Rules is set, in which case GetPairedAdjustmentIndex reuses (once) the index already assigned to its LT/RT, same-base-code, or TC/26 partner; if chargeAdjustmentIndex < Percentages.Count, p = Percentages[chargeAdjustmentIndex]/100 (else p keeps its prior value); s += MoneyMath.Multiply(x, p); adjustedIndex++ only if chargeAdjustmentIndex == adjustedIndex (i.e. not a reused/paired index). After the unit loop, detail.Adjust(s, adjustment) if s != detail.Amount.
| Key | Meaning |
|---|---|
| SortBy | SortChargesBy enum (AmountAllowed/AmountCharged); ranks affected charges before Percentages are applied; default AmountAllowed |
| BaseCodes | Rollup codes marking a charge as belonging to this multiple-procedure family; default "2"; resolved via medicareAdjustmentRepo (MedicareDataRVU.MultiProcedureCategoryCode) since ScheduleType is left null |
| Percentages | Ordered percentages applied to the 1st, 2nd, 3rd... ranked unit; defaults to an EMPTY list (ListField seeds no items) — see gotchas for the consequence |
| ExclusionCodes | List of DimensionMember codes; the containing foreach's `continue` (CalculationEngine.cs Calculators/MultipleProcedureAdjustmentCalculator.cs:125-131) only advances the modifier-check loop, never skips the charge, so this list has zero effect on GetAffectedCharges regardless of its contents |
| UseAdditionalBilateralRules | Defaults true on the Medicare subclass (false on base); groups LT/RT-paired bilateral-adjusted charges to one rank index (Ch.12 40.6.C.16) |
| UseAdditionalMultiEndoscopyRules | Defaults true on the Medicare subclass; groups same-base-code endoscopy-adjusted charges to one rank index using a summed endoscopy context (Ch.12 40.6.C.14) |
| UseAdditionalMultiRadRules | Defaults true on the Medicare subclass; groups TC/26-paired radiology-adjusted charges to one rank index (Ch.12 40.6.C.19) |
| ScheduleType | Left null (not explicitly set) by the Medicare constructor; moot regardless because the injected medicareAdjustmentRepo's IMultipleProcedureScheduleRepo implementation ignores the scheduleType parameter entirely |
Gotchas
(1) Zero-Units charges are ZEROED, not preserved: the code computes x = detail.Amount specifically for the Units==0 case, but the unit loop is `for (j = 0; j < charge.Units; j++)` — with Units==0 this never executes, so s stays 0.0M and `if (s != detail.Amount) detail.Adjust(s, adjustment)` fires, wiping any qualifying zero-unit charge to $0. The Units==0 branch that computes x is dead code that never gets used. (2) Percentages defaults to an empty list; with no configured percentages, p never updates from its initial value of 1.0, so s always equals detail.Amount and the whole adjustment silently no-ops (Adjust is never called) until an admin populates the list. (3) p and adjustedIndex are declared once outside the per-charge loop and persist across every affected charge on the claim — ranking is one continuous sequence over the whole account, not restarted per charge. (4) ScheduleType is parsed but functionally inert for the Medicare variant — medicareAdjustmentRepo's rollup lookup is hardcoded to MedicareDataRVU keyed by procedure code + TC/26 modifier, irrespective of what ScheduleType is set to. (5) MoneyMath.Multiply(decimal,double) round-trips through double (banker's rounding), unlike some sibling calculators that use plain decimal math.
class · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/MedicareMultipleProcedureAdjustment.cs:6
calculator · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/Calculators/MultipleProcedureAdjustmentCalculator.cs
dispatch · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/CalculationEngine.cs:756-759
CORRECTED — the draft's summary, formula skeleton, dispatch site, and key_attrs (including the ExclusionCodes no-op finding) all checked out against MultipleProcedureAdjustment.cs and MultipleProcedureAdjustmentCalculator.cs. It missed two behavior-changing gotchas: qualifying charges with Units==0 are silently zeroed (not left alone) due to a loop-bound/dead-branch mismatch, and Percentages defaults to an empty list, making the adjustment a no-op until configured.