Procedure Types hierarchy not saving correctly in OpenEMR 8.4.0 / 8.4.1

Continuing the discussion from Procedure order creation in openEMR 8.4.1 problems: I found a problem with the Procedure Types configuration in OpenEMR 8.4.0 and 8.4.1 where newly created procedure types are not saved with the correct hierarchy.

Environment

  • OpenEMR 8.4.0 / 8.4.1
  • PHP 8.5.1
  • MariaDB 11.8.9
  • Windows
  • Clean installation

Symptoms

When creating a new Procedure Type Group, the form submission itself contains the correct values. For example:

form_procedure_type = grp
form_procedure_type_name = procedure
form_name = DEBUG GROUP 840
form_lab_id = 1
form_procedure_code =
form_seq = 0
form_save = Save

However, before the fix, the database received the values in the wrong columns. For example, a newly created group could result in values resembling:

parent = 0
name = 1
lab_id = 0
procedure_code = grp
procedure_type = procedure
procedure_type_name =

As a result:

  • Newly created groups appeared incorrectly.
  • Child procedure orders appeared as top-level entries.
  • Everything appeared to remain Tier 1.
  • The expected expandable hierarchy was not created.
  • Procedure orders could appear in an encounter but did not behave correctly in Pending Review.

Cause

The problem is in:

interface/orders/types_edit.php

The code builds $bindValues in this order:

$bindValues = [
    types_invalue('form_name'),
    types_invalue('form_lab_id'),
    $p_procedure_code,
    types_invalue('form_procedure_type'),
    types_invalue('form_procedure_type_name'),
    types_invalue('form_body_site'),
    types_invalue('form_specimen'),
    types_invalue('form_route_admin'),
    types_invalue('form_laterality'),
    types_invalue('form_description'),
    types_invalue('form_units'),
    types_invalue('form_range'),
    types_invalue('form_standard_code'),
    isset($_POST['form_diagnosis_code'])
        ? types_invalue('form_diagnosis_code')
        : types_invalue('form_related_code'),
    types_invalue('form_seq'),
];

For an INSERT, the code then does:

$bindValues[] = $parent;

$newid = sqlInsert(
    "INSERT INTO procedure_type SET parent = ?, $sets",
    $bindValues
);

The SQL expects the first bound value to correspond to:

parent

followed by the values in $sets:

name
lab_id
procedure_code
procedure_type
procedure_type_name
...
seq

But $parent is appended to the END of $bindValues.

Therefore the parameters are shifted by one position.

Fix

I changed:

$bindValues[] = $parent;

to:

array_unshift($bindValues, $parent);

So the INSERT branch becomes:

} else {
    array_unshift($bindValues, $parent);
    $newid = sqlInsert(
        "INSERT INTO procedure_type SET parent = ?, $sets",
        $bindValues
    );
    // $newid is not really used in this script
}

This makes the bound values match the SQL placeholders:

parent
name
lab_id
procedure_code
procedure_type
procedure_type_name
...
seq

Verification

After applying this change, I tested the hierarchy.

The database correctly stored:

procedure_type_id | parent | name                  | procedure_type
8                 | 0      | DEBUG GROUP FIXED     | grp
9                 | 8      | DEBUG order FIXED     | ord
10                | 9      | DEBUG RESULT FIXED    | res

Therefore:

Group
└── Procedure Order
    └── Discrete Result

was correctly represented in the procedure_type.parent relationships.

I then used the configured procedure in an encounter. The order appeared in Pending Review, I entered and reviewed the result, signed it, logged out, logged back in, and confirmed that the result persisted.

I reproduced the same source-code issue in both OpenEMR 8.4.0 and 8.4.1.

I am posting this in case others are experiencing the same Procedure Types behavior and so the issue can be reviewed upstream.