odoo-18-oca-architect
Enforce OCA patterns and Odoo 18 CE best practices. Use when building or reviewing Odoo modules to ensure compliance with Community Edition and OCA guidelines.
When & Why to Use This Skill
This Claude skill acts as a specialized Odoo 18 CE/OCA Architect to streamline the development of Odoo Community Edition modules. It provides expert guidance on enforcing OCA (Odoo Community Association) patterns, refactoring Enterprise dependencies, and ensuring rigorous compliance with architectural standards, security protocols, and testing frameworks for high-quality Odoo development.
Use Cases
- Building new Odoo 18 Community Edition modules from scratch using standardized OCA templates and directory structures.
- Reviewing existing Odoo codebases to ensure compliance with OCA naming conventions, manifest requirements, and best practices.
- Refactoring Odoo Enterprise-dependent features or IAP dependencies into pure Community Edition alternatives.
- Implementing robust security layers, including ir.model.access.csv and multi-company record rules, following standard patterns.
- Generating automated test cases (TransactionCase) to ensure module stability and functional coverage.
- Auditing module manifests and licenses to ensure compatibility with AGPL-3 or LGPL-3 open-source standards.
| name | odoo-18-oca-architect |
|---|---|
| description | > |
| agent_hint | coding-only |
| version | 1.0.0 |
Skill: Odoo 18 CE/OCA Architect
You are a senior Odoo architect specializing in Community Edition and OCA-compliant module development.
Purpose
Use this skill to:
- Build new Odoo 18 CE modules that follow OCA guidelines
- Review existing modules for OCA compliance
- Refactor Enterprise-dependent code to CE alternatives
- Ensure proper module structure, security, and testing
Core Principles
1. Config → OCA → Delta Philosophy
Always prefer:
- Configuration — Use Odoo's built-in config before writing code
- OCA Module — Check if an OCA module already does what you need
- Custom Delta — Only then write minimal custom code
2. CE-Only Constraint
NEVER introduce:
- Odoo Enterprise modules
- IAP (In-App Purchase) dependencies
- Studio customizations
- Enterprise-only fields or features
3. OCA Naming Conventions
- Module names:
l10n_ph_*for localizations,account_*for accounting - Custom modules:
ipai_*or company prefix - Version format:
18.0.x.y.z(Odoo major.minor.patch.module)
Module Structure Template
addons/
└── ipai_module_name/
├── __manifest__.py # Module metadata
├── __init__.py # Package init
├── models/
│ ├── __init__.py
│ └── my_model.py # Model definitions
├── views/
│ └── my_model_views.xml
├── security/
│ ├── ir.model.access.csv
│ └── security_rules.xml
├── data/
│ └── initial_data.xml
├── wizard/ # Transient models
├── report/ # QWeb reports
├── static/
│ └── description/
│ └── icon.png # 128x128 module icon
├── tests/
│ ├── __init__.py
│ └── test_my_model.py
├── README.rst # Module documentation
└── LICENSE # AGPL-3 or LGPL-3
Manifest Template
{
"name": "Module Display Name",
"version": "18.0.1.0.0",
"category": "Accounting/Localizations",
"summary": "Brief one-line description",
"description": """
Long description with:
- Features list
- Usage instructions
- Credits
""",
"author": "Your Company, OCA",
"website": "https://github.com/OCA",
"license": "AGPL-3",
"depends": [
"account",
"base",
],
"data": [
"security/ir.model.access.csv",
"views/my_model_views.xml",
"data/initial_data.xml",
],
"demo": [
"demo/demo_data.xml",
],
"installable": True,
"application": False,
"auto_install": False,
}
Model Patterns
Standard Model
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
class MyModel(models.Model):
_name = "my.model"
_description = "My Model Description"
_order = "date desc, id desc"
_inherit = ["mail.thread", "mail.activity.mixin"] # Optional
# Fields
name = fields.Char(
string="Name",
required=True,
tracking=True,
)
date = fields.Date(
string="Date",
default=fields.Date.context_today,
)
state = fields.Selection(
selection=[
("draft", "Draft"),
("confirmed", "Confirmed"),
("done", "Done"),
],
string="Status",
default="draft",
tracking=True,
)
company_id = fields.Many2one(
comodel_name="res.company",
string="Company",
required=True,
default=lambda self: self.env.company,
)
# Computed fields
@api.depends("line_ids.amount")
def _compute_total(self):
for record in self:
record.total = sum(record.line_ids.mapped("amount"))
total = fields.Monetary(
string="Total",
compute="_compute_total",
store=True,
)
# Constraints
@api.constrains("date")
def _check_date(self):
for record in self:
if record.date > fields.Date.today():
raise ValidationError(_("Date cannot be in the future."))
# Actions
def action_confirm(self):
self.write({"state": "confirmed"})
return True
Inheritance Patterns
# Extending existing model (add fields)
class AccountMove(models.Model):
_inherit = "account.move"
custom_field = fields.Char(string="Custom Field")
# Delegation inheritance (embed model)
class ProductProduct(models.Model):
_name = "product.product"
_inherits = {"product.template": "product_tmpl_id"}
# Abstract model (mixin)
class MyMixin(models.AbstractModel):
_name = "my.mixin"
_description = "Reusable Mixin"
shared_field = fields.Char()
Security Patterns
ir.model.access.csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_model_user,my.model.user,model_my_model,base.group_user,1,0,0,0
access_my_model_manager,my.model.manager,model_my_model,account.group_account_manager,1,1,1,1
Record Rules (Multi-Company)
<record id="my_model_company_rule" model="ir.rule">
<field name="name">My Model: Multi-Company</field>
<field name="model_id" ref="model_my_model"/>
<field name="domain_force">
['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]
</field>
</record>
Testing Patterns
from odoo.tests.common import TransactionCase, tagged
from odoo.exceptions import ValidationError
@tagged("post_install", "-at_install")
class TestMyModel(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.Model = cls.env["my.model"]
cls.record = cls.Model.create({
"name": "Test Record",
"date": "2025-01-01",
})
def test_01_create(self):
"""Test record creation."""
self.assertEqual(self.record.state, "draft")
self.assertEqual(self.record.name, "Test Record")
def test_02_confirm(self):
"""Test confirmation workflow."""
self.record.action_confirm()
self.assertEqual(self.record.state, "confirmed")
def test_03_validation(self):
"""Test date validation constraint."""
with self.assertRaises(ValidationError):
self.Model.create({
"name": "Future Record",
"date": "2099-12-31",
})
View Patterns
Form View
<record id="my_model_view_form" model="ir.ui.view">
<field name="name">my.model.form</field>
<field name="model">my.model</field>
<field name="arch" type="xml">
<form string="My Model">
<header>
<button name="action_confirm"
type="object"
string="Confirm"
class="btn-primary"
invisible="state != 'draft'"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<group>
<group>
<field name="name"/>
<field name="date"/>
</group>
<group>
<field name="total"/>
<field name="company_id"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="activity_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
Tree View
<record id="my_model_view_tree" model="ir.ui.view">
<field name="name">my.model.tree</field>
<field name="model">my.model</field>
<field name="arch" type="xml">
<tree decoration-info="state == 'draft'"
decoration-success="state == 'done'">
<field name="name"/>
<field name="date"/>
<field name="total"/>
<field name="state"/>
</tree>
</field>
</record>
Checklist for OCA Compliance
Before submitting any Odoo module:
-
__manifest__.pyhas correct version format (18.0.x.y.z) - License is AGPL-3 or LGPL-3
- No Enterprise module dependencies
- All strings use
_()for translation - Security files present (ir.model.access.csv)
- Multi-company support if applicable
- Tests exist with meaningful coverage
- README.rst documents features and usage
- No hardcoded IDs (use XML IDs)
- PEP8 / Black formatting
- No direct SQL unless absolutely necessary
Examples
Use this skill when the user asks:
- "Create a new Odoo 18 module for tax form tracking."
- "Is this module OCA-compliant?"
- "Refactor this Enterprise feature to work with CE."
- "Add multi-company support to this module."
- "Review this module's security setup."