OSGi plugins, callouts, custom windows & reports — 100% upgrade-safe, zero core patches.
When configuration cannot close a gap, we build the difference as an OSGi plugin or Application Dictionary entry — never as a patch to the core. That single discipline is what keeps your next version upgrade a weekend job rather than a project.
The most expensive decision a team can make with an open-source ERP is to edit its source directly. It feels quick on day one and turns every future upgrade into a merge conflict nobody wants to own.
iDempiere was designed to be extended without being altered. Its OSGi runtime loads bespoke code as separate bundles alongside the platform, and its Application Dictionary adds windows, fields, processes and rules as data rather than code. Between the two, the great majority of requirements can be met without touching a single core class — the difference between an upgrade that costs a few days of regression testing and one that costs weeks of re-applying hand-made changes to a moving target.
So everything we build ships as an OSGi plugin or as Application Dictionary configuration exported in a 2-Pack. The standard source in your repository stays byte-for-byte identical to the community release: pull a new version, drop your plugins back on top, run the regression pack, and go.
You get the functionality your process needs, in a form a future consultant — ours or anyone's — can read, test and carry forward. No black boxes, no lock-in.
The Git repository, build scripts and 2-Pack packages are yours from day one.
Every change goes through code review against a written standard before it is packaged.
Plugins are re-run against the target iDempiere version before you commit to an upgrade.
Whether the requirement is a field-level validation, a new document type with its own workflow, a nightly costing process or a REST endpoint for your warehouse app, the deliverable is the same shape: clean Java in a versioned plugin, or a documented Application Dictionary change in a 2-Pack. Everything runs on the standard web client and posts through the normal document flow, so Sales Orders, Shipments and Invoices behave exactly as your users expect.
iDempiere gives you several ways to change behaviour, and choosing the right one is most of the craft: a change made in the wrong layer is either harder to build or harder to upgrade. The upgrade-risk column is our honest read.
| Mechanism | When to use it | Upgrade risk |
|---|---|---|
| Callout | Immediate field-level reaction as the user edits — default a value, recalculate a total, enable a field. | Low. Registered against a column; unaffected by core changes unless the column is removed. |
| Model Validator / Event Handler | Business rules on save and on document actions — validate before a C_Order completes, act after an M_InOut posts. | Low. Subscribes to stable events via AbstractEventHandler; the public event API rarely changes. |
| Custom Process | Batch or on-demand server jobs — a costing run, a document generator, a scheduled export. | Low. Built against the documented process framework; parameters live in the Application Dictionary. |
| Custom Window (Application Dictionary) | New screens over new or existing tables, with tabs, fields and display logic — configured as data. | Low to medium. Medium only where it overlays a standard window the new version reworks. |
| BIRT / JasperReports report | Formatted operational and statutory documents — invoices, packing lists, statements, ageing. | Low. Report files are external assets; they depend on the data model, not core Java. |
| REST endpoint | Expose or accept data for an eCommerce site, a mobile app or a partner integration over HTTP/JSON. | Low to medium. A custom JAX-RS plugin insulates callers from built-in API churn. |
| 2-Pack packaging | A delivery mechanism — bundle Application Dictionary changes to promote them from dev to test to production repeatably. | Low. Deterministic, versioned migration in place of manual clicking between environments. |
Rule of thumb. Reach for the Application Dictionary first, a plugin second, and the core never. If a requirement seems to need a core change, the design almost always needs another look.
This is the shape of an upgrade-safe rule. The handler below subscribes to the "before complete" event on a sales order and blocks completion when it has no lines. It is an ordinary OSGi component; nothing in the core is touched.
public class OrderValidator extends AbstractEventHandler {
@Override
protected void initialize() {
// Fire just before a C_Order document is completed
registerTableEvent(IEventTopics.DOC_BEFORE_COMPLETE, MOrder.Table_Name);
}
@Override
protected void doHandleEvent(Event event) {
PO po = getPO(event);
if (po instanceof MOrder) {
MOrder order = (MOrder) po;
if (order.getLines().length == 0) {
throw new AdempiereException(
"Order " + order.getDocumentNo() + " has no lines and cannot be completed.");
}
}
}
}
Throwing an AdempiereException rolls the transaction back and shows the message in the ZK web client. The same pattern extends to M_InOut, C_Invoice and any other document — only the table name and the rule inside doHandleEvent change.
Four families of custom work — all delivered as clean, documented artifacts in your own repository, never as patches to the core.
Callouts, model validators, processes and scheduled jobs — packaged as OSGi plugins with build scripts, handed over in your Git repository.
How the Core Stays Clean 02New windows, tabs and fields through the Application Dictionary, plus Jasper reports and print formats that match your documents exactly.
Explore Reporting 03Endpoints for storefronts, mobile apps and BI tools — idempotent, versioned and documented, so integrating teams never guess.
Explore Integrations 04Inherited a hacked core from a previous partner? We audit the diff, extract the changes into clean plugins and restore your upgrade path.
Book a Core AuditA bespoke change follows the same path every time, so it is reviewable, repeatable and safe to promote.
A requirement surfaces that configuration cannot meet — a rule, a screen, a process, an interface. We confirm it genuinely needs code, not a setting someone has not found yet.
We agree the mechanism — callout, validator, process, window, report or endpoint — and write a short spec: tables touched, events subscribed to, acceptance criteria. You sign it off before anyone builds.
Written as an OSGi plugin or Application Dictionary configuration, in your Git repository, against the standard iDempiere source. The core is never edited.
A second engineer reviews the change against our written standard — naming, transaction handling, error messages, upgrade safety — before packaging.
The change is packaged and promoted through dev, test and production as a 2-Pack, then re-run against the target version so you know an upgrade will not disturb it.
A customization is finished only when someone other than the author can rebuild, test and extend it.
The full Java source for every callout, validator, event handler, process and endpoint — commented and structured as standard iDempiere bundles.
Your own repository with commit history, plus the Maven Tycho build so the plugin set compiles with a single command on your infrastructure.
Versioned 2-Pack files for every Application Dictionary change, so each environment is built from the same package rather than by hand.
For every REST endpoint, a written contract — routes, payloads, authentication and examples — that your integration partners can build against.
The scenarios each change was tested against and the results, so you can see what "done" meant and re-run it after any future upgrade.
The reviewer's sign-off for each change, recording what was checked — transaction safety, error handling and upgrade risk — and any follow-ups.
A large share of the teams who come to us have already been down the other road. A previous developer edited the iDempiere source directly, and now the system is stuck several versions behind because no one dares to upgrade. This is recoverable.
The first step is honest measurement. We diff your source against the matching community release and catalogue every change — what was altered, where, and how deeply it reaches into the platform. Most forks are smaller than they feel. Once the changes are listed, we work out what each one was for, because the goal is to preserve the business intent, not the lines that happened to deliver it.
With intent understood, we re-implement each behaviour the upgrade-safe way — a validator instead of an edited posting routine, an Application Dictionary window instead of a hacked standard screen, a plugin process instead of a modified core class. We prove each one against your own scenarios, then retire the corresponding fork. When the last modification is gone, your source matches the community release again and you are back on the standard upgrade path. The effort varies with the size of the fork and we scope it after the diff — as an indicative range, a modest fork is typically a few weeks, a heavily modified core a couple of months, confirmed against the measured diff rather than guessed at the start.
"We never patch the iDempiere core. Everything we build ships as a plugin you can lift out — that is what keeps your upgrades cheap."
Customization is not a fork.
It's a clean plugin your next upgrade carries forward.
Every callout, process and window we deliver lives outside the core, in your repository, with build scripts and documentation.
Trusted worldwide for end-to-end iDempiere services — the best in the industry at what we do. Tell us the requirement and we will tell you the cleanest way to build it — and whether it needs code at all. If you have inherited a forked core, we can measure it and map the way back.