diff options
| author | Antony Lesuisse <al@openerp.com> | 2017-10-04 20:05:05 +0200 |
|---|---|---|
| committer | Antony Lesuisse <al@openerp.com> | 2017-10-04 20:22:22 +0200 |
| commit | 6b22476e20fb7eade959194bfabd94d353e2d5ff (patch) | |
| tree | fbad12338bed7d4f4b38b017cd746878f897b81c /doc/api_integration.rst | |
| parent | ea51b6b06f33fa97ace9c55bb86fceaeb60bb18a (diff) | |
[ADD] iap: In app purchase
IAP allow app publishers to charge for ongoing services. In that context, Odoo
acts mostly as a payment platform between the service user (client) and the service
provider (Odoo App developer).
Diffstat (limited to 'doc/api_integration.rst')
| -rw-r--r-- | doc/api_integration.rst | 1385 |
1 files changed, 0 insertions, 1385 deletions
diff --git a/doc/api_integration.rst b/doc/api_integration.rst deleted file mode 100644 index 612e91ed854..00000000000 --- a/doc/api_integration.rst +++ /dev/null @@ -1,1385 +0,0 @@ -:banner: banners/web_service_api.jpg -:types: api - - -:code-column: - -=============== -Web Service API -=============== - -Odoo is usually extended internally via modules, but many of its features and -all of its data are also available from the outside for external analysis or -integration with various tools. Part of the :ref:`reference/orm/model` API is -easily available over XML-RPC_ and accessible from a variety of languages. - -.. Odoo XML-RPC idiosyncracies: - * uses multiple endpoint and a nested call syntax instead of a - "hierarchical" server structure (e.g. ``odoo.res.partner.read()``) - * uses its own own manual auth system instead of basic auth or sessions - (basic is directly supported the Python and Ruby stdlibs as well as - ws-xmlrpc, not sure about ripcord) - * own auth is inconvenient as (uid, password) have to be explicitly passed - into every call. Session would allow db to be stored as well - These issues are especially visible in Java, somewhat less so in PHP - -Connection -========== - -.. kinda gross because it duplicates existing bits - -.. only:: html - - .. rst-class:: setupcode hidden - - .. code-block:: python - - import xmlrpclib - info = xmlrpclib.ServerProxy('https://demo.odoo.com/start').start() - url, db, username, password = \ - info['host'], info['database'], info['user'], info['password'] - common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url)) - uid = common.authenticate(db, username, password, {}) - models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url)) - - .. code-block:: ruby - - require "xmlrpc/client" - info = XMLRPC::Client.new2('https://demo.odoo.com/start').call('start') - url, db, username, password = \ - info['host'], info['database'], info['user'], info['password'] - common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common") - uid = common.call('authenticate', db, username, password, {}) - models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy - - .. code-block:: php - - require_once('ripcord.php'); - $info = ripcord::client('https://demo.odoo.com/start')->start(); - list($url, $db, $username, $password) = - array($info['host'], $info['database'], $info['user'], $info['password']); - $common = ripcord::client("$url/xmlrpc/2/common"); - $uid = $common->authenticate($db, $username, $password, array()); - $models = ripcord::client("$url/xmlrpc/2/object"); - - .. code-block:: java - - final XmlRpcClient client = new XmlRpcClient(); - final XmlRpcClientConfigImpl start_config = new XmlRpcClientConfigImpl(); - start_config.setServerURL(new URL("https://demo.odoo.com/start")); - final Map<String, String> info = (Map<String, String>)client.execute( - start_config, "start", emptyList()); - - final String url = info.get("host"), - db = info.get("database"), - username = info.get("user"), - password = info.get("password"); - - final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl(); - common_config.setServerURL(new URL(String.format("%s/xmlrpc/2/common", url))); - - int uid = (int)client.execute( - common_config, "authenticate", Arrays.asList( - db, username, password, emptyMap())); - - final XmlRpcClient models = new XmlRpcClient() {{ - setConfig(new XmlRpcClientConfigImpl() {{ - setServerURL(new URL(String.format("%s/xmlrpc/2/object", url))); - }}); - }}; - -Configuration -------------- - -If you already have an Odoo server installed, you can just use its -parameters - -.. warning:: - - For Odoo Online instances (<domain>.odoo.com), users are created without a - *local* password (as a person you are logged in via the Odoo Online - authentication system, not by the instance itself). To use XML-RPC on Odoo - Online instances, you will need to set a password on the user account you - want to use: - - * Log in your instance with an administrator account - * Go to :menuselection:`Settings --> Users --> Users` - * Click on the user you want to use for XML-RPC access - * Click the :guilabel:`Change Password` button - * Set a :guilabel:`New Password` value then click - :guilabel:`Change Password`. - - The *server url* is the instance's domain (e.g. - *https://mycompany.odoo.com*), the *database name* is the name of the - instance (e.g. *mycompany*). The *username* is the configured user's login - as shown by the *Change Password* screen. - -.. rst-class:: setup doc-aside - -.. switcher:: - - .. code-block:: python - - url = <insert server URL> - db = <insert database name> - username = 'admin' - password = <insert password for your admin user (default: admin)> - - .. code-block:: ruby - - url = <insert server URL> - db = <insert database name> - username = "admin" - password = <insert password for your admin user (default: admin)> - - .. code-block:: php - - $url = <insert server URL>; - $db = <insert database name>; - $username = "admin"; - $password = <insert password for your admin user (default: admin)>; - - .. code-block:: java - - final String url = <insert server URL>, - db = <insert database name>, - username = "admin", - password = <insert password for your admin user (default: admin)>; - -demo -'''' - -To make exploration simpler, you can also ask https://demo.odoo.com for a test -database: - -.. rst-class:: setup doc-aside - -.. switcher:: - - .. code-block:: python - - import xmlrpclib - info = xmlrpclib.ServerProxy('https://demo.odoo.com/start').start() - url, db, username, password = \ - info['host'], info['database'], info['user'], info['password'] - - .. code-block:: ruby - - require "xmlrpc/client" - info = XMLRPC::Client.new2('https://demo.odoo.com/start').call('start') - url, db, username, password = \ - info['host'], info['database'], info['user'], info['password'] - - .. case:: PHP - - .. code-block:: php - - require_once('ripcord.php'); - $info = ripcord::client('https://demo.odoo.com/start')->start(); - list($url, $db, $username, $password) = - array($info['host'], $info['database'], $info['user'], $info['password']); - - .. note:: - - These examples use the `Ripcord <https://code.google.com/p/ripcord/>`_ - library, which provides a simple XML-RPC API. Ripcord requires that - `XML-RPC support be enabled - <http://php.net/manual/en/xmlrpc.installation.php>`_ in your PHP - installation. - - Since calls are performed over - `HTTPS <http://en.wikipedia.org/wiki/HTTP_Secure>`_, it also requires that - the `OpenSSL extension - <http://php.net/manual/en/openssl.installation.php>`_ be enabled. - - .. case:: Java - - .. code-block:: java - - final XmlRpcClient client = new XmlRpcClient(); - - final XmlRpcClientConfigImpl start_config = new XmlRpcClientConfigImpl(); - start_config.setServerURL(new URL("https://demo.odoo.com/start")); - final Map<String, String> info = (Map<String, String>)client.execute( - start_config, "start", emptyList()); - - final String url = info.get("host"), - db = info.get("database"), - username = info.get("user"), - password = info.get("password"); - - .. note:: - - These examples use the `Apache XML-RPC library - <https://ws.apache.org/xmlrpc/>`_ - - The examples do not include imports as these imports couldn't be - pasted in the code. - -Logging in ----------- - -Odoo requires users of the API to be authenticated before they can query most -data. - -The ``xmlrpc/2/common`` endpoint provides meta-calls which don't require -authentication, such as the authentication itself or fetching version -information. To verify if the connection information is correct before trying -to authenticate, the simplest call is to ask for the server's version. The -authentication itself is done through the ``authenticate`` function and -returns a user identifier (``uid``) used in authenticated calls instead of -the login. - -.. rst-class:: setup doc-aside - -.. switcher:: - - .. code-block:: python - - common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url)) - common.version() - - .. code-block:: ruby - - common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common") - common.call('version') - - .. code-block:: php - - $common = ripcord::client("$url/xmlrpc/2/common"); - $common->version(); - - .. code-block:: java - - final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl(); - common_config.setServerURL( - new URL(String.format("%s/xmlrpc/2/common", url))); - client.execute(common_config, "version", emptyList()); - -.. rst-class:: doc-aside - -.. code-block:: json - - { - "server_version": "8.0", - "server_version_info": [8, 0, 0, "final", 0], - "server_serie": "8.0", - "protocol_version": 1, - } - -.. rst-class:: setup doc-aside - -.. switcher:: - - .. code-block:: python - - uid = common.authenticate(db, username, password, {}) - - .. code-block:: ruby - - uid = common.call('authenticate', db, username, password, {}) - - .. code-block:: php - - $uid = $common->authenticate($db, $username, $password, array()); - - .. code-block:: java - - int uid = (int)client.execute( - common_config, "authenticate", asList( - db, username, password, emptyMap())); - -Calling methods -=============== - -The second endpoint is ``xmlrpc/2/object``, is used to call methods of odoo -models via the ``execute_kw`` RPC function. - -Each call to ``execute_kw`` takes the following parameters: - -* the database to use, a string -* the user id (retrieved through ``authenticate``), an integer -* the user's password, a string -* the model name, a string -* the method name, a string -* an array/list of parameters passed by position -* a mapping/dict of parameters to pass by keyword (optional) - -.. container:: doc-aside - - For instance to see if we can read the ``res.partner`` model we can call - ``check_access_rights`` with ``operation`` passed by position and - ``raise_exception`` passed by keyword (in order to get a true/false result - rather than true/error): - - .. rst-class:: setup - - .. switcher:: - - .. code-block:: python - - models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url)) - models.execute_kw(db, uid, password, - 'res.partner', 'check_access_rights', - ['read'], {'raise_exception': False}) - - .. code-block:: ruby - - models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy - models.execute_kw(db, uid, password, - 'res.partner', 'check_access_rights', - ['read'], {raise_exception: false}) - - .. code-block:: php - - $models = ripcord::client("$url/xmlrpc/2/object"); - $models->execute_kw($db, $uid, $password, - 'res.partner', 'check_access_rights', - array('read'), array('raise_exception' => false)); - - .. code-block:: java - - final XmlRpcClient models = new XmlRpcClient() {{ - setConfig(new XmlRpcClientConfigImpl() {{ - setServerURL(new URL(String.format("%s/xmlrpc/2/object", url))); - }}); - }}; - models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "check_access_rights", - asList("read"), - new HashMap() {{ put("raise_exception", false); }} - )); - - .. code-block:: json - - true - - .. todo:: this should be runnable and checked - -List records ------------- - -Records can be listed and filtered via :meth:`~odoo.models.Model.search`. - -:meth:`~odoo.models.Model.search` takes a mandatory -:ref:`domain <reference/orm/domains>` filter (possibly empty), and returns the -database identifiers of all records matching the filter. To list customer -companies for instance: - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, - 'res.partner', 'search', - [[['is_company', '=', True], ['customer', '=', True]]]) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, - 'res.partner', 'search', - [[['is_company', '=', true], ['customer', '=', true]]]) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'search', array( - array(array('is_company', '=', true), - array('customer', '=', true)))); - - .. code-block:: java - - asList((Object[])models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "search", - asList(asList( - asList("is_company", "=", true), - asList("customer", "=", true))) - ))); - - .. code-block:: json - - [7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74] - -Pagination -'''''''''' - -By default a search will return the ids of all records matching the -condition, which may be a huge number. ``offset`` and ``limit`` parameters are -available to only retrieve a subset of all matched records. - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, - 'res.partner', 'search', - [[['is_company', '=', True], ['customer', '=', True]]], - {'offset': 10, 'limit': 5}) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, - 'res.partner', 'search', - [[['is_company', '=', true], ['customer', '=', true]]], - {offset: 10, limit: 5}) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'search', - array(array(array('is_company', '=', true), - array('customer', '=', true))), - array('offset'=>10, 'limit'=>5)); - - .. code-block:: java - - asList((Object[])models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "search", - asList(asList( - asList("is_company", "=", true), - asList("customer", "=", true))), - new HashMap() {{ put("offset", 10); put("limit", 5); }} - ))); - - .. code-block:: json - - [13, 20, 30, 22, 29] - -Count records -------------- - -Rather than retrieve a possibly gigantic list of records and count them, -:meth:`~odoo.models.Model.search_count` can be used to retrieve -only the number of records matching the query. It takes the same -:ref:`domain <reference/orm/domains>` filter as -:meth:`~odoo.models.Model.search` and no other parameter. - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, - 'res.partner', 'search_count', - [[['is_company', '=', True], ['customer', '=', True]]]) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, - 'res.partner', 'search_count', - [[['is_company', '=', true], ['customer', '=', true]]]) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'search_count', - array(array(array('is_company', '=', true), - array('customer', '=', true)))); - - .. code-block:: java - - (Integer)models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "search_count", - asList(asList( - asList("is_company", "=", true), - asList("customer", "=", true))) - )); - - .. code-block:: json - - 19 - -.. warning:: - - calling ``search`` then ``search_count`` (or the other way around) may not - yield coherent results if other users are using the server: stored data - could have changed between the calls - -Read records ------------- - -Record data is accessible via the :meth:`~odoo.models.Model.read` method, -which takes a list of ids (as returned by -:meth:`~odoo.models.Model.search`) and optionally a list of fields to -fetch. By default, it will fetch all the fields the current user can read, -which tends to be a huge amount. - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - ids = models.execute_kw(db, uid, password, - 'res.partner', 'search', - [[['is_company', '=', True], ['customer', '=', True]]], - {'limit': 1}) - [record] = models.execute_kw(db, uid, password, - 'res.partner', 'read', [ids]) - # count the number of fields fetched by default - len(record) - - .. code-block:: ruby - - ids = models.execute_kw(db, uid, password, - 'res.partner', 'search', - [[['is_company', '=', true], ['customer', '=', true]]], - {limit: 1}) - record = models.execute_kw(db, uid, password, - 'res.partner', 'read', [ids]).first - # count the number of fields fetched by default - record.length - - .. code-block:: php - - $ids = $models->execute_kw($db, $uid, $password, - 'res.partner', 'search', - array(array(array('is_company', '=', true), - array('customer', '=', true))), - array('limit'=>1)); - $records = $models->execute_kw($db, $uid, $password, - 'res.partner', 'read', array($ids)); - // count the number of fields fetched by default - count($records[0]); - - .. code-block:: java - - final List ids = asList((Object[])models.execute( - "execute_kw", asList( - db, uid, password, - "res.partner", "search", - asList(asList( - asList("is_company", "=", true), - asList("customer", "=", true))), - new HashMap() {{ put("limit", 1); }}))); - final Map record = (Map)((Object[])models.execute( - "execute_kw", asList( - db, uid, password, - "res.partner", "read", - asList(ids) - ) - ))[0]; - // count the number of fields fetched by default - record.size(); - - .. code-block:: json - - 121 - -Conversedly, picking only three fields deemed interesting. - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, - 'res.partner', 'read', - [ids], {'fields': ['name', 'country_id', 'comment']}) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, - 'res.partner', 'read', - [ids], {fields: %w(name country_id comment)}) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'read', - array($ids), - array('fields'=>array('name', 'country_id', 'comment'))); - - .. code-block:: java - - asList((Object[])models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "read", - asList(ids), - new HashMap() {{ - put("fields", asList("name", "country_id", "comment")); - }} - ))); - - .. code-block:: json - - [{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}] - -.. note:: even if the ``id`` field is not requested, it is always returned - -Listing record fields ---------------------- - -:meth:`~odoo.models.Model.fields_get` can be used to inspect -a model's fields and check which ones seem to be of interest. - -Because it returns a large amount of meta-information (it is also used by client -programs) it should be filtered before printing, the most interesting items -for a human user are ``string`` (the field's label), ``help`` (a help text if -available) and ``type`` (to know which values to expect, or to send when -updating a record): - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw( - db, uid, password, 'res.partner', 'fields_get', - [], {'attributes': ['string', 'help', 'type']}) - - .. code-block:: ruby - - models.execute_kw( - db, uid, password, 'res.partner', 'fields_get', - [], {attributes: %w(string help type)}) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'fields_get', - array(), array('attributes' => array('string', 'help', 'type'))); - - .. code-block:: java - - (Map<String, Map<String, Object>>)models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "fields_get", - emptyList(), - new HashMap() {{ - put("attributes", asList("string", "help", "type")); - }} - )); - - .. code-block:: json - - { - "ean13": { - "type": "char", - "help": "BarCode", - "string": "EAN13" - }, - "property_account_position_id": { - "type": "many2one", - "help": "The fiscal position will determine taxes and accounts used for the partner.", - "string": "Fiscal Position" - }, - "signup_valid": { - "type": "boolean", - "help": "", - "string": "Signup Token is Valid" - }, - "date_localization": { - "type": "date", - "help": "", - "string": "Geo Localization Date" - }, - "ref_company_ids": { - "type": "one2many", - "help": "", - "string": "Companies that refers to partner" - }, - "sale_order_count": { - "type": "integer", - "help": "", - "string": "# of Sales Order" - }, - "purchase_order_count": { - "type": "integer", - "help": "", - "string": "# of Purchase Order" - }, - -Search and read ---------------- - -Because it is a very common task, Odoo provides a -:meth:`~odoo.models.Model.search_read` shortcut which as its name suggests is -equivalent to a :meth:`~odoo.models.Model.search` followed by a -:meth:`~odoo.models.Model.read`, but avoids having to perform two requests -and keep ids around. - -Its arguments are similar to :meth:`~odoo.models.Model.search`'s, but it -can also take a list of ``fields`` (like :meth:`~odoo.models.Model.read`, -if that list is not provided it will fetch all fields of matched records): - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, - 'res.partner', 'search_read', - [[['is_company', '=', True], ['customer', '=', True]]], - {'fields': ['name', 'country_id', 'comment'], 'limit': 5}) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, - 'res.partner', 'search_read', - [[['is_company', '=', true], ['customer', '=', true]]], - {fields: %w(name country_id comment), limit: 5}) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'search_read', - array(array(array('is_company', '=', true), - array('customer', '=', true))), - array('fields'=>array('name', 'country_id', 'comment'), 'limit'=>5)); - - .. code-block:: java - - asList((Object[])models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "search_read", - asList(asList( - asList("is_company", "=", true), - asList("customer", "=", true))), - new HashMap() {{ - put("fields", asList("name", "country_id", "comment")); - put("limit", 5); - }} - ))); - - .. code-block:: json - - [ - { - "comment": false, - "country_id": [ 21, "Belgium" ], - "id": 7, - "name": "Agrolait" - }, - { - "comment": false, - "country_id": [ 76, "France" ], - "id": 18, - "name": "Axelor" - }, - { - "comment": false, - "country_id": [ 233, "United Kingdom" ], - "id": 12, - "name": "Bank Wealthy and sons" - }, - { - "comment": false, - "country_id": [ 105, "India" ], - "id": 14, - "name": "Best Designers" - }, - { - "comment": false, - "country_id": [ 76, "France" ], - "id": 17, - "name": "Camptocamp" - } - ] - - -Create records --------------- - -Records of a model are created using :meth:`~odoo.models.Model.create`. The -method will create a single record and return its database identifier. - -:meth:`~odoo.models.Model.create` takes a mapping of fields to values, used -to initialize the record. For any field which has a default value and is not -set through the mapping argument, the default value will be used. - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{ - 'name': "New Partner", - }]) - - .. code-block:: ruby - - id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{ - name: "New Partner", - }]) - - .. code-block:: php - - $id = $models->execute_kw($db, $uid, $password, - 'res.partner', 'create', - array(array('name'=>"New Partner"))); - - .. code-block:: java - - final Integer id = (Integer)models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "create", - asList(new HashMap() {{ put("name", "New Partner"); }}) - )); - - .. code-block:: json - - 78 - -.. warning:: - - while most value types are what would be expected (integer for - :class:`~odoo.fields.Integer`, string for :class:`~odoo.fields.Char` - or :class:`~odoo.fields.Text`), - - * :class:`~odoo.fields.Date`, :class:`~odoo.fields.Datetime` and - :class:`~odoo.fields.Binary` fields use string values - * :class:`~odoo.fields.One2many` and :class:`~odoo.fields.Many2many` - use a special command protocol detailed in :meth:`the documentation to - the write method <odoo.models.Model.write>`. - -Update records --------------- - -Records can be updated using :meth:`~odoo.models.Model.write`, it takes -a list of records to update and a mapping of updated fields to values similar -to :meth:`~odoo.models.Model.create`. - -Multiple records can be updated simultanously, but they will all get the same -values for the fields being set. It is not currently possible to perform -"computed" updates (where the value being set depends on an existing value of -a record). - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], { - 'name': "Newer partner" - }]) - # get record name after having changed it - models.execute_kw(db, uid, password, 'res.partner', 'name_get', [[id]]) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], { - name: "Newer partner" - }]) - # get record name after having changed it - models.execute_kw(db, uid, password, 'res.partner', 'name_get', [[id]]) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, 'res.partner', 'write', - array(array($id), array('name'=>"Newer partner"))); - // get record name after having changed it - $models->execute_kw($db, $uid, $password, - 'res.partner', 'name_get', array(array($id))); - - .. code-block:: java - - models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "write", - asList( - asList(id), - new HashMap() {{ put("name", "Newer Partner"); }} - ) - )); - // get record name after having changed it - asList((Object[])models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "name_get", - asList(asList(id)) - ))); - - .. code-block:: json - - [[78, "Newer partner"]] - -Delete records --------------- - -Records can be deleted in bulk by providing their ids to -:meth:`~odoo.models.Model.unlink`. - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]]) - # check if the deleted record is still in the database - models.execute_kw(db, uid, password, - 'res.partner', 'search', [[['id', '=', id]]]) - - .. code-block:: ruby - - models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]]) - # check if the deleted record is still in the database - models.execute_kw(db, uid, password, - 'res.partner', 'search', [[['id', '=', id]]]) - - .. code-block:: php - - $models->execute_kw($db, $uid, $password, - 'res.partner', 'unlink', - array(array($id))); - // check if the deleted record is still in the database - $models->execute_kw($db, $uid, $password, - 'res.partner', 'search', - array(array(array('id', '=', $id)))); - - .. code-block:: java - - models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "unlink", - asList(asList(id)))); - // check if the deleted record is still in the database - asList((Object[])models.execute("execute_kw", asList( - db, uid, password, - "res.partner", "search", - asList(asList(asList("id", "=", 78))) - ))); - - .. code-block:: json - - [] - -Inspection and introspection ----------------------------- - -.. todo:: ``get_external_id`` is kinda crap and may not return an id: it just - gets a random existing xid but won't generate one if there is no - xid currently associated with the record. And operating with xids - isn't exactly fun in RPC. - -While we previously used :meth:`~odoo.models.Model.fields_get` to query a -model and have been using an arbitrary model from the start, Odoo stores -most model metadata inside a few meta-models which allow both querying the -system and altering models and fields (with some limitations) on the fly over -XML-RPC. - -.. _reference/webservice/inspection/models: - -``ir.model`` -'''''''''''' - -Provides information about Odoo models via its various fields - -``name`` - a human-readable description of the model -``model`` - the name of each model in the system -``state`` - whether the model was generated in Python code (``base``) or by creating - an ``ir.model`` record (``manual``) -``field_id`` - list of the model's fields through a :class:`~odoo.fields.One2many` to - :ref:`reference/webservice/inspection/fields` -``view_ids`` - :class:`~odoo.fields.One2many` to the :ref:`reference/views` defined - for the model -``access_ids`` - :class:`~odoo.fields.One2many` relation to the - :ref:`reference/security/acl` set on the model - -``ir.model`` can be used to - -* query the system for installed models (as a precondition to operations - on the model or to explore the system's content) -* get information about a specific model (generally by listing the fields - associated with it) -* create new models dynamically over RPC - -.. warning:: - - * "custom" model names must start with ``x_`` - * the ``state`` must be provided and ``manual``, otherwise the model will - not be loaded - * it is not possible to add new *methods* to a custom model, only fields - -.. container:: doc-aside - - a custom model will initially contain only the "built-in" fields available - on all models: - - .. switcher:: - - .. code-block:: python - - models.execute_kw(db, uid, password, 'ir.model', 'create', [{ - 'name': "Custom Model", - 'model': "x_custom_model", - 'state': 'manual', - }]) - models.execute_kw( - db, uid, password, 'x_custom_model', 'fields_get', - [], {'attributes': ['string', 'help', 'type']}) - - .. code-block:: php - - $models->execute_kw( - $db, $uid, $password, - 'ir.model', 'create', array(array( - 'name' => "Custom Model", - 'model' => 'x_custom_model', - 'state' => 'manual' - )) - ); - $models->execute_kw( - $db, $uid, $password, - 'x_custom_model', 'fields_get', - array(), - array('attributes' => array('string', 'help', 'type')) - ); - - .. code-block:: ruby - - models.execute_kw( - db, uid, password, - 'ir.model', 'create', [{ - name: "Custom Model", - model: 'x_custom_model', - state: 'manual' - }]) - fields = models.execute_kw( - db, uid, password, 'x_custom_model', 'fields_get', - [], {attributes: %w(string help type)}) - - .. code-block:: java - - models.execute( - "execute_kw", asList( - db, uid, password, - "ir.model", "create", - asList(new HashMap<String, Object>() {{ - put("name", "Custom Model"); - put("model", "x_custom_model"); - put("state", "manual"); - }}) - )); - final Object fields = models.execute( - "execute_kw", asList( - db, uid, password, - "x_custom_model", "fields_get", - emptyList(), - new HashMap<String, Object> () {{ - put("attributes", asList( - "string", - "help", - "type")); - }} - )); - - .. code-block:: json - - { - "create_uid": { - "type": "many2one", - "string": "Created by" - }, - "create_date": { - "type": "datetime", - "string": "Created on" - }, - "__last_update": { - "type": "datetime", - "string": "Last Modified on" - }, - "write_uid": { - "type": "many2one", - "string": "Last Updated by" - }, - "write_date": { - "type": "datetime", - "string": "Last Updated on" - }, - "display_name": { - "type": "char", - "string": "Display Name" - }, - "id": { - "type": "integer", - "string": "Id" - } - } - -.. _reference/webservice/inspection/fields: - -``ir.model.fields`` -''''''''''''''''''' - -Provides information about the fields of Odoo models and allows adding -custom fields without using Python code - -``model_id`` - :class:`~odoo.fields.Many2one` to - :ref:`reference/webservice/inspection/models` to which the field belongs -``name`` - the field's technical name (used in ``read`` or ``write``) -``field_description`` - the field's user-readable label (e.g. ``string`` in ``fields_get``) -``ttype`` - the :ref:`type <reference/orm/fields>` of field to create -``state`` - whether the field was created via Python code (``base``) or via - ``ir.model.fields`` (``manual``) -``required``, ``readonly``, ``translate`` - enables the corresponding flag on the field -``groups`` - :ref:`field-level access control <reference/security/fields>`, a - :class:`~odoo.fields.Many2many` to ``res.groups`` -``selection``, ``size``, ``on_delete``, ``relation``, ``relation_field``, ``domain`` - type-specific properties and customizations, see :ref:`the fields - documentation <reference/orm/fields>` for details - -Like custom models, only new fields created with ``state="manual"`` are -activated as actual fields on the model. - -.. warning:: computed fields can not be added via ``ir.model.fields``, some - field meta-information (defaults, onchange) can not be set either - -.. todo:: maybe new-API fields could store constant ``default`` in a new - column, maybe JSON-encoded? - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - id = models.execute_kw(db, uid, password, 'ir.model', 'create', [{ - 'name': "Custom Model", - 'model': "x_custom", - 'state': 'manual', - }]) - models.execute_kw( - db, uid, password, - 'ir.model.fields', 'create', [{ - 'model_id': id, - 'name': 'x_name', - 'ttype': 'char', - 'state': 'manual', - 'required': True, - }]) - record_id = models.execute_kw( - db, uid, password, - 'x_custom', 'create', [{ - 'x_name': "test record", - }]) - models.execute_kw(db, uid, password, 'x_custom', 'read', [[record_id]]) - - .. code-block:: php - - $id = $models->execute_kw( - $db, $uid, $password, - 'ir.model', 'create', array(array( - 'name' => "Custom Model", - 'model' => 'x_custom', - 'state' => 'manual' - )) - ); - $models->execute_kw( - $db, $uid, $password, - 'ir.model.fields', 'create', array(array( - 'model_id' => $id, - 'name' => 'x_name', - 'ttype' => 'char', - 'state' => 'manual', - 'required' => true - )) - ); - $record_id = $models->execute_kw( - $db, $uid, $password, - 'x_custom', 'create', array(array( - 'x_name' => "test record" - )) - ); - $models->execute_kw( - $db, $uid, $password, - 'x_custom', 'read', - array(array($record_id))); - - .. code-block:: ruby - - id = models.execute_kw( - db, uid, password, - 'ir.model', 'create', [{ - name: "Custom Model", - model: "x_custom", - state: 'manual' - }]) - models.execute_kw( - db, uid, password, - 'ir.model.fields', 'create', [{ - model_id: id, - name: "x_name", - ttype: "char", - state: "manual", - required: true - }]) - record_id = models.execute_kw( - db, uid, password, - 'x_custom', 'create', [{ - x_name: "test record" - }]) - models.execute_kw( - db, uid, password, - 'x_custom', 'read', [[record_id]]) - - .. code-block:: java - - final Integer id = (Integer)models.execute( - "execute_kw", asList( - db, uid, password, - "ir.model", "create", - asList(new HashMap<String, Object>() {{ - put("name", "Custom Model"); - put("model", "x_custom"); - put("state", "manual"); - }}) - )); - models.execute( - "execute_kw", asList( - db, uid, password, - "ir.model.fields", "create", - asList(new HashMap<String, Object>() {{ - put("model_id", id); - put("name", "x_name"); - put("ttype", "char"); - put("state", "manual"); - put("required", true); - }}) - )); - final Integer record_id = (Integer)models.execute( - "execute_kw", asList( - db, uid, password, - "x_custom", "create", - asList(new HashMap<String, Object>() {{ - put("x_name", "test record"); - }}) - )); - - client.execute( - "execute_kw", asList( - db, uid, password, - "x_custom", "read", - asList(asList(record_id)) - )); - - .. code-block:: json - - [ - { - "create_uid": [1, "Administrator"], - "x_name": "test record", - "__last_update": "2014-11-12 16:32:13", - "write_uid": [1, "Administrator"], - "write_date": "2014-11-12 16:32:13", - "create_date": "2014-11-12 16:32:13", - "id": 1, - "display_name": "test record" - } - ] - -Report printing ---------------- - -Available reports can be listed by searching the ``ir.actions.report`` -model, fields of interest being - -``model`` - the model on which the report applies, can be used to look for available - reports on a specific model -``name`` - human-readable report name -``report_name`` - the technical name of the report, used to print it - -Reports can be printed over RPC with the following information: - -* the name of the report (``report_name``) -* the ids of the records to include in the report - -.. container:: doc-aside - - .. switcher:: - - .. code-block:: python - - invoice_ids = models.execute_kw( - db, uid, password, 'account.invoice', 'search', - [[('type', '=', 'out_invoice'), ('state', '=', 'open')]]) - report = xmlrpclib.ServerProxy('{}/xmlrpc/2/report'.format(url)) - result = report.render_report( - db, uid, password, 'account.report_invoice', invoice_ids) - report_data = result['result'].decode('base64') - - .. code-block:: php - - $invoice_ids = $models->execute_kw( - $db, $uid, $password, - 'account.invoice', 'search', - array(array(array('type', '=', 'out_invoice'), - array('state', '=', 'open')))); - $report = ripcord::client("$url/xmlrpc/2/report"); - $result = $report->render_report( - $db, $uid, $password, - 'account.report_invoice', $invoice_ids); - $report_data = base64_decode($result['result']); - - .. code-block:: ruby - - require 'base64' - invoice_ids = models.execute_kw( - db, uid, password, - 'account.invoice', 'search', - [[['type', '=', 'out_invoice'], ['state', '=', 'open']]]) - report = XMLRPC::Client.new2("#{url}/xmlrpc/2/report").proxy - result = report.render_report( - db, uid, password, - 'account.report_invoice', invoice_ids) - report_data = Base64.decode64(result['result']) - - .. code-block:: java - - final Object[] invoice_ids = (Object[])models.execute( - "execute_kw", asList( - db, uid, password, - "account.invoice", "search", - asList(asList( - asList("type", "=", "out_invoice"), - asList("state", "=", "open"))) - )); - final XmlRpcClientConfigImpl report_config = new XmlRpcClientConfigImpl(); - report_config.setServerURL( - new URL(String.format("%s/xmlrpc/2/report", url))); - final Map<String, Object> result = (Map<String, Object>)client.execute( - report_config, "render_report", asList( - db, uid, password, - "account.report_invoice", - invoice_ids)); - final byte[] report_data = DatatypeConverter.parseBase64Binary( - (String)result.get("result")); - - .. note:: - - the report is sent as PDF binary data encoded in base64_, it must be - decoded and may need to be saved to disk before use - -.. _PostgreSQL: http://www.postgresql.org -.. _XML-RPC: http://en.wikipedia.org/wiki/XML-RPC -.. _base64: http://en.wikipedia.org/wiki/Base64 |
