PHP code example of obuchmann / odoo-jsonrpc

1. Go to this page and download the library: Download obuchmann/odoo-jsonrpc library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

obuchmann / odoo-jsonrpc example snippets


use Obuchmann\OdooJsonRpc\Odoo;
use Obuchmann\OdooJsonRpc\Odoo\Request\Arguments\Domain;

$this->host = 'http://localhost:8069';
$this->username = 'admin';
$this->password = 'password';
$this->database = 'odoo';

// Connect to Odoo
$odoo = new Odoo(new Odoo\Config($database, $host, $username, $password));
$odoo->connect();


// Check Access rights (bool)
$check = $odoo->checkAccessRights('res.partner', 'read');

// List model fields
$fields = $odoo->listModelFields('res.partner');

// Check Access rights in model syntax

$check = $odoo->model('res.partner')
            ->can('read');
            
// Use Domain for Search
// You can also use orWhere() when building domains: $domain->orWhere('field', 'operator', 'value');
$isCompanyDomain = (new Domain())->where('is_company', '=', true);
$companyIds = $odoo->search('res.partner', $isCompanyDomain);

// read ids
$companies = $odoo->read('res.partner', $companyIds);

// search_read with model Syntax
$companies = $odoo->model('res.partner')
            ->where('is_company', '=', true)
            ->get();
            
// search_read with single item
$company = $odoo->model('res.partner')
            ->where('is_company', '=', true)
            ->where('name', '=', 'My Company')
            ->first();

// Count records directly
$count = $odoo->count('res.partner', $isCompanyDomain);

// Count records with model syntax
$count = $odoo->model('res.partner')
            ->where('is_company', '=', true)
            ->count();

// Group records and aggregate fields
$groupedData = $odoo->model('res.partner')
    ->where('active', '=', true)
    ->groupBy(['country_id']) // Fields to group by (e.g., 'country_id', ['category_id', 'state_id'])
    ->fields(['id', 'name']) // Fields to retrieve in each group
    ->get();
// This typically returns an array of objects, where each object has the grouped fields and any aggregated fields.
            
// create with model syntax
$partner = $odoo->model('res.partner')
            ->create([
                'name' => 'My Company',
                'is_company' => true
            ]);
            
// update with model syntax
$partner = $odoo->model('res.partner')
            ->where('name', '=', 'My Company')
            ->update([
                'name' => 'My New Company'
            ]);
// direct update by id            
$myCompanyId = 1;
$partner = $odoo->updateById('res.partner', $myCompanyId, [
    'name' => 'My New Company'
]);

// delete by id
$odoo->deleteById('res.partner', $myCompanyId);

// Execute arbitrary keywords (custom RPC calls)
$customResult = $odoo->executeKw('res.partner', 'check_access_rule', [[$myCompanyId], 'read']);
// The arguments for executeKw (the third parameter) depend on the specific Odoo method being called.



class Controller{

    public function index(\Obuchmann\OdooJsonRpc\Odoo $odoo){
        // Find Model by Id
        $product = $odoo->find('product.template', 1);
        
        // Update Model by ID
        $this->odoo->updateById('product.product', $product->id, [
            'name' => $name,
        ]);
        
        // Create returning ID
        $id = $this->odoo
            ->create('res.partner', [
                'name' => 'Bobby Brown'
            ]);
        
        // Search for Models with or
        $partners = $this->odoo->model('res.partner')
            ->where('name', '=', 'Bobby Brown')
            ->orWhere('name', '=', 'Gregor Green')
            ->limit(5)
            ->orderBy('id', 'desc')
            ->get();
        
        // Update by Query
        $updateResponse = $this->odoo
            ->model('res.partner')
            ->where('name', '=', 'Bobby Brown')
            ->update([
                'name' => 'Dagobert Duck'
            ]);
    }
}

    // config/odoo.php
    return [
        // ... other configurations
        'host' => env('ODOO_HOST',''),
        'database' => env('ODOO_DATABASE',''),
        'username' => env('ODOO_USERNAME', ''),
        'password' => env('ODOO_PASSWORD', ''),
        'fixed_user_id' => env('ODOO_FIXED_USER_ID', null), // <--- Add this line
        // ... other configurations
    ];
    

#[Model('res.partner')]
class Partner extends OdooModel
{
    #[Field]
    public string $name;

    #[Field('email')]
    public ?string $email;

    #[Field('country_id')] // The Odoo foreign key field name
    #[BelongsTo('country_id', Country::class)] // First param is Odoo FK name, second is related model class
    public ?Country $country;
    // Defines an inverse one-to-one or many-to-one relationship.
    // Parameters for #[BelongsTo]:
    //   - name (string): The name of the foreign key field in the Odoo model (e.g., 'country_id').
    //                    This name *must* match the name specified in the #[Field] attribute.
    //   - class (string): The fully qualified class name of the related OdooModel (e.g., Country::class).
    // Type hinting:
    //   - Should be type-hinted as nullable (e.g., ?Country) if the relationship can be optional.
    //   - Or non-nullable (e.g., Country) if it's mandatory (though Odoo relations are generally nullable).
    // Data access:
    //   - Accessing the property (e.g., $partner->country) returns an instance of the related model (Country)
    //     or null if the relation is not set or the related record doesn't exist.
    //   - Related model properties can be accessed using the nullsafe operator (e.g., $partner->country?->name).

    #[Field('child_ids')] // The Odoo field name on the current model holding related IDs
    #[HasMany(Partner::class, 'child_ids')] // First param is related model class, second is Odoo field name
    public array $children;
    // Defines a one-to-many or many-to-many relationship.
    // Parameters for #[HasMany]:
    //   - class (string): The fully qualified class name of the related OdooModel (e.g., Partner::class).
    //   - name (string): The name of the Odoo field on the *current* model that holds the IDs of the related models (e.g., 'child_ids').
    //                    This name *must* match the name specified in the #[Field] attribute.
    // Type hinting:
    //   - Should be type-hinted as `array` or `iterable`. The property will be an instance of `LazyHasMany`.

    // Lazy Loading Behavior:
    // The `HasMany` relationship implements lazy loading to optimize performance.
    // 1. Initial Fetch: When a model instance is fetched (e.g., `$partner = Partner::find(1);`),
    //    the `children` property is initialized with a `LazyHasMany` object, but no related data is fetched from Odoo yet.
    //    `$partner->children->isLoaded()` would return `false` at this point.
    // 2. Data Trigger: The actual child records are fetched from Odoo only when the `LazyHasMany` collection is first accessed.
    //    This 
            ->fields(['name', 'email']) // Specify fields to retrieve
            ->where('is_company', '=', true)
            ->get();

        // Search model with ordering
        $sortedPartners = Partner::query()
            ->orderBy('name', 'asc') // Order by name ascending
            ->limit(10)
            ->get();

        // Update Model
        // You can also use $partner->fill(['name' => 'Dagobert Duck', 'email' => '[email protected]']) for mass assignment
        $partner->name = "Dagobert Duck";
        $partner->save();
        
        // Create model
        $newPartner = new Partner();
        $newPartner->name = 'Tester';
        // or using fill:
        // $newPartner->fill(['name' => 'Tester', 'is_company' => false]);
        $newPartner->save(); // The ID is set on $newPartner->id after saving. save() returns true on success.

        // Comparing models
        $anotherPartner = Partner::find(1);
        if ($partner->equals($anotherPartner)) {
            // Models are considered equal if they are of the same class and have the same ID
        }
    }
}

### Field Type Casting
For handling specific field types like dates or custom Odoo types, please refer to the [Casts](#casts) section.

// Example: Registering the built-in DateTimeCast
\Obuchmann\OdooJsonRpc\Odoo::registerCast(new \Obuchmann\OdooJsonRpc\Odoo\Casts\DateTimeCast());

// Example: Registering a DateTime cast that respects a specific timezone
\Obuchmann\OdooJsonRpc\Odoo::registerCast(new \Obuchmann\OdooJsonRpc\Odoo\Casts\DateTimeTimezoneCast(new \DateTimeZone('Europe/Berlin')));



namespace App\OdooModels;

use Obuchmann\OdooJsonRpc\Odoo\OdooModel;
use Obuchmann\OdooJsonRpc\Attributes\Model;
use Obuchmann\OdooJsonRpc\Attributes\Field;

#[Model('some.odoo.model')]
class SomeOdooModel extends OdooModel
{
    #[Field]
    public int $id;

    #[Field('name')]
    public string $name;

    #[Field('create_date')] // This is the field name in Odoo
    public ?\DateTime $createdAt; // Property type-hinted as \DateTime

    // Other fields...
}

// Assuming DateTimeCast is registered globally as shown above

// Fetching a model
$model = SomeOdooModel::find(1);

if ($model && $model->createdAt instanceof \DateTime) {
    // $model->createdAt is already a \DateTime object!
    echo "Created at: " . $model->createdAt->format('Y-m-d H:i:s');
}

// Setting a DateTime value
$newModel = new SomeOdooModel();
$newModel->name = "New Record";
$newModel->createdAt = new \DateTime('now', new \DateTimeZone('UTC')); // Assign a DateTime object

// When $newModel->save() is called, the createdAt property (which is a \DateTime object)
// will be automatically converted by DateTimeCast::uncast() to a string like 'YYYY-MM-DD HH:MM:SS'
// before being sent to Odoo.
$newModel->save();


namespace Obuchmann\OdooJsonRpc\Odoo\Casts;

class DateTimeCast extends Cast
{
    public function getType(): string
    {
        return \DateTime::class;
    }

    public function cast($raw)
    {
        if($raw){ // Odoo might send 'false' for empty date/datetime fields
            try {
                // Attempt to create a DateTime object from the raw string
                return new \DateTime($raw);
            } catch (\Exception) {
                // If parsing fails (e.g., invalid date format), return null
                return null;
            }
        }
        return null; // Return null if raw value is false or empty
    }

    public function uncast($value)
    {
        if($value instanceof \DateTime){
            // Format the DateTime object into Odoo's expected string format
            return $value->format('Y-m-d H:i:s');
        }
        // If it's not a DateTime object (e.g., null), return it as is
        // Odoo typically expects 'false' for empty date/datetime fields if not setting a value
        return $value === null ? false : $value;
    }
}
bash
php artisan vendor:publish --provider="Obuchmann\OdooJsonRpc\OdooServiceProvider" --tag="config"