Our organization has heavily customized Odoo 15’s warehouse management module with specific workflows for our multi-location distribution centers. We’re using Git for version control, but I’m concerned about our strategy as we plan the eventual upgrade to Odoo 16 and beyond. Currently, we have about 12 custom modules that extend stock.picking, stock.move, and related models with custom validation rules, automated routing logic, and integration with our WMS hardware.
The challenge is that each Odoo version changes core warehouse models in ways that could break our customizations. We’ve maintained everything in feature branches that get merged to a main development branch, but there’s no clear strategy for handling version compatibility. Some team members suggest maintaining separate branches per Odoo version (odoo-15-custom, odoo-16-custom), while others want a single main branch with conditional logic based on Odoo version detection.
I’m particularly interested in hearing from teams who’ve successfully upgraded custom warehouse modules across multiple Odoo versions. What Git branching strategy works best? How do you handle API changes in core models? Do you maintain backward compatibility or create version-specific implementations? Any insights on managing technical debt while keeping customizations maintainable would be valuable.
Before touching a single branch, establish your baseline:
Audit all 12 modules for direct inheritance depth on stock.picking, stock.move, and stock.move.line. Shallow overrides (_inherit) survive upgrades better than deep class replacements.
Run odoo-upgrade or the Odoo Upgrade Analysis tool against your source database to surface field renames, model splits, and deprecated API calls — particularly critical since Odoo 16 restructured stock.picking validation flows and introduced stock.lot changes (verify exact scope in your version).
Catalog every _sql_constraints, _default_* method, and raw SQL query in your modules. These break silently across versions.
Identify all XML id references and report templates tied to stock.* models — view inheritance breaks are the most common silent failure mode.
Check your hardware WMS integration points: if you’re calling action_confirm(), button_validate(), or _action_done() directly, all three have signature or behavior changes between 15 and 16 (verify exact signatures).
Lock your current environment: tag the production database state and module versions as v15-production-baseline in Git before any migration work begins.
Branching Strategy: Recommended Approach
Use version-pinned long-lived branches, not conditional runtime detection.
Runtime version sniffing (odoo.release.version) produces unmaintainable spaghetti and makes CI/CD fragile. Separate branches are operationally cleaner for an organization with 12 interdependent modules.
Recommended structure:
main ← integration/release target (always deployable)
odoo-15/stable ← production-frozen, hotfixes only
odoo-15/dev ← active 15 development
odoo-16/migration ← porting work in progress
odoo-16/dev ← future development on 16 baseline
Port modules individually rather than attempting a full-repo migration. Each module should have its own __manifest__.py with explicit 'version': '16.0.x.y.z' versioning.
Migration Step Sequence (15 → 16 per module)
Create odoo-16/migration from odoo-15/stable — not from dev, to avoid carrying unreleased changes.
Run the OCA openupgrade scripts for stock module (verify coverage for your version); these handle known field migrations automatically.
Update __manifest__.py: bump version prefix, update depends to reflect any 16-specific module renames.
Replace deprecated method calls — specifically audit all overrides of button_validate, _action_assign, and _get_moves_action (verify method names in target version release notes).
Refactor routing logic that hooks into procurement.group or stock.rule — these models had architectural changes in 16 (verify scope).
Re-test all automated routing with isolated unit tests before touching hardware integration layer.
Validate with --test-enable --stop-after-init against a restored copy of production data, not demo data.
Merge only after all module-level tests pass; never merge partially-ported modules.
Rollback Procedure
Odoo database upgrades are not natively reversible. Your rollback is entirely at the infrastructure level.
Restore from the v15-production-baseline database snapshot.
Redeploy from odoo-15/stable branch — this is why that branch must remain frozen.
If partial data was written post-cutover, assess via a diff of ir.module.module states between environments before attempting any data reconciliation.
Do not rely on --uninstall for rollback of migrated warehouse modules; custom stock.move records created under 16 schema will not cleanly downgrade.
Managing Technical Debt
Enforce module boundary discipline: routing logic, validation rules, and hardware integration should live in separate modules, not a monolithic wms_custom module. This makes selective porting tractable. Adopt OCA coding standards now — their module structure assumptions align with how Odoo’s upgrade tooling processes dependencies.
This draft is based on general Odoo knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.
We maintain separate branches per major Odoo version and it’s worked well for three upgrade cycles now. Our structure is main branch tracks latest Odoo version, with long-lived branches for each supported version (odoo-14-stable, odoo-15-stable). When upgrading, we create a migration branch from the old version, apply necessary API changes, test extensively, then merge to the new version branch. Critical bug fixes get cherry-picked back to older versions if needed. This approach keeps version-specific code isolated and makes rollback straightforward if upgrades fail.
After managing warehouse customizations through Odoo 11 to 15 upgrades, my strong recommendation is version-specific branches with a compatibility layer abstraction. Create a common interface module that defines your business logic, then implement version-specific adapters that handle API differences in core Odoo models. For example, stock.move.line structure changed significantly between versions - our adapter pattern isolated those changes to small adapter modules rather than rewriting entire workflows. This also makes testing easier since you can validate adapters independently.
The version detection approach with conditional logic sounds tempting but becomes unmaintainable quickly. We tried it and ended up with code full of if statements checking Odoo versions. Much cleaner to maintain separate branches and accept that some code duplication is okay. The key is having comprehensive automated tests that can run against any version - that’s what gives you confidence during upgrades. We use a CI pipeline that tests our custom modules against multiple Odoo versions in parallel, catching API breakages immediately.
One critical aspect often overlooked: document your customization patterns thoroughly. We maintain a CUSTOMIZATION_GUIDE.md in our repo that explains which core models we extend, why we made specific architectural choices, and known API dependencies. When upgrade time comes, this documentation is invaluable for identifying what needs review. Also consider the stability of APIs you’re using - some Odoo methods are more stable across versions than others. Stick to well-documented public APIs when possible rather than relying on internal implementation details.
From a consulting perspective, I’ve seen teams struggle most when they don’t plan upgrade cycles from the beginning. Build upgrade costs into your annual budget and schedule dedicated upgrade sprints rather than treating them as emergency projects. For Git strategy, we recommend version-specific branches with clear naming (stable-15, stable-16) and a develop branch that targets the next planned version. Tag releases clearly with both Odoo version and your internal version number. This makes it easy to identify which code runs in production and simplifies rollback if needed.
I’ll share our battle-tested approach after four major Odoo upgrades with extensive warehouse customizations. We use a hybrid strategy that balances maintainability with upgrade flexibility.
Git branching structure:
main: Always tracks latest stable Odoo version we support
version branches: odoo-15-stable, odoo-16-stable (one per major version)
feature branches: Created from appropriate version branch, merged back after review
upgrade branches: Temporary branches for migration work (upgrade-15-to-16)
For custom modules, we follow these principles:
Minimize direct modifications to core model methods - use inheritance and composition patterns
Create abstraction layers for version-sensitive operations (especially stock.move, stock.picking APIs)
Maintain a compatibility module that detects Odoo version and loads appropriate adapters
Write extensive unit tests that validate business logic independent of Odoo version
Upgrade workflow:
Create upgrade branch from current stable version
Update Odoo core as Git submodule or dependency
Run automated test suite - failures indicate API breaks
Fix breaks one module at a time, commit incrementally
Manual testing of complete workflows in staging environment
Merge to new version stable branch only after full validation
Tag release with both Odoo version and custom module version
Key lessons learned:
Don’t try to maintain backward compatibility across major versions - the complexity isn’t worth it
Do maintain clear separation between business logic and Odoo API calls
Version-specific branches are cleaner than conditional code
Budget 2-3 months for thorough testing of major upgrades
Keep a detailed changelog of Odoo API changes that affected your customizations
For your 12 custom modules, I’d start by auditing which core Odoo APIs each one depends on. Create a dependency matrix showing module vs. core model usage. This tells you which modules are highest risk during upgrades and should get testing priority. Also consider whether some modules could be consolidated - 12 is manageable but on the higher end for maintenance overhead.
Nina, this is incredibly helpful and aligns with what I was thinking but needed validation from someone who’s been through it. The dependency matrix idea is brilliant - I’m going to create that this week to understand our risk exposure. The hybrid branching strategy makes sense and the abstraction layer approach should help us avoid the conditional logic mess. Really appreciate the detailed workflow and timeline guidance. This gives me a solid framework to present to management for upgrade planning.