Complete API reference for the Odoo client and cache stores in generated PWAs. ## What this command does: - Provides comprehensive API documentation - Lists all available methods and functions - Shows parameter types and return values - Includes code examples for each method - Helps developers use the generated code effectively --- ## Odoo API Client Reference 🔌 The Odoo API client (`src/lib/odoo.js` or equivalent) provides methods for interacting with Odoo Studio models. ### Configuration #### Environment Variables ```bash VITE_ODOO_URL=https://yourcompany.odoo.com VITE_ODOO_DB=yourcompany-main ODOO_API_KEY=your_api_key ODOO_USERNAME=your.email@company.com VITE_MODEL_NAME=x_expense ``` --- ## CRUD Operations ### createRecord() Create a new record in Odoo. **Signature:** ```javascript async function createRecord(model, fields) ``` **Parameters:** - `model` (string) - Odoo model name (e.g., 'x_expense') - `fields` (object) - Field values to set **Returns:** Promise - ID of created record **Example:** ```javascript const newId = await odoo.createRecord('x_expense', { x_studio_description: 'Team lunch', x_studio_amount: 45.50, x_studio_date: '2025-01-15', x_studio_category: 'meal', x_studio_employee: odoo.formatMany2one(12) }); console.log(`Created expense with ID: ${newId}`); ``` **Error Handling:** ```javascript try { const id = await odoo.createRecord('x_expense', fields); } catch (error) { console.error('Failed to create:', error.message); // Handle error (show message to user, retry, etc.) } ``` --- ### searchRecords() Search and read records from Odoo. **Signature:** ```javascript async function searchRecords(model, domain, fields, limit = null, offset = null) ``` **Parameters:** - `model` (string) - Odoo model name - `domain` (array) - Odoo domain filter (e.g., [['id', '>', 100]]) - `fields` (array) - List of field names to fetch - `limit` (number, optional) - Maximum number of records - `offset` (number, optional) - Number of records to skip **Returns:** Promise> - Array of record objects **Example:** ```javascript // Get all expenses const allExpenses = await odoo.searchRecords( 'x_expense', [], ['x_studio_description', 'x_studio_amount', 'x_studio_date'] ); // Get expenses > $100 const largeExpenses = await odoo.searchRecords( 'x_expense', [['x_studio_amount', '>', 100]], ['x_studio_description', 'x_studio_amount'] ); // Get recent 10 expenses const recentExpenses = await odoo.searchRecords( 'x_expense', [], ['x_studio_description', 'x_studio_date'], 10 // limit ); // Get expenses with pagination const page2 = await odoo.searchRecords( 'x_expense', [], fields, 20, // limit: 20 per page 20 // offset: skip first 20 (page 2) ); ``` **Domain Syntax:** ```javascript // Equals [['x_studio_status', '=', 'draft']] // Greater than [['x_studio_amount', '>', 100]] // In list [['x_studio_category', 'in', ['meal', 'travel']]] // Multiple conditions (AND) [ ['x_studio_amount', '>', 50], ['x_studio_status', '=', 'draft'] ] // OR conditions ['|', ['x_studio_amount', '>', 100], ['x_studio_category', '=', 'travel'] ] // Complex: (amount > 100 OR category = travel) AND status = draft ['&', '|', ['x_studio_amount', '>', 100], ['x_studio_category', '=', 'travel'], ['x_studio_status', '=', 'draft'] ] ``` --- ### updateRecord() Update an existing record. **Signature:** ```javascript async function updateRecord(model, id, values) ``` **Parameters:** - `model` (string) - Odoo model name - `id` (number) - Record ID to update - `values` (object) - Fields to update **Returns:** Promise - true if successful **Example:** ```javascript await odoo.updateRecord('x_expense', 123, { x_studio_status: 'approved', x_studio_amount: 55.00 }); // Update multiple fields await odoo.updateRecord('x_expense', 123, { x_studio_description: 'Updated description', x_studio_date: '2025-01-20', x_studio_notes: 'Added receipt' }); ``` --- ### deleteRecord() Delete a record from Odoo. **Signature:** ```javascript async function deleteRecord(model, id) ``` **Parameters:** - `model` (string) - Odoo model name - `id` (number) - Record ID to delete **Returns:** Promise - true if successful **Example:** ```javascript await odoo.deleteRecord('x_expense', 123); // With confirmation if (confirm('Are you sure you want to delete this expense?')) { await odoo.deleteRecord('x_expense', expenseId); } ``` **Error Handling:** ```javascript try { await odoo.deleteRecord('x_expense', id); console.log('Deleted successfully'); } catch (error) { console.error('Failed to delete:', error.message); alert('Could not delete: ' + error.message); } ``` --- ## Helper Methods ### fetchPartners() Fetch partner (res.partner) records. **Signature:** ```javascript async function fetchPartners(ids = null) ``` **Parameters:** - `ids` (array, optional) - Specific partner IDs to fetch. If null, fetches all. **Returns:** Promise> - Array of partner objects **Example:** ```javascript // Fetch all partners const allPartners = await odoo.fetchPartners(); // Fetch specific partners const somePartners = await odoo.fetchPartners([1, 2, 3]); // Use in dropdown const partners = await odoo.fetchPartners(); // Display: partners.map(p => ({ value: p.id, label: p.name })) ``` --- ### formatMany2one() Format a Many2one field value for Odoo. **Signature:** ```javascript function formatMany2one(id) ``` **Parameters:** - `id` (number | null) - Partner/record ID **Returns:** Array | false - Odoo-formatted value **Example:** ```javascript // Set employee field const fields = { x_studio_employee: odoo.formatMany2one(12) // Result: [12, false] }; // Clear employee field const fields = { x_studio_employee: odoo.formatMany2one(null) // Result: false }; ``` --- ### formatMany2many() Format a Many2many field value for Odoo. **Signature:** ```javascript function formatMany2many(ids) ``` **Parameters:** - `ids` (array) - Array of record IDs **Returns:** Array - Odoo command format **Example:** ```javascript // Set tags (replace all) const fields = { x_studio_tags: odoo.formatMany2many([1, 2, 3]) // Result: [[6, 0, [1, 2, 3]]] }; // Clear tags const fields = { x_studio_tags: odoo.formatMany2many([]) // Result: [[6, 0, []]] }; ``` **Odoo Many2many Commands:** ```javascript // (6, 0, [ids]) - Replace all (what formatMany2many uses) // (4, id) - Add link to id // (3, id) - Remove link to id // (5, 0) - Remove all links ``` --- ## Cache Store API Reference 💾 The cache store provides reactive state management with offline-first capabilities. ### Properties #### records **Type:** Reactive Array Current cached records. **Example:** ```javascript // SvelteKit $: totalAmount = $expenseCache.reduce((sum, e) => sum + e.x_studio_amount, 0); // React const totalAmount = useMemo(() => records.reduce((sum, e) => sum + e.x_studio_amount, 0), [records] ); // Vue const totalAmount = computed(() => expenseStore.records.reduce((sum, e) => sum + e.x_studio_amount, 0) ); ``` #### isLoading **Type:** Reactive Boolean Loading state indicator. **Example:** ```javascript {#if $expenseCache.isLoading} {:else} {/if} ``` #### error **Type:** Reactive String | null Current error message, if any. **Example:** ```javascript {#if $expenseCache.error} {/if} ``` #### lastSync **Type:** Reactive Number (timestamp) Timestamp of last successful sync. **Example:** ```javascript const timeSinceSync = Date.now() - $expenseCache.lastSync; const minutes = Math.floor(timeSinceSync / 60000); // Display: "Last synced ${minutes} minutes ago" ``` --- ### Methods ### load() Load records from cache and trigger background sync. **Signature:** ```javascript async function load() ``` **Returns:** Promise **Behavior:** 1. Loads from cache immediately (instant UI update) 2. Checks if cache is stale (> 5 minutes) 3. If stale, syncs in background 4. Updates UI when new data arrives **Example:** ```javascript // SvelteKit $effect(() => { expenseCache.load(); }); // React useEffect(() => { expenseCache.load(); }, []); // Vue onMounted(() => { expenseStore.load(); }); ``` --- ### create() Create a new record with optimistic update. **Signature:** ```javascript async function create(data) ``` **Parameters:** - `data` (object) - Field values for new record **Returns:** Promise - ID of created record **Behavior:** 1. Generates temporary ID 2. Adds to cache immediately (optimistic) 3. Creates in Odoo (background) 4. Replaces temp ID with real ID 5. Rolls back on error **Example:** ```javascript try { const newId = await expenseCache.create({ x_studio_description: 'Lunch meeting', x_studio_amount: 45.50, x_studio_date: '2025-01-15', x_studio_category: 'meal' }); console.log('Created:', newId); navigate(`/expenses/${newId}`); } catch (error) { alert('Failed to create: ' + error.message); } ``` --- ### update() Update an existing record. **Signature:** ```javascript async function update(id, data) ``` **Parameters:** - `id` (number) - Record ID - `data` (object) - Fields to update **Returns:** Promise **Behavior:** 1. Updates cache immediately (optimistic) 2. Updates in Odoo (background) 3. Rolls back on error **Example:** ```javascript await expenseCache.update(123, { x_studio_amount: 50.00, x_studio_status: 'submitted' }); ``` --- ### delete() Delete a record. **Signature:** ```javascript async function remove(id) ``` **Parameters:** - `id` (number) - Record ID to delete **Returns:** Promise **Behavior:** 1. Removes from cache immediately 2. Deletes from Odoo (background) 3. Restores on error **Example:** ```javascript if (confirm('Delete this expense?')) { try { await expenseCache.remove(123); navigate('/expenses'); } catch (error) { alert('Failed to delete: ' + error.message); } } ``` --- ### refresh() Force refresh from Odoo. **Signature:** ```javascript async function refresh() ``` **Returns:** Promise **Behavior:** 1. Fetches all records from Odoo 2. Replaces cache 3. Updates UI **Example:** ```javascript // Manual refresh button ``` --- ### clearCache() Clear all cached data. **Signature:** ```javascript function clearCache() ``` **Returns:** void **Behavior:** 1. Clears localStorage 2. Clears IndexedDB 3. Resets records to empty array **Example:** ```javascript // Logout function async function logout() { expenseCache.clearCache(); // Clear other caches navigate('/login'); } ``` --- ## Advanced Patterns ### Custom Filters ```javascript // Derived store (SvelteKit) import { derived } from 'svelte/store'; export const draftExpenses = derived( expenseCache, $cache => $cache.filter(e => e.x_studio_status === 'draft') ); // Hook (React) function useDraftExpenses() { const { records } = useExpense(); return useMemo( () => records.filter(e => e.x_studio_status === 'draft'), [records] ); } // Computed (Vue) const draftExpenses = computed(() => expenseStore.records.filter(e => e.x_studio_status === 'draft') ); ``` ### Sorting ```javascript export const sortedExpenses = derived( expenseCache, $cache => [...$cache].sort((a, b) => b.x_studio_date.localeCompare(a.x_studio_date) ) ); ``` ### Search ```javascript function searchExpenses(query) { return records.filter(e => e.x_studio_description.toLowerCase().includes(query.toLowerCase()) ); } ``` ### Grouping ```javascript function groupByCategory(records) { return records.reduce((groups, record) => { const category = record.x_studio_category; if (!groups[category]) groups[category] = []; groups[category].push(record); return groups; }, {}); } ``` ### Aggregation ```javascript function getTotalByCategory(records) { return records.reduce((totals, record) => { const cat = record.x_studio_category; totals[cat] = (totals[cat] || 0) + record.x_studio_amount; return totals; }, {}); } ``` --- ## Server Route API Reference 🔐 The server route (`src/routes/api/odoo/+server.js`) handles Odoo communication. ### Endpoint **URL:** `/api/odoo` **Method:** POST **Content-Type:** application/json ### Request Format ```json { "action": "create|search|update|delete", "model": "x_expense", ...parameters } ``` ### Actions #### create ```json { "action": "create", "model": "x_expense", "fields": { "x_studio_description": "Lunch", "x_studio_amount": 45.50 } } ``` **Response:** `{ "id": 123 }` #### search ```json { "action": "search", "model": "x_expense", "domain": [["id", ">", 100]], "fields": ["x_studio_description", "x_studio_amount"] } ``` **Response:** `{ "records": [...] }` #### update ```json { "action": "update", "model": "x_expense", "id": 123, "values": { "x_studio_amount": 50.00 } } ``` **Response:** `{ "success": true }` #### delete ```json { "action": "delete", "model": "x_expense", "id": 123 } ``` **Response:** `{ "success": true }` --- ## Example prompts to use this command: - `/api-reference` - Show complete API documentation - User: "What methods are available in the Odoo client?" - User: "How do I use the cache store?" - User: "Show me API examples" ## Next Steps: - Try the methods in your project - Review `/examples` for practical use cases - See `/architecture` for design patterns - Check `/help` for more information