Calculation type
Applies a stepped-percentage multiple-therapy reduction (BCBS variant of Medicare's multiple-procedure-payment-reduction logic) to charges flagged by a multiple-procedure schedule as belonging to a configured base rollup code: recomputes each affected charge's Medicare RVU practice-expense (PE) component in a throwaway RVU pass, applies the configured per-unit percentage sequence to that PE component, converts the result into an equivalent percentage of the charge's already-priced base allowed amount, and adjusts the charge to that recomputed amount.
affected = charges i=1..NumCharges-1 where multiple-procedure schedule records[i] is non-null and records[i].Code is in BaseCodes, and IncludeCharge passes (not already MultipleEndoscopyAdjustment-marked unless AllowWithMultipleEndoscopy, not IgnoreCharge, no ExclusionCodes match -- this ExclusionCodes check DOES correctly exclude, unlike the inert one in MultipleProcedureAdjustment). rvuContext = a full MedicareRVUCalculation pass (Percentage forced to 100, using adjustment's GPCIAdjusted/MissingCodeLogic) over a context copy, with ApplyOPPSCandidate() substituted in per-charge if UseOPPS and the charge has an OPPS candidate. sortedAffected = GetChargeOrder(rvuContext, affected, SortChargesBy.PEAmount) -- this sorts by each charge's TOTAL PEAmount (only zeroed when Units==0), NOT per-unit PEAmount, unlike the AmountAllowed/AmountCharged sort modes which do divide by Units. Global adjustedIndex (0-based, shared across all affected charges) and percentage (starts at 1.0) walk unit-by-unit in sorted-charge order: while adjustedIndex < Percentages.Count, percentage = Percentages[adjustedIndex]/100; once exhausted, percentage keeps its last value for all remaining units. Per unit: rvuUnitAdjustedAmount = rvuUnitAmount - PEAmount + PEAmount*percentage (rvuUnitAmount = rvuDetail.BaseCalculation.Amount/units, PEAmount = rvuDetail.PEAmount, both from the RVU pass); rvuPercent = Round(rvuUnitAdjustedAmount/rvuUnitAmount*100 * 10^PercentageRoundingDecimals)/10^PercentageRoundingDecimals via the RoundingType-selected Round(); newAmount += Round(initialUnitAmount * rvuPercent)/100.0 -- initialUnitAmount = original context's detail.Amount/units (the already-priced base amount, NOT the RVU price). If loop total newAmount != detail.Amount, Adjust(newAmount).
| Key | Meaning |
|---|---|
| GPCIAdjusted | Passed into the internal MedicareRVUCalculation used to derive PE amounts; default true. |
| UseOPPS | If true, after the RVU context is built, any charge with an OPPS candidate (HasOPPSCandidate) has ApplyOPPSCandidate() invoked before its PE amount is read, so the reduction is priced against OPPS rather than MPFS; default false. |
| MissingCodeLogic | Passed to the internal MedicareRVUCalculation controlling fallback behavior when a charge's code has no RVU data; default None. |
| BaseCodes | List of multiple-procedure-schedule rollup codes eligible for the reduction; default {"5"}. |
| Percentages | Ordered list of percentages applied unit-by-unit across ALL affected charges combined in sorted order (default {100, 50}); once the list is exhausted, the last-assigned percentage value is reused for every remaining unit rather than cycling or defaulting to 100%. |
| ExclusionCodes | List of DimensionMember codes; charges carrying any of these are excluded -- functions correctly (returns false / excludes), unlike the similarly-named field in MultipleProcedureAdjustment. |
| AllowWithMultipleEndoscopy | If false (default), charges already carrying a MultipleEndoscopyAdjustment adjustment marker (detail.HasAdjustment) are excluded from this adjustment. |
| RoundingType | Enum (Floor default, also Ceiling/Round) controlling the private Round() helper, which is used at BOTH the rvuPercent-rounding step and the final per-unit dollar-rounding step. |
| PercentageRoundingDecimals | Decimal places rvuPercent is rounded to before use (default 1); only scales the FIRST Round() call via a 10^n factor -- the second Round() call (final dollar amount) is NOT scaled by this factor. |
Gotchas
1) ZERO-UNIT CHARGE SILENTLY ZEROED: the per-unit accumulation loop is `for (i=0; i < charge.Units; i++)` -- using the RAW charge.Units, not the Math.Max(charge.Units,1)-clamped 'units' variable used for the initialUnitAmount/rvuUnitAmount divisions just above it. If charge.Units==0, this loop runs zero times, newAmount stays 0.0m, and since `newAmount != detail.Amount` is then true (detail.Amount presumably nonzero), the charge's allowed amount is unconditionally Adjust()'d DOWN TO ZERO -- not skipped, not left alone. 2) ROUNDING INCONSISTENCY BETWEEN ROUNDINGTYPES: the private Round(decimal) method is called twice with the SAME signature but different effective precision needs -- first on rvuPercent*factor (factor = 10^PercentageRoundingDecimals, so Floor/Ceiling/Round all correctly land on the configured decimal precision after dividing back by factor), but second directly on (initialUnitAmount*rvuPercent) with NO factor scaling. For RoundingType.Floor/Ceiling this coincidentally yields exact-cent precision after the /100.0m divide (rounding to nearest integer beforehand). For RoundingType.Round, the private method calls Math.Round(amount,2) -- rounding the pre-scaled value to 2 decimal PLACES OF ITSELF, not to the nearest cent -- so after /100.0m the result carries FOUR decimal places of precision instead of two, silently leaking sub-cent amounts into the stored allowed amount. 3) GetChargeOrder's PEAmount sort branch (used exclusively by this type) ranks by each charge's TOTAL PEAmount, not per-unit PEAmount unlike the other two SortChargesBy modes -- a 1-unit and a 4-unit charge with the same per-unit PE are NOT ranked equally; the 4-unit charge sorts higher purely from having more units, which changes which units get the higher (e.g. 100%) Percentages slots. 4) percentageScheduleTypeKey lookup in FindAffectedCharges calls procedureScheduleRepo.GetCodeScheduleRecords(context, null) with a literal null schedule-type key -- BCBSMultipleTherapyAdjustment has no ScheduleType property of its own; which schedule is actually consulted is entirely up to the repo's handling of a null key.
class · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/BCBSMultipleTherapyAdjustment.cs:10
calculator · /home/cary/src/mdc/MdClarity/MDClarity/MDClarityCore/Backend/PricingEngine/Adjustments/Calculators/BCBSMultipleTherapyAdjustmentCalculator.cs
dispatch · CalculationEngine.cs:828
CORRECTED: draft's high-level shape (affected-charge filter, PEAmount-based sort, per-unit percentage stepping, rvuPercent formula) was confirmed correct against BCBSMultipleTherapyAdjustmentCalculator.cs, but the draft asserted the final per-unit rounding was hardcoded 'floor-to-cent' -- false; it goes through the same RoundingType-configurable Round() method as the rvuPercent step, and for RoundingType.Round that method's Math.Round(amount,2) call does not actually produce cent-level precision at that point in the calculation (a real rounding-inconsistency bug the draft missed entirely). Also newly found and added: the zero-Units-silently-zeroes-the-charge bug (loop bound uses raw charge.Units, not the Math.Max-clamped divisor), and that GetChargeOrder's PEAmount branch sorts by total, not per-unit, PE amount.