Search by

anun333 / oe-module-revenue-cycle

anun333

Revenue Cycle for OpenEMR: a charge review before claims go out, both directions (missed charges and charges the record doesn't support), as a Staff Worklist tab, with a look-back report.

Package info

github.com/anun333/oe-module-revenue-cycle

Type:openemr-module

pkg:composer/anun333/oe-module-revenue-cycle

Statistics

Installs: 22

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.9 2026-10-27 17:42 UTC

This package is auto-updated.

Last update: 2026-10-27 17:43:07 UTC


README

Status: 0.1.9, a pre-release. Tested on OpenEMR 8.4.1 and master with synthetic data only.

A charge review inside the clinic, before claims go out: care in the record that no charge bills, and charges the record doesn't support. Both directions, from the first version, because an internal audit that only ever finds money reads like a revenue tool, and one that finds both reads like what the HHS Office of Inspector General asks for: "regular internal billing and coding audits".

What it does

  • Nine checks on each visit whose claim hasn't gone out:

    1. seen and not billed: a documented visit, past the days coding gets, with no charge; or an appointment marked seen with no visit;
    2. a vaccine given here with no line for the product the clinic bills for it, or with no administration line;
    3. a test run in the clinic, resulted, with no line for its code;
    4. the mirrors: a vaccine product or administration line with no vaccine given (a vaccine recorded without choosing a visit counts toward the patient's only visit that day), an in-clinic test billed with no result, charges on a visit with no forms and no signature;
    5. the same code twice on one visit, where units would carry the count;
    6. modifier 25 on a visit code with no other service beside it;
    7. a charge with no diagnosis pointer;
    8. a drug billed by its J code with no NDC the claim would carry (Medicaid needs it on drugs given in the clinic).
    9. a claim to a payer whose referring provider has no NPI: OpenEMR's Demographics lets a user with no NPI be chosen, and the claim then carries the name without the NPI Medicare requires (core issue #14858).
  • The queue is a "Charges to check" tab in the Staff Worklist, for whoever bills. Each item says what was found and opens the visit. Accept by fixing the fee sheet; the flag clears on its own. Dismiss with a reason, which the Worklist logs. A view records only the flags that are new, cleared or found again, so one that changes nothing writes nothing to the database or to OpenEMR's audit log.

  • The look-back runs the same checks over visits already billed, both directions, with each charge from the clinic's own fee schedule at the patient's own price level and, for a missed charge, the days left in the year a Medicare claim can be corrected. It counts what became of every flag: accepted, dismissed or open, by check and direction. The list shows 200 findings a page, all checks or one, and downloads as a CSV file with every row of the chosen list.

  • Confidential Title X visits: when Title X Report is installed and enabled, the visit categories it names for confidential services keep their charge checks but not checks 8 and 9, which exist to get a claim through to an insurer (42 CFR 59.10(a)). It's a guarded read of Title X Report's settings, off when that module isn't there.

  • Settings: when the review starts, how many days coding gets, the visit categories never billed, the procedure provider whose tests are run in the clinic, the clinic's vaccine list (each CVX with the product code it bills), and whether check 8 runs (on unless turned off, for a site that bills no payer needing NDCs). The vaccine rows start from what was given here.

  • A staff guide, GUIDE.md, task by task for the biller, whoever reviews billing, and the administrator. Help on each page opens it at the installed version.

What it never does

  • It never changes a claim or the fee sheet. The person who accepts a flag makes the change in OpenEMR's own fee sheet.
  • No flag asks for documentation. A missed-charge flag rests only on what the record already holds; notes changed after the fact to support a code are what an audit should help a clinic avoid.
  • It never refunds or reports to a payer. A charge with nothing behind it on a paid claim is for whoever handles compliance at the clinic (the 60-day rule, 42 CFR 401.305).
  • It ships no CPT descriptions. data/codes.json names a few CPT numbers (vaccine administration, the visit codes modifier 25 attaches to) with labels in our own words; the clinic's own code table supplies the names.

Who can open what

The page, the settings and the Worklist tab need OpenEMR's billing permission (acct/bill). A visit marked with a sensitivity shows only to users core's own sensitivity check allows. Viewing the look-back, downloading its CSV and saving settings are in the audit log.

Known limits

  • Percentage price levels aren't applied. OpenEMR 8.4.1's fee sheet applies a percentage price level when Billing's enable_percent_pricing is on; master's lookup (FeeSheetChargeLookup) doesn't. The look-back follows master, so on 8.4.1 a patient on a percentage level shows no amount for a missed charge.

Not done yet

  • The dashboard (0.2.0), on the shared library's figures contract.
  • NCCI pairs and units for practices billing per service (0.3.0), from files the site imports.
  • Health-center claim presets and charge capture (0.4.0).

Install

From the OpenEMR directory:

composer require anun333/oe-module-revenue-cycle

The installer plugin places it in interface/modules/custom_modules/oe-module-revenue-cycle/, and Composer brings openhealthcare-common with it. Without Composer, copy this directory there and run composer install --no-dev in it, which puts openhealthcare-common in its own vendor/; the module stays switched off until it finds that package one way or the other. If you copy several of our modules in by hand, keep their vendor/openhealthcare-common at the same version: OpenEMR loads the first copy it finds for all of them.

After adding, upgrading or removing a module copied in by hand, restart the container (or Apache). OpenEMR's official Docker images (8.0.0 to 8.5.0) keep in APCu which file holds each class, and each class they didn't find, across requests: until a restart, a class once not found stays not found, and a removed module's classes still point at its folder. An OpenEMR built from source without Composer's --apcu-autoloader has no such cache.

Then go to Modules › Manage Modules › Unregistered, and Register, Install and Enable it. Open Revenue Cycle › Settings, fill in your vaccine list and the in-clinic provider, and save. The Charges to check tab needs the Staff Worklist.

Compatibility

Written for OpenEMR 7.0 and later through openhealthcare-common's compatibility layer; its bootstrap never stops a page on any version. Checked end to end on 8.4.1 and master, and on fresh official 7.0.2 and 8.5.0 installs with its pages loaded and its forms posted (from 0.1.1: 0.1.0's forms stopped on 7.0.x); for 0.1.5, on 2026-10-26, the fresh installs and master again.

Development

composer install
vendor/bin/phpunit
php tools/footprint.php --check

Sources

  • 42 CFR 401.305 (reporting and returning overpayments, the 60-day rule) and 424.44 (timely filing).
  • HHS OIG, General Compliance Program Guidance (November 2023).
  • CMS, National Correct Coding Initiative Policy Manual, chapter I, section D (modifier 25).
  • CMS, Medicare Claims Processing Manual, chapter 9 (FQHC visits and vaccines).

Codes and their terms

CPT is a registered trademark of the American Medical Association. No CPT descriptor is reproduced here; the labels in data/codes.json are ours (CC0). HCPCS Level II codes are published by CMS.

Other modules for OpenEMR

See openhealthcare-common for the modules that share it.

License

GPL-3.0-or-later, as OpenEMR. See LICENSE. The labels we wrote in data/codes.json are CC0 1.0: see LICENSES/CC0-1.0.txt.