Interaction between Odoo and PHP via XML-RPC

Web Services with Odoo (OpenERP)

Auteur

Thierry Godin

This is a small presentation of the use of Web Services to allow PHP to read and write to Odoo database but also to trigger any function of a module.

- Titre : Interaction between Odoo and PHP via XML-RPC

- Auteur : Thierry Godin

- Parution : 17 septembre 2014

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 Thierry Godin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Presentation of XML-RPC

- II. Requirements

- III. Installation

- IV. Reminder

- V. Connection to Odoo

- VI. xmlprcval()

- VII. Implementation of the create() method

- VIII. Entire create() script

- IX. search() and read() methods

- X. Statement of the result

- XI. search() and read() entire script

- XII. search() and unlink() methods

- XIII. search() and unlink() entire script :

- XIV. Write() method

- XV. And after ???

- XVI. Download

- XVII. Documentation

- XVIII. Thanks

I - Presentation of XML-RPC

WARNING

This is the english translation of the french article I made.

My native language is french. I have some basic knowledge of english language, thus I translated the tutorial by myself and sometimes by the use of a famous translation service, so I hope the whole text is easily understandable.

Whatever, the french version prevails.

In case of misunderstanding, do not hesitate to contact me at OpenERP Official Forum

Thank you for reading

Simply put, the XML-RPC Web Service is a set of tools and specifications that allow software running on different operating systems, running in different environments to make procedure calls over the Internet.

This is the procedure call remotely via HTTP as transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned.

II - Requirements

To use the XML-RPC protocol with PHP, you'll need the PHPXML-RPC library.

Official website :XML-RPC for PHP

To go into this tutorial, you need a good knowledge of the following programming languages:

- PHP ;

- Python ;

- XML.

And you must certainly be well familiar with the OpenERP ORM.

III - Installation

Download the library and unzip the archive.

Copy the files that are in the « lib » directory on your server.

Tip :

For clarity and ease of maintenance, I recommend you create a « xmlrpc_lib » directory (for example) on your server and to put files in this directory.

IV - Reminder

We will act on Odoo from a website using the PHP programming language. For the tutorial, I installed OpenERP 7 (7.0-20140627-231127) with demo data on a Debian 7 (wheezy) server. I created an Apache virtual host on a Suse Linux 10 Server, already configured for the Web (PHP, MySQL, etc.).

So Odoo is on the Debian server, and PHP scripts are executed on the Suse server. These tests are performed on my local network, so you will have of course to change the URL in the scripts.

Also, I show you the different HTTP / HTTPS connections, but the tests are carried out locally by HTTP.

V - Connection to Odoo

To perform functions in Odoo, it is necessary first, to connect, and then call a function of a module.

To connect, we will create an XML-RPC client:

Creating XMLRPC client

$server_url = 'https://www.mon-serveur-openerp.com:8069'; //connexion sécurisée
$sock = new xmlrpc_client($server_url . "/xmlrpc/common");
$sock->setSSLVerifyPeer(0);

Tip:

If you are using a secure connection, you can override the SSL certificate verification with setSSLVerifyPeer (0);

The connection may fail in case of a self-signed certificate, for example.

We will then send a XML-RPC command, ie: we call a Odoo Python function. Here we call the « login » function

To pass parameters to this function, we will use the AddParam() function by creating a xmlrpcval() object (value on XML-RPC format):

Connecting to Odoo

$user = 'admin';
$password = 'mY5up3rPwd';
$dbname = 'test';

$server_url = 'https://www.monsite.com:8069'; //connexion sécurisée
$connexion = new xmlrpc_client($server_url . "/xmlrpc/common");
$connexion->setSSLVerifyPeer(0);

$c_msg = new xmlrpcmsg('login');
$c_msg->addParam(new xmlrpcval($dbname, "string"));
$c_msg->addParam(new xmlrpcval($user, "string"));
$c_msg->addParam(new xmlrpcval($password, "string"));
$c_response = $connexion->send($c_msg);

Info :

We use the URL /xmlrpc/common for the following methods:

'login', 'about', 'timezone_get', 'get_server_environment', 'login_message','get_stats', 'check_connectivity', 'list_http_services', 'version', 'authenticate'

Then simply return the response to see if the connection has been established.

In case of error a message is displayed

if ($c_response->errno != 0){
echo  '<p>error : ' . $c_response->faultString() . '</p>';
}
else{
//… on continue le script
}

Here, if errno!=0, so there was an error message and the connection was refused. Otherwise, we have established the connection, we can then retrieve the UID of the user. This is the UID that will then be sent to each XML-RPC request.

If you well remind, most of the Python functions Odoo require the user ID:

def function(self, cr, uid, …) :

Retrieve the uid of the user

$uid = $c_response->value()->scalarval();

VI - xmlprcval()

As we have seen, to pass parameters to functions we format the data with the object xmlrpcval(value, type).

The different types accepted are : string, i4, int, double, boolean, dateTime.iso8601, base64, null, array et struct.

struct is used to pass field names and their value on xmlprcval() format.

In the example below, we will create a customer (partner):

$val = array (
"name"    => new xmlrpcval("Godin", "string"),
"city" => new xmlrpcval("Marne la Vallée", "string"),
"zip" => new xmlrpcval("77000", "string"),
"website" => new xmlrpcval("http://www.lapinmoutardepommedauphine.com", "string"),
"lang"   => new xmlrpcval("fr_FR", "string"),
"tz"   => new xmlrpcval("Europe/Paris", "string"),
);

VII - Implementation of the create() method

We will now make another connection to directly call the execute() method on the res.partner object.

Info :

We use the URL /xmlrpc/object for the following methods:

'execute', 'execute_kw', 'exec_workflow'

$client = new xmlrpc_client($server_url . "/xmlrpc/object");
$client->setSSLVerifyPeer(0);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("create", "string"));
$msg->addParam(new xmlrpcval($val, "struct"));
$response = $client->send($msg);

Then simply display the return with:

Return

echo 'Partner created - partner_id = ' . $response->value()->scalarval();

As a reminder, the create() method returns the ID of the record created.

VIII - Entire create() script

xml-rpc-create.php

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
echo '<h2>XML-RPC AVEC OPENERP/ODOO ET PHP</h2>';

include("xmlrpc_lib/xmlrpc.inc.php");
include("xmlrpc_lib/xmlrpcs.inc.php");
$GLOBALS['xmlrpc_internalencoding']='UTF-8';

$user = 'admin';
$password = 'mY5up3rPwd';
$dbname = 'test';

$server_url = 'http://192.168.1.120:8069';
$connexion = new xmlrpc_client($server_url . "/xmlrpc/common");
$connexion->setSSLVerifyPeer(0);

$c_msg = new xmlrpcmsg('login');
$c_msg->addParam(new xmlrpcval($dbname, "string"));
$c_msg->addParam(new xmlrpcval($user, "string"));
$c_msg->addParam(new xmlrpcval($password, "string"));
$c_response = $connexion->send($c_msg);

if ($c_response->errno != 0){
echo  '<p>error : ' . $c_response->faultString() . '</p>';
}
else{

$uid = $c_response->value()->scalarval();

$val = array (
"name"    => new xmlrpcval("Godin Thierry", "string"),
"street"  => new xmlrpcval("Au fond à gauche", "string"),
"city"    => new xmlrpcval("Marne la Vallée", "string"),
"zip"     => new xmlrpcval("77000", "string"),
"website" => new xmlrpcval("http://www.lapinmoutardepommedauphine.com", "string"),
"lang"    => new xmlrpcval("fr_FR", "string"),
"tz"      => new xmlrpcval("Europe/Paris", "string"),
);

$client = new xmlrpc_client($server_url . "/xmlrpc/object");
$client->setSSLVerifyPeer(0);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("create", "string"));
$msg->addParam(new xmlrpcval($val, "struct"));
$response = $client->send($msg);

echo 'Partner created - partner_id = ' . $response->value()->scalarval();
}
?>

IX - search() and read() methods

We saw how to create a record through the create() method, we will now see search() and read() methods.

We use the search() method using a domain filter to retrieve the list of record IDs that we want to read with the read() method.

Indeed, remember, the read() method takes several arguments with an ID (or IDs) of the record(s) to read.

Domain filter

$domain_filter = array (
new xmlrpcval(
array(new xmlrpcval('is_company' , "string"),
new xmlrpcval('!=',"string"),
new xmlrpcval('True',"string")
),"array"
),
);

As seen in the above code, we are looking for all customers who are not companies.

This filter would result in Python for Odoo to:

domain

[('is_company', '!=', True)]

Thus a new connection then the search() method is executed as below:

$client = new xmlrpc_client($server_url . "/xmlrpc/object");
$client->setSSLVerifyPeer(0);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("search", "string"));
$msg->addParam(new xmlrpcval($domain_filter, "array"));
$response = $client->send($msg);

$result = $response->value();
$ids = $result->scalarval();

Then we format the ID to pass to the read() method as below:

Formate Ids

$id_list = array();

for($i = 0; $i < count($ids); $i++){
$id_list[]= new xmlrpcval($ids[$i]->me['int'], 'int');
}

Then we create the list of fields that we want to read:

Field list

$field_list = array(
new xmlrpcval("name", "string"),
new xmlrpcval("email", "string"),
new xmlrpcval("street", "string"),
new xmlrpcval("city", "string"),
new xmlrpcval("zip", "string"),
);

Then, the read() method is executed:

Run read() method

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("read", "string"));
$msg->addParam(new xmlrpcval($id_list, "array"));
$msg->addParam(new xmlrpcval($field_list, "array"));

$resp = $client->send($msg);

if ($resp->faultCode()){
echo $resp->faultString();
}

$result = $resp->value()->scalarval();

Finally, partners are displayed:

Displaying the results

for($i = 0; $i < count($result); $i++){
echo '<h1>' . $result[$i]->me['struct']['name']->me['string'] . '</h1>'
. '<ol>'
. '<li><strong>Email</strong> : ' . $result[$i]->me['struct']['email']->me['string'] . '</li>'
. '<li><strong>Street</strong> : ' . $result[$i]->me['struct']['street']->me['string'] . '</li>'
. '<li><strong>City</strong> : ' . $result[$i]->me['struct']['city']->me['string'] . '</li>'
. '<li><strong>Zip code</strong> : ' . $result[$i]->me['struct']['zip']->me['string'] . '</li>'
. '</ol>'
. '<hr />';
}

X - Statement of the result

If we do a print_r($ result) we get this:

print_r($result)

Array ( [0] => xmlrpcval Object ( [me] => Array ( [struct] => Array ( [city] => xmlrpcval Object ( [me] => Array ( [boolean] => ) [mytype] => 1 [_php_class] => ) [name] => xmlrpcval Object ( [me] => Array ( [string] => Administrator ) [mytype] => 1 [_php_class] => ) [zip] => xmlrpcval Object ( [me] => Array ( [boolean] => ) [mytype] => 1 [_php_class] => ) [email] => xmlrpcval Object ( [me] => Array ( [string] => admin@example.com ) [mytype] => 1 [_php_class] => ) [street] => xmlrpcval Object ( [me] => Array ( [boolean] => ) [mytype] => 1 [_php_class] => ) [id] => xmlrpcval Object ( [me] => Array ( [int] => 3 ) [mytype] => 1 [_php_class] => ) ) ) [mytype] => 3 [_php_class] => ) [1] => xmlrpcval Object ( [me] => Array ( [struct] => Array ( [city] => xmlrpcval Object ( [me] => Array ( [string] => Wavre ) [mytype] => 1 [_php_class] => ) [name] => xmlrpcval Object ( [me] => Array ( [string] => Michel Fletcher ) [mytype] => 1 [_php_class] => ) [zip] => xmlrpcval Object ( [me] => Array ( [string] => 1300 ) [mytype] => 1 [_php_class] => ) [email] => xmlrpcval Object ( [me] => Array ( [string] => m.fletcher@agrolait.com ) [mytype] => 1 [_php_class] => ) [street] => xmlrpcval Object ( [me] => Array ( [string] => 69 rue de Namur ) [mytype] => 1 [_php_class] => ) [id] => xmlrpcval Object ( [me] => Array ( [int] => 31 ) [mytype] => 1 [_php_class] => ) ) ) [mytype] => 3 [_php_class] => ) [2] => xmlrpcval Object ( [me] => Array ( [struct] => Array ( [city] => xmlrpcval Object ( [me] => Array ( [string] => Wavre ) [mytype] => 1 [_php_class] => ) [name] => xmlrpcval Object ( [me] => Array ( [string] => Thomas Passot ) [mytype] => 1 [_php_class] => ) [zip] => xmlrpcval Object ( [me] => Array ( [string] => 1300 ) [mytype] => 1 [_php_class] => ) [email] => xmlrpcval Object ( [me] => Array ( [string] => p.thomas@agrolait.com ) [mytype] => 1 [_php_class] => ) [street] => xmlrpcval Object ( [me] => Array ( [string] => 69 rue de Namur ) [mytype] => 1 [_php_class] => ) [id] => xmlrpcval Object ( [me] => Array ( [int] => 30 ) [mytype] => 1 [_php_class] => ) ) ) [mytype] => 3 [_php_class] => ) [3] => xmlrpcval Object ( [me] => Array ( [struct] => Array ( [city] => xmlrpcval Object ( [me] => Array ( [string] => Taipei ) [mytype] => 1 [_php_class] => ) [name] => xmlrpcval Object ( [me] => Array ( [string] => Joseph Walters ) [mytype] => 1 [_php_class] => ) [zip] => xmlrpcval Object ( [me] => Array ( [string] => 106 ) [mytype] => 1 [_php_class] => ) [email] => xmlrpcval Object ( [me] => Array ( [string] => joseph.walters@asustek.com ) [mytype] => 1 [_php_class] => ) [street] => xmlrpcval Object ( [me] => Array ( [string] => 31 Hong Kong street ) [mytype] => 1 [_php_class] => ) [id] => xmlrpcval Object ( [me] => Array ( [int] => 29 ) [mytype] => 1 [_php_class] => ) ) ) [mytype] => 3 [_php_class] => ) [4] => xmlrpcval Object ( [me] => Array  …....

$result is an array of xmlrpcval() objects.

If we want for example to get the value of the « name » field of the first record returned, we will write this:

// Array ( [0] => xmlrpcval Object ( [me] => Array ( [struct] => Array
// ( [city] => xmlrpcval Object ( [me] => Array ( [boolean] => )
// [mytype] => 1 [_php_class] => ) [name] => xmlrpcval Object (
// [me] => Array ( [string] => Administrator )

echo $result[0]->me['struct']['name']->me['string'] // = Administrator

XI - search() and read() entire script

xml_rpc_search_and_read.php

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php

echo '<h2>XML-RPC AVEC OPENERP/ODOO ET PHP</h2>';

include("xmlrpc_lib/xmlrpc.inc.php");
include("xmlrpc_lib/xmlrpcs.inc.php");
$GLOBALS['xmlrpc_internalencoding']='UTF-8';

$user = 'admin';
$password = 'mY5up3rPwd';
$dbname = 'test';

$server_url = 'http://192.168.1.120:8069';
$connexion = new xmlrpc_client($server_url . "/xmlrpc/common");
$connexion->setSSLVerifyPeer(0);

$c_msg = new xmlrpcmsg('login');
$c_msg->addParam(new xmlrpcval($dbname, "string"));
$c_msg->addParam(new xmlrpcval($user, "string"));
$c_msg->addParam(new xmlrpcval($password, "string"));
$c_response = $connexion->send($c_msg);

if ($c_response->errno != 0){
echo  '<p>error : ' . $c_response->faultString() . '</p>';
}
else{

$uid = $c_response->value()->scalarval();

$domain_filter = array (
new xmlrpcval(
array(new xmlrpcval('is_company' , "string"),
new xmlrpcval('!=',"string"),
new xmlrpcval('True',"string")
),"array"
),
);

$client = new xmlrpc_client($server_url . "/xmlrpc/object");
$client->setSSLVerifyPeer(0);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("search", "string"));
$msg->addParam(new xmlrpcval($domain_filter, "array"));
$response = $client->send($msg);

$result = $response->value();
$ids = $result->scalarval();

$id_list = array();

for($i = 0; $i < count($ids); $i++){
$id_list[]= new xmlrpcval($ids[$i]->me['int'], 'int');
}

$field_list = array(
new xmlrpcval("name", "string"),
new xmlrpcval("email", "string"),
new xmlrpcval("street", "string"),
new xmlrpcval("city", "string"),
new xmlrpcval("zip", "string"),
);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("read", "string"));
$msg->addParam(new xmlrpcval($id_list, "array"));
$msg->addParam(new xmlrpcval($field_list, "array"));

$resp = $client->send($msg);

if ($resp->faultCode()){
echo $resp->faultString();
}

$result = $resp->value()->scalarval();

echo '<h2>Resultat brut de la requête avec print_r($result) :</h2>';
print_r($result);
echo '<hr />';
echo '<h2>Liste des partners qui ne sont pas des sociétés:</h2>';

for($i = 0; $i < count($result); $i++){
echo '<h1>' . $result[$i]->me['struct']['name']->me['string'] . '</h1>'
. '<ol>'
. '<li><strong>Email</strong> : ' . $result[$i]->me['struct']['email']->me['string'] . '</li>'
. '<li><strong>Street</strong> : ' . $result[$i]->me['struct']['street']->me['string'] . '</li>'
. '<li><strong>City</strong> : ' . $result[$i]->me['struct']['city']->me['string'] . '</li>'
. '<li><strong>Zip code</strong> : ' . $result[$i]->me['struct']['zip']->me['string'] . '</li>'
. '</ol>'
. '<hr />';
}

}
?>

XII - search() and unlink() methods

In the same way as before, we will now use the search() method to search for all customers whose name includes the word « godin » (these are the customers that we created earlier in this tutorial) and then we will remove them with unlink() method.

We will rewrite the domain filter like this:

Domain filter

$domain_filter = array (
new xmlrpcval(
array(new xmlrpcval('name' , "string"),
new xmlrpcval('ilike',"string"),
new xmlrpcval('godin',"string")
),"array"
),
);

Then, the search() method is executed:

Run the search() method

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("search", "string"));
$msg->addParam(new xmlrpcval($domain_filter, "array"));
$response = $client->send($msg);

$result = $response->value();
$ids = $result->scalarval();

And finally, we reformate the list of IDs and unlink() method is executed to delete all customers whose names contain « godin »

Run unlink() method

$id_list = array();

for($i = 0; $i < count($ids); $i++){
$id_list[]= new xmlrpcval($ids[$i]->me['int'], 'int');
}

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("unlink", "string"));
$msg->addParam(new xmlrpcval($id_list, "array"));

$resp = $client->send($msg);

if ($resp->faultCode()){
echo $resp->faultString();
}

XIII - search() and unlink() entire script :

xml_rpc_search_and_unlink.php

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php

echo '<h2>XML-RPC AVEC OPENERP/ODOO ET PHP</h2>';

include("xmlrpc_lib/xmlrpc.inc.php");
include("xmlrpc_lib/xmlrpcs.inc.php");
$GLOBALS['xmlrpc_internalencoding']='UTF-8';

$user = 'admin';
$password = 'mY5up3rPwd';
$dbname = 'test';

$server_url = 'http://192.168.1.120:8069';
$connexion = new xmlrpc_client($server_url . "/xmlrpc/common");
$connexion->setSSLVerifyPeer(0);

$c_msg = new xmlrpcmsg('login');
$c_msg->addParam(new xmlrpcval($dbname, "string"));
$c_msg->addParam(new xmlrpcval($user, "string"));
$c_msg->addParam(new xmlrpcval($password, "string"));
$c_response = $connexion->send($c_msg);

if ($c_response->errno != 0){
echo  '<p>error : ' . $c_response->faultString() . '</p>';
}
else{

$uid = $c_response->value()->scalarval();

$domain_filter = array (
new xmlrpcval(
array(new xmlrpcval('name' , "string"),
new xmlrpcval('ilike',"string"),
new xmlrpcval('godin',"string")
),"array"
),
);

$client = new xmlrpc_client($server_url . "/xmlrpc/object");
$client->setSSLVerifyPeer(0);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("search", "string"));
$msg->addParam(new xmlrpcval($domain_filter, "array"));
$response = $client->send($msg);

$result = $response->value();
$ids = $result->scalarval();

$id_list = array();

for($i = 0; $i < count($ids); $i++){
$id_list[]= new xmlrpcval($ids[$i]->me['int'], 'int');
}

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("unlink", "string"));
$msg->addParam(new xmlrpcval($id_list, "array"));

$resp = $client->send($msg);

if ($resp->faultCode()){
echo $resp->faultString();
}

echo '<h2>Liste des ids des partners qui ont été supprimés:</h2>';

for($i = 0; $i < count($id_list); $i++){
echo '<li><strong>ID</strong> : ' . $id_list[$i]->me['int'] . '</li>';
}

}
?>

Obviously, we do not have to use the search() method if we know the IDs of the records to be read/modify/ delete.

XIV - Write() method

Now the write() method.

In the example below, I do not use the search() method, it is assumed that I know the ID of the record I want to edit.

xml_rpc_write.php

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php

echo '<h2>XML-RPC AVEC OPENERP/ODOO ET PHP</h2>';

include("xmlrpc_lib/xmlrpc.inc.php");
include("xmlrpc_lib/xmlrpcs.inc.php");
$GLOBALS['xmlrpc_internalencoding']='UTF-8';

$user = 'admin';
$password = 'mY5up3rPwd';
$dbname = 'test';

$server_url = 'http://192.168.1.120:8069';
$connexion = new xmlrpc_client($server_url . "/xmlrpc/common");
$connexion->setSSLVerifyPeer(0);

$c_msg = new xmlrpcmsg('login');
$c_msg->addParam(new xmlrpcval($dbname, "string"));
$c_msg->addParam(new xmlrpcval($user, "string"));
$c_msg->addParam(new xmlrpcval($password, "string"));
$c_response = $connexion->send($c_msg);

if ($c_response->errno != 0){
echo  '<p>error : ' . $c_response->faultString() . '</p>';
}
else{

$uid = $c_response->value()->scalarval();

$id_list = array();
$id_list[]= new xmlrpcval(89, 'int');

$values = array (
'street'=>new xmlrpcval('Rue de la gare' , "string"),
'city'=>new xmlrpcval('Fontainebleau',"string"),
'zip'=>new xmlrpcval('77120',"string")
);

$client = new xmlrpc_client($server_url . "/xmlrpc/object");
$client->setSSLVerifyPeer(0);

$msg = new xmlrpcmsg('execute');
$msg->addParam(new xmlrpcval($dbname, "string"));
$msg->addParam(new xmlrpcval($uid, "int"));
$msg->addParam(new xmlrpcval($password, "string"));
$msg->addParam(new xmlrpcval("res.partner", "string"));
$msg->addParam(new xmlrpcval("write", "string"));
$msg->addParam(new xmlrpcval($id_list, "array"));
$msg->addParam(new xmlrpcval($values, "struct"));
$response = $client->send($msg);

if ($response->faultCode()){
echo $response->faultString();
}

echo '<h2>Mise à jour effectuée</h2>';

}
?>

XV - And after ???

Well after, you'll just call any method of any module, making sure to pass the expected parameters.

When you call a method via XML-RPC, they are executed in the same way as when they are called from the Odoo interface. Thus a method may fail if the user does not have sufficient rights.

Here for the tutorial, I used the « admin » user, but for safety reasons, I recommend that you create a specific user to whom you assign only sufficient rights to execute the methods you need and anything else.

XVI - Download

Download the scripts above: odoo_xmlrpc_php_files.zip

XVII - Documentation

You can find documentation on the official site.

Odoo: XML-RPC Web services

This documentation appears to have been written for OpenERP 6.2 but it works with version 7. I have not yet tested with Odoo version 8.

XVIII - Thanks

Thanks to OpenERP SA for their software Odoo.