Fee Schedule Line Dynamic Property

This text describes the use of dynamic logic for prioritizing fee schedule lines, to account for situations where the initial selection of fee schedule lines renders multiple applicable fee schedule lines. To price a claim line using a fee schedule, it must be unambiguous which one fee schedule line to apply.

The use of dynamic logic is necessary because the criteria with which to prioritize fee schedule lines are likely to differ from implementation to implementation, e.g. because it depends on dynamic fields. The prioritization of lines is thus not suitable to be 'hardcoded'; rather it may be coded in each implementation in a way appropriate for that particular implementation.

If not prevented by using the functionality described in this text, a fatal error message is raised if multiple applicable fee schedule lines are found (CLA-FL-PRIC-009 and/or CLA-FL-PRIC-003). Dynamic prioritization of fee schedule lines is all about preventing these fatal error messages and being able to price the claim line instead.

It is of course possible that the initial selection of fee schedule lines renders exactly one applicable fee schedule line, or none at all. This text concerns only the situation where multiple applicable fee schedule lines are found.

Dynamically Prioritize Fee Schedule Lines

If multiple applicable fee schedule lines are selected, a piece of dynamic logic can be executed. This dynamic logic has as input objects the claim line and the list of applicable fee schedule lines. It is expected to dynamically determine from the input list of fee schedule lines the fee schedule line with the highest priority, i.e. the line with which to price the claim line. This fee schedule line must be returned as the only element in the output list of fee schedule lines. OHI Claims will then price the claim line using that fee schedule line.

For this dynamic prioritization a piece of function dynamic logic must be created with signature "Fee Schedule Line Priority". If during claim line pricing the initial selection renders multiple applicable fee schedule lines, the piece of function dynamic logic with this signature is selected and executed. Note that in case such a piece of dynamic logic has not been defined, this step is skipped without raising an error message for this. Only one piece of dynamic logic with signature "Fee Schedule Line Priority" may be defined. Refer to the implementation guide on dynamic logic for a complete description of this signature.

It may be so that the dynamic logic determines the same highest priority for multiple fee schedule lines, i.e. the dynamic logic cannot choose. It is then allowed to include all the lines with the same highest priority into the output list of fee schedule lines. OHI Claims will then raise a fatal message as described above (CLA-FL-PRIC-009 and/or CLA-FL-PRIC-003). A pend may be configured to trigger on this fatal message and prompt the claims operator to follow up.

Procedure and Modifier Specificity

OHI Claims offers the following predefined methods to evaluate procedure and modifier specificity:

  • filterOnProcedureSpecificity(): has as input a list of fee schedule lines and the claim line, it returns a filtered version of that list, including only the fee schedule lines that are most specific with regard to procedure match (a match on 2 procedures being more specific than on 1).

  • filterOnModifierSpecificity(): has as input a list of fee schedule lines and returns a filtered version of that list, including only the fee schedule lines that are most specific with regard to modifier match (a match on 2 modifiers being more specific than on 1).

To understand when these methods may be useful, consider that a factor in determining the fee schedule line with the highest priority may be the specificity of procedures and modifiers:

  • Procedure specificity: both a fee schedule line with CPT 99201 only, and a fee schedule line with CPT 99201 and REV 510 will be applicable for a claim line with CPT 99201 and REV 510. The fee schedule line with CPT 99201 and REV 510 however is more specific and can be deemed better suitable to price the claim line.

  • Modifier specificity: both a fee schedule line with modifier TC only, and a fee schedule line with modifiers TC and XY will be applicable for a claim line with modifiers TC and XY. The fee schedule line with modifiers TC and XY however is more specific and can be deemed better suitable to price the claim line.

Specificity on procedure and/or modifier does not per se make a fee schedule line more suitable to price a claim line. Other factors may also play a role; maybe the less specific fee schedule line has a match on a dynamic field and the more specific fee schedule line has not. That dynamic field may just be very important. As such OHI Claims evaluates neither procedure specificity nor modifier specificity by itself, but instead offers the predefined methods mentioned above that may be used in the dynamic logic in a way that is appropriate for the implementation (if at all).

Refer to the implementation guide on dynamic logic for a complete description of these predefined methods.

Example

The following example demonstrates a possible piece of function dynamic logic that may be used to dynamically prioritize fee schedule lines.

It uses a reference sheet in which significances of field matches are configured:

Reference Sheet "Fee Schedule Line Field Significance" (usage name: feeScheduleLineFieldSignificance)

Matched field (column name: matchedField) Description (column name: description) Match Type (columnName: matchType) Significance (column name: significance)

REV

Match on a procedure that is a revenue code

special

128

CPT

Match on a procedure that is a CPT code

special

64

individualProvider

Match on individual provider

simple

32

organizationProvider

Match on organization provider

simple

16

providerGroup

Match on provider group

simple

8

contractReference

Match on contract reference

simple

4

feeScheduleLineModifierList

Match on one or more modifiers

simple

2

state

Match on state - a dynamic field

simple

1

The total significance of a fee schedule line is determined by all the fields by which it matches with the claim line, e.g.:

  • A claim line that matches only on "REV" has significance 128

  • A claim line that matches on "CPT" and "Contract Reference" has significance 64+4=68

  • A claim line that matches on "CPT" and "Contract Reference" and "State" has significance 64+4+1=69

  • A claim line that has no matches that are particularized in this reference sheet has significance 0

In this methodology the fee schedule line with the highest total significance is held to be the line with the highest priority and this line will price the claim line.

The significances in this reference sheet are configured in such a way that a match on a more significant field will always take precedence over a match on any combination of less significant fields. For example, a match on "providerGroup" only, renders total significance 8 where a match on "contractReference", "feeScheduleLineModifierList" and "state" renders total significance 7 (4+2+1).

The column "Matched field" contains references to fee schedule line fields, where for simple matches (see below) each field is denoted using its name as it appears in dynamic logic. This makes it possible to write generic dynamic logic that can handle both fixed and dynamic fields. Thus, for simple matches, the dynamic logic code for prioritizing fee schedule lines does not have to be changed, when a new dynamic field is added to the fee schedule line. It is only needed to add that dynamic field to the reference sheet with the right significance, and alter the fee schedule condition so it makes sure the dynamic field matches with the claim line.

Simple matches are matches where a particular fee schedule line field matches directly with a particular claim line field. E.g. the fee schedule line’s individual provider, if specified, matches claim lines that also specify that individual provider. These simple matches are covered by the generic code described below. Special matches are not direct; e.g. a match on REV applies if any of the three claim line procedures matches with any of the three fee schedule line procedures or is part of any of the fee schedule line’s procedure groups. Such special matches must be coded for specifically in the dynamic logic.

The dynamic logic in this example filters the input list of fee schedule lines in three steps:

  • In step 1 the input list is filtered based on procedure specificity using the standard predefined method

  • In step 2 the list is filtered further based on the significance of fee schedule lines, calculated as described above.

  • In step 3 the list is filtered further based on modifier specificity using the standard predefined method

Ideally, after executing all 3 steps the input list is filtered down to only one element: the fee schedule line with which to price the claim.

The dynamic logic code:

/**
This logic assumes the existence of a reference sheet
with usage name feeScheduleLineFieldSignificance. In this
reference sheet significances of field matches are
configured in the following way (where 1 is least significant):

       matchedField         | matchType | significance
=======================================================
REV                         | special   |           128
CPT                         | special   |            64
individualProvider          | simple    |            32
organizationProvider        | simple    |            16
providerGroup               | simple    |             8
contractReference           | simple    |             4
feeScheduleLineModifierList | simple    |             2
state                       | simple    |             1

Note that simple matches are matches where a particular claim line
field matches directly with a particular fee schedule line field.
Simple matches are covered by generic dynamic logic code.

Special matches are not direct and most be coded for specifically.
E.g. the CPT match is a match between any of the 3
procedure fields on the claim line and any procedure field
or procedure group field on the fee schedule line.
**/

/**
Prioritization step 1: execute the standard procedure specificity
**/
feeScheduleLineList = claimLine.filterFeeScheduleLineProcedureSpecificity(feeScheduleLineList)

/**
Prioritization step 2: execute the significance reference sheet
**/
highestTotalSignificanceEncountered = 0
outputFeeScheduleLineList = []

// Helper function to determine if there was a procedure match
def procedureMatch(procedure, feeScheduleLine)
    {return (
              procedure == feeScheduleLine.procedure
              ||
              procedure == feeScheduleLine.procedure2
              ||
              procedure == feeScheduleLine.procedure3
              ||
              (feeScheduleLine.procedureGroup != null
               &&
               procedure.inProcedureGroup(feeScheduleLine.procedureGroup.code)
              )
              ||
              (feeScheduleLine.procedureGroup2 != null
               &&
               procedure.inProcedureGroup(feeScheduleLine.procedureGroup2.code)
              )
              ||
              (feeScheduleLine.procedureGroup3 != null
               &&
               procedure.inProcedureGroup(feeScheduleLine.procedureGroup3.code)
              )
          )
    }

// For each fee schedule line in the fee schedule line list:
// Calculate the total significance and determine what to do
// with the line
feeScheduleLineList.each() { feeScheduleLine ->
    totalSignificance = 0

    // Account for simple matches.
    // Go through all lines of the reference sheet;
    // check for each fee schedule line field specified
    // if the fee schedule line field has a value.
    // If so, we assume a match on this field and add
    // the significance of that match to the total
    // significance of the fee schedule line.
    // This works for all fixed and dynamic fields where we
    // have a 1:1 match. Note that for dynamic fields
    // the fee schedule condition must be used to assert
    // that the dynamic field actually matches the claim line;
    // here we just check that the dynamic field on the fee
    // schedule is not null, and assume a match with the claim
    // line if so.

 def referenceSheetlines = new SearchBuilder(ReferenceSheetLine.class).join("feeScheduleLineFieldSignifican").by("matchType").eq("simple").execute();
        referenceSheetlines.each()
        { referenceSheetLine ->
            if (
                feeScheduleLine.properties.startsWithKey(referenceSheetLine.payloadValues.matchedField)
                &&
                    (
                        (
                            (feeScheduleLine[referenceSheetLine.payloadValues.matchedField] instanceof List)
                            &&
                            !(feeScheduleLine[referenceSheetLine.payloadValues.matchedField].isEmpty())
                            )
                            ||
                            (
                            !(feeScheduleLine[referenceSheetLine.payloadValues.matchedField] instanceof List)
                            &&
                            feeScheduleLine[referenceSheetLine.payloadValues.matchedField] != null
                            )
                        )
                    )
                {
                    totalSignificance = totalSignificance + referenceSheetLine.payloadValues.significance
                }
        }

    // Acocunt for 'Special Matches'
    // For each special match there needs to be specific code
    specialMatchedFields = []
    // Match on CPT:
    if  (
         (
          claimLine.procedure != null
          &&
          claimLine.procedure.flexCodeSystem.code == 'CPT_CODES'
          &&
          procedureMatch(claimLine.procedure, feeScheduleLine)
         )
         ||
         (
          claimLine.procedure2 != null
          &&
          claimLine.procedure2.flexCodeSystem.code == 'CPT_CODES'
          &&
          procedureMatch(claimLine.procedure2, feeScheduleLine)
         )
         ||
         (
          claimLine.procedure3 != null
          &&
          claimLine.procedure3.flexCodeSystem.code == 'CPT_CODES'
          &&
          procedureMatch(claimLine.procedure3, feeScheduleLine)
         )
        )
        {specialMatchedFields.add('CPT')}

    // Match on REV:
    if  (
         (
          claimLine.procedure != null
          &&
          claimLine.procedure.flexCodeSystem.code == 'REVENUE_CODES'
          &&
          procedureMatch(claimLine.procedure, feeScheduleLine)
         )
         ||
         (
          claimLine.procedure2 != null
          &&
          claimLine.procedure2.flexCodeSystem.code == 'REVENUE_CODES'
          &&
          procedureMatch(claimLine.procedure2, feeScheduleLine)
         )
         ||
         (
          claimLine.procedure3 != null
          &&
          claimLine.procedure3.flexCodeSystem.code == 'REVENUE_CODES'
          &&
          procedureMatch(claimLine.procedure3, feeScheduleLine)
         )
        )
        {specialMatchedFields.add('REV')}

    // Add to the total significance of the fee schedule line
    // based on the special matches of fields.
       specialMatchedFields.each()
       { specialMatchedField ->
            referenceSheetlines = new SearchBuilder(ReferenceSheetLine.class).join("feeScheduleLineFieldSignifican").by("matchType").eq("special").and().join("feeScheduleLineFieldSignifican").by("matchedField").eq(specialMatchedField).execute();
                significance = referenceSheetlines.size() > 0 ? referenceSheetlines.get(0).payloadValues.significance : 0
                totalSignificance = totalSignificance + significance
       }

    /**
    Now we know the totalSignificance of the fee schedule line and
    can determine what to do with the line. Possible options:
    - Let it take precedence over other lines encountered so far
    - Add it to the list of lines with the most significance
    - Ignore it because it is less significant than other lines
    **/

    // If this fee schedule line has the highest significance
    // encountered so far, let it replace the output list
    if (totalSignificance > highestTotalSignificanceEncountered)
        {
        outputFeeScheduleLineList = [feeScheduleLine]
        highestTotalSignificanceEncountered = totalSignificance
        }
    // If this fee schedule line equals the highest significance
    // encountered so far, add it to the output list
    else if (totalSignificance == highestTotalSignificanceEncountered)
        {
         outputFeeScheduleLineList.add(feeScheduleLine)
        }
    // If this fee schedule line does neither have a higher nor equal
    // significance than the highest significance encountered so far,
    // i.e. it is lower, we ignore the line
    else {}
 }

/**
Prioritization step 3: execute the standard modifier specificity
                       and return the result. Hopefully the output
                       list contains only one line now.
**/
return claimLine.filterFeeScheduleLineModifierSpecificity(outputFeeScheduleLineList)

table class = pdf-full-page-width