Calculation type
Implements the CMS Multiple Procedure Payment Reduction (MPPR) for diagnostic imaging: splits each affected charge into Technical (TC) and Professional (26) components (both, for an unmodified/global charge), independently re-prices each component through the fee-schedule engine, ranks each component list separately by allowed/charged amount, and reduces each component by (1 - configured percentage) based on its own rank.
Qualifying charges: !IgnoreCharge, rollup Code (via medicareAdjustmentRepo, keyed off MedicareDataRVU) in BaseCodes, no IgnoredModifierTypes modifier present, and not carrying both TC and 26 modifiers simultaneously. Each qualifying charge/unit is split into a synthetic single-unit TC and/or 26 charge (global/unmodified charges produce both); these synthetic charges are added to a cloned 2-row context (account row + the synthetic charge) and re-priced via calculationEngine.CalculateAmountAllowedBase — i.e. each component's AmountAllowed comes from an independent fee-schedule lookup for that code+modifier, not a split of the original charge's allowed amount. TC and 26 component lists are each sorted independently by SortBy (per-unit amount descending). For each affected charge: modifierTCPercentage = 1 - AdjustmentTCPercentages[rankIndex]/100 (or the last entry if rank exceeds the list, or 0 if the list is empty), same for modifier26Percentage; adjustmentAmount = modifierTCPercentage*TC.AmountAllowed + modifier26Percentage*26.AmountAllowed (only the applicable term(s) for that charge's modifier state). detail.Adjust(detail.Amount - adjustmentAmount, adjustment) if 0 < adjustmentAmount <= detail.Amount; Adjust(0, adjustment) if adjustmentAmount exceeds detail.Amount; Adjust(detail.Amount, adjustment) (no-op, just tags) if adjustmentAmount == 0 AND more than one charge in the affected set — a lone affected charge with a $0 adjustment is left completely untouched (no Adjust call at all).
| Key | Meaning |
|---|---|
| AdjustmentTCPercentages | Ordered percentages by rank for the Technical component's allowed amount; Medicare subclass default {100, 50}, confirmed in the constructor |
| Adjustment26Percentages | Ordered percentages by rank for the Professional (26) component's allowed amount; Medicare subclass default {100, 95}, confirmed in the constructor |
| BaseCodes | Rollup codes marking a charge as subject to the radiology MPPR; the Medicare constructor does not override this, so it inherits the base protected constructor's default "4" (MultipleRadiologyAdjustment.DefaultBaseCode) |
| IgnoredModifierTypes | Modifier values (default {"59"}) that exclude a charge from this adjustment entirely |
| ModifierDimensionKey | Which dimension holds the TC/26 modifier codes to inspect on a charge |
| SortBy | Ranks the TC and 26 component lists independently before percentages apply; Medicare default AmountAllowed (same as base default) |
| ScheduleType | Explicitly set to null in the Medicare constructor; also moot because medicareAdjustmentRepo's IMultipleProcedureScheduleRepo implementation ignores the scheduleType argument it's handed |
Gotchas
(1) TC/26 pricing is NOT a proportional split of the original charge's AmountAllowed — each component is independently re-priced via a real call into CalculateAmountAllowedBase against a synthetic charge carrying only the procedure code and the TC or 26 modifier, so its price is whatever the fee schedule returns for that code+modifier combination. (2) ScheduleType is parsed but the injected repo ignores it (same pattern as the other three Medicare Multiple* adjustments) — rollups always resolve via MedicareDataRVU regardless. (3) GetPercentageFromCalculationPercentagesByUnitNumber returns 0 (no reduction) when a percentages list is empty, not the last configured value — an admin who clears AdjustmentTCPercentages or Adjustment26Percentages silently disables reduction for that component only. (4) This calculator uses plain decimal arithmetic for the adjustment math (no MoneyMath call), unlike the Procedure/Endoscopy/Surgery siblings, so it doesn't inherit MoneyMath's double round-trip rounding behavior. (5) A charge that is the sole member of its affected set and computes a $0 adjustmentAmount gets no Adjust call at all (hasMultipleCharges guard), so it isn't even tagged as touched by this adjustment.
class · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/MedicareMultipleRadiologyAdjustment.cs:6
calculator · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/Calculators/MultipleRadiologyAdjustmentCalculator.cs
dispatch · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/CalculationEngine.cs:790-793
CORRECTED — the draft's qualifying-charge logic, percentage-factor formula, and dispatch-site wiring were all accurate on inspection. It missed that TC/26 amounts are independently re-priced from the fee schedule (not split from the original amount), the scheduleType-is-ignored behavior shared with the sibling Medicare adjustments, and the single-charge/zero-adjustment edge case that leaves a charge completely untouched.