Skills odoo
Query Odoo data including salesperson performance, customer analytics, orders, invoices, CRM, accounting, VAT, inventory, and AR/AP. Generates WhatsApp cards, PDFs, Excel. Use when user explicitly mentions Odoo or asks for Odoo data.
git clone https://github.com/openclaw/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/ashrf-in/odoo-reporting" ~/.claude/skills/clawdbot-skills-odoo && rm -rf "$T"
skills/ashrf-in/odoo-reporting/SKILL.mdOdoo Financial Intelligence
Read-only, Evidence-First, Ledger-Based Reports
Quick Reference: Common Odoo Models
| Model | What It Contains | Use For |
|---|---|---|
| Users/Salespeople | Find salesperson by name, get user_id |
| Sales Orders | Revenue by salesperson, order counts, status |
| Invoices/Journal Entries | Invoice tracking, payments, P&L data |
| Contacts/Customers | Customer info, top customers by revenue |
| Products | Product sales, inventory |
| Chart of Accounts | Financial reporting, balance sheet |
| Journal Lines | Detailed ledger entries |
Security & Credentials
Security Model
This skill implements a defense-in-depth security model:
- User Invocation Required: This skill CANNOT be invoked autonomously by AI models
- Read-Only Enforcement: All data modifications are blocked at the code level
- Credential Isolation: Credentials stored only in local
file, never transmitted elsewhere.env - Network Boundaries: Only connects to user-specified Odoo URL, no external telemetry
Required Environment Variables
This skill REQUIRES Odoo connection credentials stored in
assets/autonomous-cfo/.env:
| Variable | Description | Secret | Required |
|---|---|---|---|
| Odoo instance URL (e.g., ) | No | Yes |
| Odoo database name | No | Yes |
| Odoo username/email | No | Yes |
| Odoo API key (recommended) or password | Yes | Yes |
⚠️ CRITICAL: These credentials are REQUIRED. The skill will not function without them.
Setup:
cd skills/odoo/assets/autonomous-cfo cp .env.example .env # Edit .env with your actual credentials nano .env
API Key vs Password
For production, use an Odoo API key:
- Log into Odoo → Settings → Account Security → API Keys
- Generate a new key (e.g., "Financial Reports Skill")
- Use this key as
ODOO_PASSWORD
Why API keys?
- Scoped permissions (can be read-only)
- Can be revoked independently
- Don't expose your main password
- Better audit trail in Odoo
Authentication Methods
XML-RPC (Legacy, default):
- Password/API key sent in XML-RPC request body
- Supported by all Odoo versions
JSON-RPC (Odoo 19+):
- API key sent as
headerAuthorization: Bearer <api_key> - More efficient for large datasets
- Use
to enableODOO_RPC_BACKEND=json2
Model Invocation Policy
🚫 Model invocation is STRICTLY DISABLED.
Per
skill.json:
"modelInvocation": { "disabled": true, "requiresUserInvocation": true }
This means:
- AI models CANNOT invoke this skill automatically
- User MUST explicitly request Odoo operations
- Every invocation requires user intent
Read-Only Enforcement
⚠️ IMPORTANT: Client-Side Enforcement Limitation
The skill implements client-side read-only enforcement. This means:
- Mutating methods are blocked in the Python code
- Blocked methods raise
if calledPermissionError - However, a modified or compromised client could bypass this
For Production Security:
- Use a read-only Odoo user (recommended)
- Don't give modify permissions to the API key's user
- Review Odoo access logs regularly
Blocked Methods:
,create
,write
(CRUD operations)unlink
(duplicate records)copy
,action_post
,action_confirm
(workflow actions)button_validate
Allowed Methods (Read-Only):
,search
,search_read
(data retrieval)read
,search_count
(metadata)fields_get
,name_search
,context_get
(helpers)default_get
Attempting to call blocked methods raises
PermissionError.
Data Handling & Privacy
- No Data Exfiltration: Reports generated locally in
assets/autonomous-cfo/output/ - No Telemetry: No usage data sent to external servers
- Network Isolation: Only connects to
specified inODOO_URL.env - Credential Security: Password/API key never logged or displayed
- Local Processing: All chart generation, PDF creation happens locally
Output Security
All outputs are local files only:
- PDF reportsoutput/pdf_reports/
- PNG image cardsoutput/whatsapp_cards/
- Chart imagesoutput/charts/
- Excel spreadsheetsoutput/excel/
No cloud upload, no external sharing, no data leaves your machine except to your specified Odoo instance.
Installation
The skill requires a Python virtual environment with specific packages:
cd skills/odoo/assets/autonomous-cfo ./install.sh
Or manually:
cd skills/odoo/assets/autonomous-cfo python3 -m venv venv ./venv/bin/pip install -r requirements.txt
Dependencies:
requests, matplotlib, pillow, fpdf2, openpyxl
Critical Rules
- NEVER assume - Always ask clarifying questions before generating reports
- Multi-company check - If multiple companies exist, ASK which one to use
- Ledger-based - Use Chart of Accounts and journal entries (account.move.line), not just invoice summaries
- Verify periods - Confirm date ranges with user before running
- No silent defaults - Every assumption must be confirmed
Before Any Report, Ask:
- "Which company should I use?" (if multiple exist)
- "What period? (from/to dates)"
- "Which accounts or account types to include?"
- "Any specific breakdown needed?" (by account, by partner, by journal, etc.)
- "Output format preference?" (PDF, WhatsApp cards, or both)
Entrypoint
Uses the venv with fpdf2, matplotlib, pillow for proper PDF/chart generation:
./skills/odoo/assets/autonomous-cfo/venv/bin/python ./skills/odoo/assets/autonomous-cfo/src/tools/cfo_cli.py <command>
Or from the skill directory:
cd skills/odoo/assets/autonomous-cfo && ./venv/bin/python src/tools/cfo_cli.py <command>
Chart of Accounts Based Reporting
Reports should be built from:
- Chart of Accounts structure (code, name, type, internal_group)account.account
- Journal entry lines (debit, credit, account_id, date)account.move.line
- Source journals (type: sale, purchase, cash, bank, general)account.journal
Account Internal Groups
- ASSET - Assets (current, non-current, cash, receivables)
- LIABILITY - Liabilities (payables, taxes, accrued)
- EQUITY - Owner's equity
- INCOME - Revenue accounts
- EXPENSE - Cost and expense accounts
- OFF_BALANCE - Off-balance sheet accounts
Common Account Types
- Bank and cash accountsasset_cash
- Accounts receivableasset_receivable
- Current assetsasset_current
- Accounts payableliability_payable
- Revenueincome
- Expensesexpense
Special Equity Types (Odoo-Specific)
- Standard equity accounts (share capital, retained earnings)equity
- Suspense account for undistributed profits/losses (e.g., 999999)equity_unaffected
CRITICAL for Balance Sheet: Odoo's
equity_unaffected is a SUSPENSE account. Do NOT use its ledger balance directly.
Correct Equity Calculation:
- Equity Proper (type:
) - Use ledger balance (credit - debit)equity - Retained Earnings (prior years) - Ledger balance from
equity_unaffected - Current Year Earnings - Compute real-time: Income - Expenses
Total Equity = Equity Proper + Retained Earnings + Current Year Earnings
Where Current Year Earnings = Σ(income credit-debit) - Σ(expense debit-credit)
Why this matters: Odoo computes Current Year Earnings in real-time on the Balance Sheet. Using only the
equity_unaffected ledger balance will cause the balance sheet to NOT balance.
Automatic Reporting Standard Detection
The skill automatically detects the company's accounting standard based on country/jurisdiction and formats reports accordingly.
Supported Standards:
| Standard | Jurisdiction | Notes |
|---|---|---|
| IFRS | International | Default for most countries |
| US GAAP | United States | SEC registrants |
| Ind-AS | India | Indian GAAP converged with IFRS |
| UK GAAP | United Kingdom | FRS 102 |
| SOCPA | Saudi Arabia | IFRS adopted |
| EU IFRS | European Union | IAS Regulation |
| CAS | China | Chinese Accounting Standards |
| JGAAP | Japan | Japanese GAAP |
| ASPE | Canada | Private enterprises |
| AASB | Australia | Australian standards |
Detection Logic:
- Query company's country from
res.company - Map country code to reporting standard
- Apply standard-specific formatting:
- Number format (1,234.56 vs 1.234,56)
- Negative display ((123) vs -123)
- Date format (DD/MM/YYYY vs MM/DD/YYYY)
- Statement titles (Balance Sheet vs Statement of Financial Position)
- Cash flow method (indirect vs direct)
Override:
# Force a specific standard reporter.generate(..., standard="US_GAAP")
Commands
Sales & CRM Queries
# Salesperson performance - use direct RPC for flexibility ./venv/bin/python -c " from src.visualizers.whatsapp_cards import WhatsAppCardGenerator # Query sale.order by user_id, aggregate by month/status # Generate cards with generate_kpi_card() and generate_comparison_card() " # Example RPC query for salesperson: # - sale.order (user_id, amount_total, state, date_order) # - account.move (invoice_user_id, amount_total, payment_state) # - res.users (salesperson info) # - res.partner (customer info)
Pre-built Reports
# Financial Health - cash flow, liquidity, burn rate, runway cfo_cli.py health --from YYYY-MM-DD --to YYYY-MM-DD --company-id ID # Revenue Analytics - MoM trends, top customers cfo_cli.py revenue --from YYYY-MM-DD --to YYYY-MM-DD --company-id ID # AR/AP Aging - overdue buckets cfo_cli.py aging --as-of YYYY-MM-DD --company-id ID # Expense Breakdown - by vendor/category cfo_cli.py expenses --from YYYY-MM-DD --to YYYY-MM-DD --company-id ID # Executive Summary - one-page CFO snapshot cfo_cli.py executive --from YYYY-MM-DD --to YYYY-MM-DD --company-id ID
Direct RPC Queries (Advanced)
For sales/CRM data not covered by pre-built commands, use direct RPC:
# Query sales orders by salesperson orders = jsonrpc('sale.order', 'search_read', [[('user_id', '=', SALESPERSON_ID)]], {'fields': ['name', 'partner_id', 'amount_total', 'state', 'date_order']}) # Query invoices by salesperson invoices = jsonrpc('account.move', 'search_read', [[('invoice_user_id', '=', SALESPERSON_ID), ('move_type', '=', 'out_invoice')]], {'fields': ['name', 'partner_id', 'amount_total', 'payment_state']}) # Find salesperson by name users = jsonrpc('res.users', 'search_read', [[('name', 'ilike', 'name_here')]], {'fields': ['id', 'name', 'login']})
Ad-hoc Reports
# Custom comparison cfo_cli.py adhoc --from YYYY-MM-DD --to YYYY-MM-DD --metric-a "revenue" --metric-b "expenses" # Examples: cfo_cli.py adhoc --metric-a "cash in" --metric-b "cash out" cfo_cli.py adhoc --metric-a "direct expenses" --metric-b "indirect expenses"
Output Formats
--output whatsapp # Dark theme 1080x1080 PNG cards --output pdf # Light theme A4 PDF --output excel # Excel workbook (.xlsx) --output both # PDF + WhatsApp cards --output all # PDF + Excel + WhatsApp cards
Automatic Visualizations
Reports always include appropriate visualizations by default:
| Report | Auto-Included Charts |
|---|---|
| Financial Health | Cash position, burn rate trend, runway |
| Revenue | MoM trend, top customers, growth KPI |
| AR/AP Aging | Aging buckets pie, overdue highlights |
| Expenses | Category breakdown, trend, top vendors |
| Executive | All KPI cards, summary charts |
| Balance Sheet | Asset/liability composition |
| P&L | Revenue vs expense, margin trend |
| Cash Flow | Operating breakdown, cash trend |
Rule: If visualization makes the report clearer, include it automatically. Never ask "do you want charts?" — just add them.
Interactive Param Collection
If required params are missing, the skill will ask:
- Company: "Which company?" (list available options)
- Period: "What period? (e.g., 'last month', 'Q4 2024', custom dates)"
- Accounts: "Which accounts or groups?" (e.g., 'all income', 'bank accounts only')
- Breakdown: "Group by? (Month, Customer, Category, Account)"
- Output: "Output format? (WhatsApp cards, PDF, Both)"
How to Use in Chat
Just ask naturally:
Sales & CRM:
- "How is [name] salesperson performance?"
- "Show me top customers for [salesperson]"
- "Compare sales team performance"
- "Which salesperson has the most orders?"
Financial Reports:
- "Give me a financial health report for last quarter"
- "Show revenue vs expenses for the past 6 months"
- "What's my AR aging?"
- "Generate an executive summary for this month"
- "Show me profit & loss statement based on chart of accounts"
General Queries:
- "How many orders did we get this month?"
- "Who are the top 10 customers?"
- "Show invoice status for [customer name]"
The skill will:
- Check for multiple companies and ask which one
- Parse your request
- Ask for any missing info
- Fetch data from Odoo using ledger entries or direct RPC
- Generate charts + WhatsApp cards
- Deliver via WhatsApp cards and/or PDF
Hard Rules
- Odoo RPC output is source of truth
- Strict read-only (no create/write/unlink)
- No proactive actions unless requested
- Every number includes methodology note
- Always verify with user before assuming
- Always include visualizations - If a report benefits from charts/graphs, include them automatically without asking. Reports should be visually complete.
Diagnostics
python3 ./skills/odoo/assets/autonomous-cfo/src/tools/cfo_cli.py doctor
Report Themes
- WhatsApp Cards: "Midnight Ledger" — Navy-black (#0a0e1a), copper glow (#cd7f32)
- PDF Reports: Clean white, copper accents, professional layout