magendoo / module-omnibus

magendoo/module-omnibus

EU Omnibus Directive (2019/2161) price tracker for Magento 2. Records price changes with timestamps, computes the lowest prior price in the disclosure window, and displays it on PDP and PLP, with async queue processing for bulk operations.

magento2-module Compatibility: 2.4.7-2.4.9 Code Quality: Fail Tests: N/A Security: Pass MIT

Are you the maintainer of magendoo?

Packagento pulls magendoo's Composer packages from the public registry so buyers can find them here.

Claim the namespace to take ownership, publish new releases directly, and start charging for premium versions.

Claim this namespace →

Magendoo Omnibus Price Tracker

A Magento 2 module that records product price history and computes the lowest price in a configurable window, satisfying the requirements of the EU Omnibus Directive 2019/2161 (Article 6a).

The directive requires that any price reduction must show the lowest price from the preceding 30 days — measured not from today, but from the moment the reduction began. This module implements that anchored-window algorithm correctly.


Requirements

Dependency Version
PHP ≥ 8.1
Magento Open Source / Adobe Commerce 2.4.4 – 2.4.x
MySQL / MariaDB 8.0 / 10.6+

No RabbitMQ required: all queue topics are pinned to Magento's MySQL-backed db queue connection (queue_message table), so the async pipeline works on any standard Magento installation. Consumers run through Magento cron (consumers_runner) or a process manager — see Async processing.


Installation

The module is distributed via its GitHub repository (it is not published on Packagist).

Via Composer (recommended)

Add the repository to your project's composer.json:

"repositories": [
    {
        "type": "vcs",
        "url": "https://github.com/magendooro/module-omnibus"
    }
]

Install and enable:

composer require magendoo/module-omnibus:^2.0
bin/magento module:enable Magendoo_Omnibus
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

Manual installation

Copy the module directory to app/code/Magendoo/Omnibus/, then run the same setup:upgrade / setup:di:compile / cache:flush sequence.


Quick Start

After installation, navigate to:

Stores → Configuration → Magendoo Extensions → Omnibus Price Tracker

  1. Set Enable Price History to Yes
  2. Set Period in Days to 30 (minimum required by the Directive; increase for a wider safety margin)
  3. Set Display Mode to Discounted Products Only (recommended for compliance)
  4. Set Display Omnibus Prices On to Product Pages Only or Product and Category Pages — the default is None, which records history but renders nothing on the storefront
  5. Click Save Config → the module queues a full catalog recompute on the magendoo.omnibus.recompute queue (make sure consumers are running)
  6. Seed an initial baseline so products have history to compute from:
bin/magento omnibus:history:restore --force

The omnibus_price product attribute is then populated and the label renders on the configured surfaces.


Configuration Reference

general/* settings are scoped per website. label/* settings are scoped per store view so the label can be translated for each language (store view is Magento's locale boundary); an untranslated store view inherits the website/default value. cleanup/* and cron/* are global.

Path Default Description
general/enabled No Master toggle. Disabling stops capture and display but does not delete existing history.
general/period_in_days 30 Window length in days. Hard minimum: 30 (enforced at save time and again at read time).
general/display_mode discounted_only discounted_only — show only during active reductions. all_products — show for all products (rolling window).
general/display_on none Where to render the label: none, pdp_only, or pdp_and_plp. Must be changed from the default for any storefront output.
general/hide_if_matches Yes Suppress the label when the Omnibus price equals the current price.
general/show_history_on_product No Adds a notice on the admin product edit page pointing to the price history grid.
general/hide_for_customer_groups (none) Suppress the label for specific customer groups (history is still recorded).
label/template The lowest price from the last {days} days: {omnibus_price} Label text. Variables: {days}, {omnibus_price}, {percentage}. Allowed HTML tags: span i u b strong em.
label/display_format text text (inline) or tooltip.
label/percentage_difference disabled Show % change between current price and Omnibus price via {percentage}.
cleanup/enabled Yes Automatic deletion of old history records by the cleanup cron.
cleanup/period_in_days 400 Delete records older than this many days. Must be ≥ period_in_days + 30. The newest pre-cutoff record per product/website/group is always kept (carry-in).
cron/sync_schedule 0 2 * * * Drift-sync cron: queues captures for products whose current effective price (rule / active special / regular) drifted from the last history entry.
cron/cleanup_schedule 0 3 * * * Cleanup cron: deletes records older than the retention window.

All recorded_at timestamps are stored in UTC.


CLI Commands

All three commands refuse to run (exit non-zero) while magendoo_omnibus/general/enabled is 0.

# Recompute omnibus_price for all products on all websites
bin/magento omnibus:prices:recompute

# Recompute for a single product (all websites)
bin/magento omnibus:prices:recompute --product-id=42

# Recompute for a single product on a specific website
bin/magento omnibus:prices:recompute --product-id=42 --website-id=2

# Delete history older than the configured retention period, or a given date.
# The newest pre-cutoff record per product/website/group is always preserved.
bin/magento omnibus:history:clean
bin/magento omnibus:history:clean --before=2025-01-01
bin/magento omnibus:history:clean --before="2025-01-01 12:00:00"

# Wipe and rebuild history (fresh snapshot + full recompute).
# Prints the actual inserted row count, per-product coverage, and how many
# products ended up with a stored omnibus_price value.
# Requires confirmation unless --force is passed.
bin/magento omnibus:history:restore
bin/magento omnibus:history:restore --force
bin/magento omnibus:history:restore --force --website-id=1

Admin Interface

Marketing → Omnibus → Price Change History

The price history grid displays every recorded price change across your catalog. Columns: ID, SKU, Website, Customer Group, Price Type, Price (excl. tax), Price (incl. tax), Source, Recorded At, Actions.

Filterable columns include SKU (text), Website, Customer Group, Price Type, Source, and Recorded At (date range).

  • Row action: Delete — POST with confirmation dialog.
  • Mass action: Delete selected — POST.
  • Toolbar button: Restore History — wipes the history table and rebuilds it from a full catalog snapshot (POST with confirmation; only visible to admins holding the manage ACL resource). Refuses to run while the module is disabled globally or for any website: the capture/recompute services no-op when disabled, so the wipe would never be re-seeded.

All destructive endpoints accept POST only; GET requests are rejected.

ACL resources

Resource Grants
Magendoo_Omnibus::view_history View the price history grid
Magendoo_Omnibus::delete_history Delete single records / mass delete
Magendoo_Omnibus::manage Restore History (wipe + rebuild)
Magendoo_Omnibus::configuration Stores → Configuration section

Product attributes

Attribute Where Purpose
omnibus_price Product edit → Prices group (read-only value, website scope) The computed lowest prior price.
omnibus_hide Product edit → General group (Yes/No) Set to Yes to suppress the storefront label for this product.

Async processing

Bulk capture and recompute work runs through two message queue topics on the MySQL (db) queue connection:

  • magendoo.omnibus.capture — price capture for single products (catalog rule changes, imports, drift sync)
  • magendoo.omnibus.recomputeomnibus_price recompute batches (config changes)

Magento's cron consumers_runner starts the consumers automatically. To run them under a process manager instead:

bin/magento queue:consumers:start magendoo.omnibus.capture
bin/magento queue:consumers:start magendoo.omnibus.recompute

A single product save in admin/API is captured synchronously (so the product page is correct immediately); everything else is queued.


How It Works

See docs/how-it-works.md for a full explanation of the anchored-window algorithm (including the carry-in rule), the price resolution chain, and the complete event capture pipeline.

Architecture

See docs/architecture.md for the module structure, database schema, DI wiring, queue topology, and cron schedule.

Testing

See docs/testing.md for the PHPUnit suite inventory and manual verification checklist.


Roadmap

Reserved for future versions (constants exist in Api/Data/PriceHistoryInterface, but no code writes them yet):

  • Per-customer-group price tracking (tier / group price types)
  • REST API write sources (api, api_override source labels)
  • Cart price rule (checkout promotion) disclosure — the v1.x salesrule.is_omnibus column was removed in v2.0.0 and may return as a separate feature

Changelog

v2.0.0 — 2026-07-18

Major refactor. Breaking changes — review before upgrading from v1.x:

Removed

  • Config field general/display_child_products (never implemented), constant OmnibusConfigInterface::XML_PATH_DISPLAY_CHILD_PRODUCTS, method Config::isDisplayChildProducts()
  • Methods Config::getSyncCronSchedule() / Config::getCleanupCronSchedule() (schedules are read by etc/crontab.xml directly)
  • DB column salesrule.is_omnibusdropped on setup:upgrade; any data in that column is lost — and the sales_rule_form.xml checkbox that wrote it
  • Redundant index MGDOO_OMNIBUS_HIST_PROD_WEB_TIME_IDX (the unique key covers the same prefix)
  • The magendoo.omnibus.cleanup queue topic and its consumer (cleanup deletes directly, no queue round-trip)
  • Admin grid filter options that were never written: sources API / API Override, price types Tier / Group (interface constants remain reserved)

Fixed / changed

  • Window query now applies the carry-in rule: the price in force before the window opened is part of the minimum, so a product with a long-stable price gets a correct reference price
  • History retention (omnibus:history:clean and the cleanup cron) always keeps the newest pre-cutoff row per product/website/customer group — the future carry-in
  • Catalog rule changes, imports, config changes, and drift sync now publish to the message queue instead of doing bulk work inline; product save stays synchronous
  • Drift-sync cron pre-filters with a single SQL query per website and queues only genuinely drifted products
  • Config-change recompute is gated on the changed paths (enabled, period_in_days, display_mode)
  • PLP label implemented (pricing render plugin, pdp_and_plp mode); previously advertised but missing
  • Special price date handling: a special_from_date of today is active from the start of the day
  • All timestamps generated in UTC via the framework date library
  • Admin: ACL split into view/delete/manage/configuration; destructive endpoints POST-only; Restore button hidden without the manage resource
  • CLI commands exit with an error when the module is disabled; restore prints real inserted/coverage counts
  • Data patches are re-runnable (skip attribute creation when the attribute exists)

Notes

  • Product deletion also deletes that product's price history (ON DELETE CASCADE on the history table). If you need audit history to survive product deletion, export before deleting products.
  • composer.json version 2.0.0; module description updated to match actual behavior.

v1.0.0 — 2026-04-16

Initial release:

  • Price capture from admin save, catalog rules, Magento Import, config change, nightly cron
  • Anchored 30-day window algorithm
  • Async queue processing (MySQL-backed)
  • Admin price history grid with filters, mass-delete, and restore
  • CLI commands, omnibus_price and omnibus_hide EAV product attributes
  • PHPUnit unit test suite

License

MIT — see the license header in each source file.
Copyright © Magendoo (https://magendoo.com)

No changelog yet

The vendor hasn't published a changelog. Tagged releases appear in the Versions tab.

Versions
Version Stability QA Status Compatibility Released
2.0.1 stable Fail Magento 2.4.7-2.4.9 Details 2026-07-20 07:14:09
2.0.0 stable Not tested Not yet tested Details 2026-07-18 20:41:56
1.0.0 stable Not tested Not yet tested Details 2026-04-16 12:07:42

Requires 10

Package Constraint
magento/framework >=103.0.0
magento/module-backend >=102.0.0
magento/module-catalog >=104.0.0
magento/module-catalog-rule >=101.2.0
magento/module-eav >=102.1.0
magento/module-sales-rule >=101.2.0
magento/module-store >=101.0.0
magento/module-tax >=100.4.0
magento/module-ui >=101.2.0
php >=8.1

Requires-dev 2

Package Constraint
phpstan/phpstan ^1.10 || ^2.0
phpunit/phpunit ^10.5

Compatibility

Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.

Compatibility matrix (Magento × PHP)
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 Pass Pass
2.4.8 Pass Pass
2.4.9 Pass Pass

Code Quality

Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge. A phpcs finding can't make a module incompatible.

Static analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

Static analysis results
Tool Status Findings Summary
PHPCS Warning 181 181 warnings (ruleset: Magento2), 22 auto-fixable with phpcbf
PHPMD Warning 142 142 rule violations (UnusedPrivateField:142)
Cpd Warning 2 2 duplicated chunks spanning 27 total lines (min-lines=5, min-tokens=70)
Composer validate Info 10 valid; 10 advisory notes (composer validate --strict)

PHPStan

Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases.

PHPStan results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 32 32
2.4.8 32 32
2.4.9 32 32

Tests

Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.

Unit tests

Unit tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Integration tests

Integration tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Security

Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.

Security results
Tool Status Findings Summary
Composer audit Pass 0
Malware scan Pass 0
License
MIT
Authors
  • Magendoo

More from magendoo

View vendor
Make it pay

Turn an existing module into recurring revenue.

If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.