How to Structure ACES/PIES Data in Odoo
By Aktiv Software · August 10, 2026 · 10 min read
If you're implementing a parts business on Odoo, ACES and PIES aren't optional. They're how the industry moves catalog data between manufacturers, distributors, and retailers. The problem is Odoo's product model wasn't designed with either standard in mind, and every serious implementation runs into the same architectural questions early.
This post is for teams already familiar with ACES/PIES — you know what applications are, you understand PAdb, you've probably wrestled with XML imports before. What we're going to cover is where ACES and PIES actually fit in Odoo's data model, and the four architectural decisions that determine whether your implementation scales or hits a wall at 50,000 SKUs.
Where Odoo's product model doesn't quite fit
Odoo's core product model has three layers that are worth naming precisely before we map anything onto it. The product template is the abstract concept ("Brake Rotor, Front, Slotted"). The product variant is the specific SKU with its own attributes ("Brake Rotor, Front, Slotted, 12.5 inch, PN BR-12500"). Product attributes and attribute values generate the variants ("Diameter: 11.5, 12.0, 12.5" produces three variants of the template).
This model works beautifully for products where variants are enumerated at the SKU level. A t-shirt in three colors and four sizes is twelve variants, one row per SKU. Odoo handles this natively without a scratch.
Parts don't work this way. The variant explosion problem is well-known: a single brake rotor SKU can fit 300+ vehicle applications, and each application has its own qualifier data (front/rear, driver/passenger, quantity per vehicle, engine constraint, note text). If you naively model each application as a variant, one part becomes 300 rows in your product table. Multiply by a catalog of 10,000 parts and you have three million product records, most of them administrative artifacts rather than real SKUs.
The other direction — putting ACES fitment data into product attributes — has a different problem. Attributes in Odoo are meant to be catalog-selectable ("choose your color"). Fitment isn't a choice a customer makes about the part; it's a constraint on which parts can be shown to a given customer. Different semantic, different UI, different storage requirements.
ACES and PIES need to live somewhere other than the product template/variant/attribute triangle. That "somewhere" is the first architectural decision.
Decision 1 — Separate fitment tables, not variants
In every serious Odoo parts implementation we've done, the answer is the same: create separate tables for fitment data that reference product SKUs, but aren't part of the product hierarchy itself.
Practically, this means three related tables at minimum:
- Vehicle base table — a normalized store of year/make/model/submodel identifiers, ideally keyed against the industry's Vehicle Configuration Database (VCdb) identifiers so you can sync updates cleanly. This is your MMY lookup source.
- Fitment/application table — the many-to-many relationship between products and vehicles, with qualifier fields (position, quantity, notes). This is what the ACES XML actually populates.
- Qualifier reference tables — the ACES-defined lists of qualifiers (position codes, engine codes, transmission codes) that fitment records reference. These change over time as ACES releases updates.
Odoo doesn't ship with these tables. They're additions to the schema. The good news is Odoo's ORM handles custom models cleanly — you extend the data model, tie it to the standard product model via one-to-many relations, and the rest of the platform (search, reporting, permissions) works with them naturally.
The specific implementation detail that matters: whether these tables are new Odoo models or external tables Odoo queries via a connector. For most implementations, we build them as native Odoo models. Keeping fitment data inside the same PostgreSQL database gives you referential integrity guarantees and simpler queries. External databases only start to make sense when the fitment table crosses tens of millions of rows and query performance becomes the bottleneck.
Decision 2 — PIES structural attributes on the product, extended attributes elsewhere
PIES splits attributes into two rough categories. Structural attributes are the ones every part has — part number, brand, description, GTIN, packaging dimensions, HAZMAT flags. Extended attributes are the category-specific fields that PAdb defines (brake rotor diameter, filter thread pitch, hose inner diameter, thousands of them).
The temptation is to add every extended attribute directly to the Odoo product model as custom fields. Don't do this. A brake rotor and a spark plug share almost none of their PAdb attribute IDs. Modeling every possible extended attribute on the base product model produces a table with hundreds of columns, most of them null for any given product, and a maintenance nightmare as PAdb evolves.
The right structure is:
- Structural PIES fields go on the product record. Part number, brand, primary description, GTIN — these are queryable, indexable, and used everywhere. They belong as first-class product fields.
- Extended attributes live in a separate model. A key-value store keyed by PAdb attribute ID, with the product as the parent. This makes the schema flexible without polluting the product table.
- Display logic lives in category templates. When rendering a product page, look up which extended attributes are relevant for that PAdb category and pull them from the key-value table. Different product categories render different attribute sets.
This structure survives PAdb updates without schema migrations. When PIES 8.0 adds new category-specific attributes, you don't add columns — you just start populating new keys in the existing key-value model. That's what makes the design scalable over years, not just months.
Decision 3 — Fitment data local, refreshed from source
The most reliable pattern is to store all ACES fitment locally in Odoo's database, refreshed from your third-party source on a defined schedule. Not because Odoo can't call external APIs — it can. But because every query that determines whether a part can be shown to a customer runs against this data, and API round-trips per query are unsustainable.
The pattern:
- Source of truth remains external. Your fitment data provider (whichever third-party ACES/PIES tool you're using) maintains the canonical dataset. You never edit fitment records inside Odoo directly. Ownership of the data stays with the source.
- Odoo holds a working copy. Full ACES applications, PIES structural and extended attributes, all cached locally. This is what the storefront reads on every query.
- Sync jobs handle refresh. Scheduled jobs pull deltas from the external source and update the local copy. Full re-imports happen rarely (typically only when the source data structure changes materially).
The critical part of this architecture is the delta detection. A parts distributor with 200,000 SKUs and 15 million fitment records cannot re-import the entire dataset every week. The sync must know which specific records changed since the last successful sync — usually via a "last-updated" timestamp on the source side, or by hashing record content and comparing hashes.
Third-party ACES/PIES tools vary a lot in how well they support delta sync. This is worth asking about before committing to a data source. A vendor that requires full re-imports will hit performance limits early.
Decision 4 — Application qualifiers as first-class data, not text notes
ACES qualifiers — the position codes, engine codes, transmission constraints, quantity-per-vehicle values, and notes attached to each application — are where less-experienced implementations quietly go wrong.
The wrong pattern is treating qualifiers as free-text notes on the fitment record. This works for display ("Fits 2019 Camry V6, front only, 2 required") but breaks the moment a customer needs to filter their storefront intelligently. If a shopper filters for "brake pads for driver-side front only," you need qualifiers modeled as structured data, not free text.
The right pattern:
- Each qualifier code in ACES has its own field on the fitment record. Position, quantity, engine base, engine designation, transmission type, drive type — separate columns, each mapped to the ACES reference table.
- Notes fields exist for the truly unstructured stuff. But the note field is a fallback, not the primary storage. Anything that can be structured, is.
- Reference tables for qualifier values live in Odoo. Not as free strings on the fitment record. That way, storefront filters can query against known values, and when ACES releases updates to the qualifier lists, you update one table rather than search-and-replace across millions of fitment rows.
Structured qualifiers are what enable the smart storefront experience buyers expect. Without them, your fitment data is a filing cabinet — you can retrieve records but you can't slice them intelligently. With them, your storefront can show a shopper exactly the parts that fit their 2019 Camry V6, driver's side, automatic transmission, without ambiguity.
Common mistakes that cause pain 6 months in
A few patterns we've seen in implementations that didn't get these architectural decisions right up front:
Modeling applications as product variants. Discussed above. Usually surfaces around the 5,000-SKU mark, when the product catalog becomes physically unmanageable. Very expensive to unwind.
Storing extended PIES attributes as JSON blobs in a single field. Works fine for display. Breaks the moment you need to filter or query on those attributes ("show me all rotors with diameter greater than 12 inches"). Requires JSON path queries that are slow and hard to maintain.
Skipping VCdb integration for vehicle base data. Teams build their own vehicle taxonomy instead of aligning with the industry standard. Then every time they add a new fitment data source, the vehicle IDs don't match and merging catalogs becomes manual reconciliation work.
Treating ACES/PIES as an import problem, not a data model problem. Focusing on getting the initial XML into Odoo, without thinking about how the data will be queried, updated, or extended. This produces implementations that work great on day one and slow to a crawl at scale.
No plan for standard updates. ACES and PIES both evolve. Every year or two the standards release updates that affect existing implementations. Teams that didn't design for extension have to rebuild significant portions of the schema each time.
What this means practically
If you're evaluating whether to build Odoo parts eCommerce in-house or work with an implementation partner, the ACES/PIES architecture is one of the areas where experience matters most. The four decisions above don't seem huge in isolation — they're each a few hours of design work. But making them wrong compounds over years, and the cost of retrofitting a bad data model to a live parts business is significant.
The good news is that once these decisions are made correctly, everything downstream — fitment filtering, kit builders, customer garages, tiered pricing, catalog authoring — becomes tractable. Bad architecture makes everything hard; good architecture makes everything possible.
If you're wrestling with these decisions on a specific implementation, our parts eCommerce solution page covers how we structure the full stack, and we're happy to have a working call on your specific data model challenges. We've done enough of these to know where the sharp edges are.
For a broader look at why vanilla Odoo doesn't work for parts businesses without these layers, our earlier Building Parts eCommerce on Odoo post covers the full architecture.
Frequently Asked Questions
Can Odoo natively handle ACES and PIES data?
Not directly. Odoo's product model was designed for general commerce and manufacturing, not the automotive aftermarket. It has product templates, variants, and attributes — but no native concept of applications (which vehicles a part fits), fitment qualifiers (position, quantity, engine constraints), or the extended PIES attribute set that manufacturers publish. Every serious Odoo parts implementation adds a mapping layer that translates between ACES/PIES structures and Odoo's native product model.
Should ACES applications be stored as Odoo product variants?
No. This is the most common architectural mistake. A single part typically fits hundreds or thousands of vehicle applications. Modeling each application as a variant creates a catalog explosion that Odoo cannot manage — inventory, pricing, and product management all break down. Applications should be stored in a separate fitment table that references the product, not as variants of the product.
How should PIES attributes be represented in Odoo?
PIES has both structural attributes (part number, brand, UPC, dimensions) and extended attributes (thousands of category-specific fields). Structural attributes map cleanly to Odoo's native product fields. Extended attributes should live in a separate model tied to the product, keyed by PAdb attribute IDs so you can map them consistently across brands. Loading every extended attribute onto the product record directly makes the product model unmanageable.
Do I need to store ACES data in the same database as Odoo?
For most implementations, yes — but not for the reason you'd think. It's not about database performance. It's about referential integrity: when a customer configures a vehicle in the storefront, filters by it, adds a part to cart, and completes checkout, every step needs to know which vehicle-part relationships are valid. Storing fitment in a separate system creates sync problems that eventually cause the storefront to show parts that don't actually fit. The right architecture keeps ACES data local, refreshed from the external source on a schedule.
How often should ACES/PIES data be refreshed from the source?
Depends on your data source and business. Most manufacturers publish updated ACES/PIES quarterly, with some doing monthly. For a distributor pulling from multiple brands, you're likely refreshing something weekly. What matters more than frequency is the delta detection — knowing which specific records changed since the last sync — because a full re-import on a large catalog every week will crush your Odoo instance. Incremental sync with change detection is the sustainable pattern.
Get the architecture right the first time
If you're evaluating a parts eCommerce build on Odoo, a 30-minute call with our team covers where the sharp edges are — and how to avoid them.
Talk to Our Team