UNPKG

odoo-xmlrpc-ts

Version:

Type-safe Odoo XML-RPC client for Node.js written in TypeScript

380 lines (285 loc) 9.55 kB
# odoo-xmlrpc-ts A type-safe Odoo XML-RPC client for Node.js written in TypeScript. This package provides a robust interface to interact with Odoo's external API through XML-RPC. ## Features - ✨ Full TypeScript support with type definitions - 🔄 Promise-based API - 🔐 Automatic authentication handling - 🛡️ Comprehensive error handling - 🎯 Support for all major Odoo operations - 📝 Built-in TypeScript interfaces for Odoo models - 🔍 Type-safe domain builders - 📦 Zero external dependencies except xmlrpc - 🔄 Supports both ESM and CommonJS ## Prerequisites - Node.js >= 18 - pnpm >= 8 - Odoo instance with XML-RPC enabled - API access enabled in your Odoo instance ## Installation ```bash pnpm add odoo-xmlrpc-ts ``` Using npm: ```bash npm install odoo-xmlrpc-ts ``` Using yarn: ```bash yarn add odoo-xmlrpc-ts ``` ## Usage ### ESM Import ```typescript import { OdooClient } from 'odoo-xmlrpc-ts'; ``` ### CommonJS Require ```javascript const { OdooClient } = require('odoo-xmlrpc-ts'); ``` ### Basic Example ```typescript import { OdooClient } from 'odoo-xmlrpc-ts'; // Or for CommonJS: // const { OdooClient } = require('odoo-xmlrpc-ts'); // Define your model interfaces interface Partner { id: number; name: string; email?: string; is_company: boolean; } async function example() { // Initialize client const client = new OdooClient({ url: 'https://your-odoo-instance.com', db: 'your-database', username: 'admin', password: 'admin', }); try { // Search and read partners const partners = await client.searchRead<Partner>('res.partner', [['is_company', '=', true]], { fields: ['name', 'email'], limit: 10, }); console.log('Partners:', partners); } catch (error) { if (error instanceof OdooError) { console.error('Odoo Error:', error.message); } } } ``` ### HTTP Agent Configuration You can configure custom HTTP agents for advanced network configurations such as custom SSL settings, or connection pooling: > **Note**: Odoo doesn't support HTTPS natively. For production deployments, place Odoo behind a reverse proxy (Nginx/Apache) with SSL termination. The agent configuration below is useful when connecting to such HTTPS-enabled Odoo instances. ```typescript import { OdooClient } from 'odoo-xmlrpc-ts'; import https from 'node:https'; import fs from 'node:fs'; // Example: Custom HTTPS agent with specific SSL options const httpsAgent = new https.Agent({ ca: fs.readFileSync('/path/to/ca-certificate.pem'), // Custom CA certificate keepAlive: true, maxSockets: 10, }); // Alternative: For development/testing only (not recommended for production) const httpsAgent = new https.Agent({ rejectUnauthorized: false, // Disables SSL verification (use only for testing) keepAlive: true, maxSockets: 10, }); const client = new OdooClient({ url: 'https://your-odoo-instance.com', // HTTPS URL (via reverse proxy) db: 'your-database', username: 'admin', password: 'admin', agent: httpsAgent, }); ``` ### Advanced Usage ```typescript import { OdooClient, OdooBaseModel } from 'odoo-xmlrpc-ts'; // Extend the base model interface interface CustomPartner extends OdooBaseModel { name: string; email: string; phone?: string; is_company: boolean; child_ids: number[]; } async function advancedExample() { const client = new OdooClient({ url: 'https://your-odoo-instance.com', db: 'your-database', username: 'admin', password: 'admin', }); // Create a new partner const partnerId = await client.create<Partial<CustomPartner>>('res.partner', { name: 'Test Company', is_company: true, email: 'test@example.com', }); // Read the created partner const [partner] = await client.read<CustomPartner>('res.partner', [partnerId]); // Update the partner await client.write<Partial<CustomPartner>>('res.partner', [partnerId], { phone: '+1234567890', }); // Delete the partner await client.unlink('res.partner', [partnerId]); } ``` ## API Reference ### Constructor ```typescript const client = new OdooClient({ url: string; // Odoo instance URL db: string; // Database name username: string; password: string; agent?: https.Agent | http.Agent; // Optional HTTP agent for custom network configuration }); ``` ### Methods #### `async version(): Promise<OdooVersion>` Get Odoo server version information. #### `async authenticate(): Promise<number>` Authenticate with the Odoo server. Called automatically when needed. #### `async search(model: string, domain: OdooDomain, options?: SearchOptions): Promise<number[]>` Search for record IDs. ```typescript interface SearchOptions { offset?: number; limit?: number; order?: string; } ``` #### `async searchRead<T>(model: string, domain: OdooDomain, options?: SearchReadOptions): Promise<T[]>` Search and read records in one call. ```typescript interface SearchReadOptions extends SearchOptions { fields?: string[]; } ``` #### `async read<T>(model: string, ids: number[], fields?: string[]): Promise<T[]>` Read specific records by ID. #### `async create<T>(model: string, values: T): Promise<number>` Create a new record. #### `async write<T>(model: string, ids: number[], values: T): Promise<boolean>` Update existing records. #### `async unlink(model: string, ids: number[]): Promise<boolean>` Delete records. #### `async fieldsGet(model: string, attributes?: string[]): Promise<OdooFieldsMap>` Get field information for a model. #### `async execute<T>(model: string, method: string, args?: any[], kwargs?: object): Promise<T>` Execute any method on an Odoo model. This is useful for calling custom methods or workflow actions. ```typescript // Example: Confirm a sale order await client.execute('sale.order', 'action_confirm', [orderId]); // Example: Send email using template await client.execute('mail.template', 'send_mail', [templateId, recordId]); // Example: Custom method with keyword arguments await client.execute('your.model', 'your_method', [arg1, arg2], { kwarg1: 'value1', kwarg2: 'value2' }); ## Error Handling The client includes built-in error classes: - `OdooError`: Base error class for all Odoo-related errors - `OdooAuthenticationError`: Authentication-specific errors ```typescript try { await client.authenticate(); } catch (error) { if (error instanceof OdooAuthenticationError) { console.error('Authentication failed:', error.message); } } ``` ## Development ```bash # Install dependencies pnpm install # Build pnpm run build # Run tests pnpm test # Run tests with coverage pnpm test:coverage # Lint pnpm run lint # Format code pnpm run format # Type check pnpm run type-check ``` ## Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'feat: add amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ## Common Issues ### CORS Issues If you're using this client in a browser environment, you might encounter CORS issues. This client is intended for Node.js usage. For browser environments, consider using Odoo's JSON-RPC interface instead. ### Authentication Issues Make sure your Odoo instance has XML-RPC enabled and your user has the necessary access rights. For Odoo.sh or Odoo Online instances, you might need to whitelist your IP address. ## Notes & Considerations ### HTTPS/SSL Deployment - Odoo doesn't provide native HTTPS support (removed since ~v6.1) - Production deployments require a reverse proxy (Nginx/Apache) for SSL termination - Use `proxy_mode = 1` in Odoo configuration when behind a proxy - The HTTP agent configuration is useful for custom SSL certificates and corporate environments ### XML-RPC vs JSON-RPC - This library uses Odoo's XML-RPC endpoints (`/xmlrpc/2/common`, `/xmlrpc/2/object`) - Odoo also provides JSON-RPC endpoints (`/jsonrpc`) - these are separate protocols - Both provide the same functionality; JSON-RPC is lighter weight - XML-RPC is well-documented with many examples and good TypeScript support ## Contributors Thanks to all the amazing contributors who have made this project possible: <!-- ALL-CONTRIBUTORS-LIST:START --> <table> <tr> <td align="center"> <a href="https://github.com/iraycd"> <img src="https://avatars.githubusercontent.com/u/1450984?v=4" width="100px;" alt="Ray Ch"/> <br /> <sub><b>Ray Ch</b></sub> </a> <br /> <sub>29 contributions</sub> </td> <td align="center"> <a href="https://github.com/Haris565"> <img src="https://avatars.githubusercontent.com/u/64888353?v=4" width="100px;" alt="Haris565"/> <br /> <sub><b>Haris565</b></sub> </a> <br /> <sub>3 contributions</sub> </td> <td align="center"> <a href="https://github.com/Xstoudi"> <img src="https://avatars.githubusercontent.com/u/2575182?v=4" width="100px;" alt="Xavier Stouder"/> <br /> <sub><b>Xavier Stouder</b></sub> </a> <br /> <sub>1 contribution</sub> </td> <td align="center"> <a href="https://github.com/vendethiel"> <img src="https://avatars.githubusercontent.com/u/199499?v=4" width="100px;" alt="ven"/> <br /> <sub><b>ven</b></sub> </a> <br /> <sub>1 contribution</sub> </td> </tr> </table> <!-- ALL-CONTRIBUTORS-LIST:END --> ## License MIT © Dilip Ray Ch