All posts
    Oracle EBSOracle FusionAP AutomationArchitecture

    One AP platform, many ERPs: the adapter pattern for clean integration

    October 30, 20256 min readBy Founder, EZ Cloud

    The moment an AP automation platform supports more than one ERP, it faces a fork in the road. The wrong path is the one most products drift into: ERP-specific logic scattered through the invoice and supplier code as a thicket of if EBS … else if Fusion … else if Yardi … branches. Each new ERP makes that thicket denser, every change risks breaking a customer on a different ERP, and the codebase slowly becomes unmaintainable.

    The right path is to decide, up front, that the core invoice flow must not know which ERP it's talking to. Approving an invoice, routing it for sign-off, writing it to the database — that logic is identical whether the destination is Oracle EBS, Oracle Fusion, or something else entirely. Only the last mile differs. The architectural job is to isolate that last mile behind a single, well-defined seam. That seam is the ERP adapter pattern.

    One interface, many implementations

    You start by defining what any ERP integration must be able to do, as an abstract interface — a small, stable set of operations the core code calls:

    class ERPAdapter {
      async validateInvoice(invoiceData, teamConfig) { /* ... */ }
      async approveInvoice(invoiceData, teamConfig)  { /* ... */ }
      async syncSuppliers(teamConfig)                { /* ... */ }
      async searchSuppliers(query, teamConfig)       { /* ... */ }
      async exportInvoice(invoiceData, teamConfig)   { /* ... */ }
      async pollExportResponse(teamConfig)           { /* ... */ }
    }
    

    Then each ERP gets a concrete implementation behind that same interface:

    • An EBS adapter — PO validation and invoice staging into Oracle EBS via a Spring Boot REST service, operating-unit handling, the documented AP import path.
    • A Fusion (OIC) adapter — supplier-number resolution, validation calls over Oracle Integration Cloud REST, invoice export as a file to an SFTP endpoint, and polling the response directory for the import result.
    • A null adapter — a no-op for customers with no ERP integration or a simple file export, so the core flow completes cleanly without special-casing.

    The core invoice DAO asks a factory for the right adapter based on the customer's configuration and then just calls the interface:

    const erp = getERPAdapter(featureFlags);
    const result = await erp.validateInvoice(invoiceData, teamConfig);
    

    It has no idea, and no need to know, whether erp is the EBS adapter or the Fusion one. The branching that used to be smeared across the codebase now happens exactly once, in the factory.

    Why this matters more for Oracle than anywhere else

    EBS and Fusion are both "Oracle," but their integration surfaces could hardly be more different. EBS posting goes through interface tables and a concurrent import program; validation calls a middle-tier service that reaches the EBS database. Fusion has no base tables you're allowed to touch — you post through a file-based import (FBDI) and read state through OIC REST APIs, and you respect quirks like OIC returning an HTTP 200 that carries an error status in a header.

    Trying to serve both from shared branching code means every Fusion-specific subtlety becomes a landmine for EBS customers and vice versa. The adapter pattern is what lets each Oracle integration keep its full, idiosyncratic complexity — isolated, so it can't bleed into the other. An EBS-only concern like receipt creation or AP-import status polling lives inside the EBS adapter, gated by its own feature flags, invisible to everyone else.

    Configuration drives selection — not code forks

    The companion principle is that which adapter a customer uses is data, not a code path. A single configuration value — the customer's ERP type — tells the factory which adapter to construct. Onboarding a customer onto a different ERP is a configuration change plus, at most, one new adapter file; it is never a fork of the invoice engine.

    This is what lets a single deployable codebase serve every customer. There are no per-customer builds, no per-customer branches of the core logic. The invoice flow is written once. The supplier sync is written once. The only thing that varies between an Oracle EBS shop and an Oracle Fusion shop is which adapter the factory hands back — and that's chosen at runtime from their config.

    Adding the next ERP is a contained change

    The real test of the pattern is what it costs to add ERP number four. With branching code, it's an open-heart operation on shared logic. With the adapter pattern, it's:

    1. Write a new class implementing the ERPAdapter interface.
    2. Register it in the factory against a new ERP-type value.
    3. Set that value in the new customer's configuration.

    The core invoice and supplier code isn't touched. Existing customers on other ERPs can't be affected, because nothing they depend on changed. The blast radius of "support a new ERP" shrinks from "the whole application" to "one new file" — which is exactly the property you want as the customer list grows.

    Where this fits

    This is the structural foundation under ERP-native AP automation: the platform behaves natively to each ERP precisely because each ERP's integration is fully encapsulated rather than half-merged with everyone else's. It's also what makes posting into both Oracle EBS and Oracle Fusion from one product credible instead of marketing — the two Oracle integrations share zero ERP-specific code, so neither compromises the other. And it underpins more specialized behavior, like the running-balance partial-receipt validation that lives inside the Fusion adapter without complicating the EBS path at all.

    Where EZ Cloud fits

    EZ Cloud is built on exactly this pattern. The invoice approval, routing, and supplier logic is ERP-agnostic; every Oracle EBS and Oracle Fusion specific — interface-table staging, FBDI export over OIC, validation calls, supplier sync — lives behind an adapter selected from the customer's configuration. One codebase, clean Oracle integrations on both sides, and a new ERP is an additive change rather than a rewrite.

    If you're weighing an AP platform that claims to support your ERP and the one you might migrate to, the question worth asking is architectural: is the ERP logic isolated, or is it branching all the way down? That answer determines whether the integration stays durable as both Oracle and your environment evolve.

    See it against your Oracle AP

    Book a 30-minute walkthrough — we'll run a real exception from supplier email to Oracle posting, on Fusion or EBS.