1. Home
  2. Docs
  3. Webservice API

Webservice API

Debug Mode
To get all the fields of a model you can use fields_get() which is explained in the section Listing record fields.It’s also possible to put the instance in debug mode by using https://mycompany.bizzcloud.nl/web?debug=1If in debug mode it’s possible to hover over every field label to get information about the record.For example when opening a customer and hover over the label website you get the following information:Field: websiteObject: res.partner (note: this is the model, in all examples we use res.partner)Type: char

Tip

When opening the chrome inspector and creating a customer you can see the call on the network tab. When looking to the create call you can see the request payload with information about creating a customer.

Connection Parameters
  • Python
url = <insert server URL>
db = <insert database name>
username = 'demo'
password = <insert password for your user>
  • Ruby
url = <insert server URL>
db = <insert database name>
username = "demo"
password = <insert password for your user>
  • PHP
$url = <insert server URL>;
$db = <insert database name>;
$username = "demo";
$password = <insert password for your user>
  • Java
final String url = <insert server URL>,
              db = <insert database name>,
        username = "admin",
        password = <insert password for your user>;

Logging in

BizzCloud 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.

  • Python
import xmlrpclib
common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url))
common.version()
uid = common.authenticate(db, username, password, {})
  • Ruby
common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common")
common.call('version')
uid = common.call('authenticate', db, username, password, {})
  • PHP
$common = ripcord::client("$url/xmlrpc/2/common");
$common->version();
$uid = $common->authenticate($db, $username, $password, array());

Note

These examples use the Ripcord library, which provides a simple XML-RPC API. Ripcord requires that XML-RPC support be enabled in your PHP installation.

Since calls are performed over HTTPS, it also requires that the OpenSSL extension be enabled.

  • 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());
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 BizzCloud 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)

 

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):

  • Python
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password,
    'res.partner', 'check_access_rights',
    ['read'], {'raise_exception': False})
true
  • 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})
true
  • 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));
true
  • 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); }}
));

true

List records

Records can be listed and filtered via search().

search() takes a mandatory domain filter (possibly empty), and returns the database identifiers of all records matching the filter. To list customer companies for instance:

  • Python
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True], ['customer', '=', True]]])
[7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
  • Ruby
models.execute_kw(db, uid, password,
    'res.partner', 'search',
    [[['is_company', '=', true], ['customer', '=', true]]])
[7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
  • PHP
$models->execute_kw($db, $uid, $password,
    'res.partner', 'search', array(
        array(array('is_company', '=', true),
              array('customer', '=', true))));
[7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
  • Java
asList((Object[])models.execute("execute_kw", asList(
    db, uid, password,
    "res.partner", "search",
    asList(asList(
        asList("is_company", "=", true),
        asList("customer", "=", true)))
)));
[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.

  • Python
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password, 'res.partner', 'search', [[['is_company', '=', True], ['customer', '=', True]]], {'offset': 10, 'limit': 5})
[13, 20, 30, 22, 29]

Count records

Rather than retrieve a possibly gigantic list of records and count them, search_count() can be used to retrieve only the number of records matching the query. It takes the same domain filter as search() and no other parameter.

  • Python
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))

models.execute_kw(db, uid, password, 'res.partner', 'search_count', [[['is_company', '=', True], ['customer', '=', True]]])
19
  • Ruby
models.execute_kw(db, uid, password,
    'res.partner', 'search_count',
    [[['is_company', '=', true], ['customer', '=', true]]])
19
  • PHP
$models->execute_kw($db, $uid, $password,
    'res.partner', 'search_count',
    array(array(array('is_company', '=', true),
                array('customer', '=', true))));
19
  • Java
(Integer)models.execute("execute_kw", asList(
    db, uid, password,
    "res.partner", "search_count",
    asList(asList(
        asList("is_company", "=", true),
        asList("customer", "=", true)))
));

19

Read records

Record data is accessible via the read() method, which takes a list of ids (as returned by 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.

  • 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)
121
  • 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
121
  • 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]);
121
  • 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();
121

Conversedly, picking only three fields deemed interesting.

  • Python
models.execute_kw(db, uid, password,
    'res.partner', 'read',
    [ids], {'fields': ['name', 'country_id', 'comment']})
[{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]
  • Ruby
models.execute_kw(db, uid, password,
    'res.partner', 'read',
    [ids], {fields: %w(name country_id comment)})
[{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]
  • PHP
$models->execute_kw($db, $uid, $password,
    'res.partner', 'read',
    array($ids),
    array('fields'=>array('name', 'country_id', 'comment')));
[{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]
  • 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"));
    }}
)));
[{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]

Listing record fields

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):

  • Python
models.execute_kw(
    db, uid, password, 'res.partner', 'fields_get',
    [], {'attributes': ['string', 'help', 'type']})
{
    "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"
    },
  • Ruby
models.execute_kw(
    db, uid, password, 'res.partner', 'fields_get',
    [], {attributes: %w(string help type)})
{
    "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"
    },
  • PHP
$models->execute_kw($db, $uid, $password,
    'res.partner', 'fields_get',
    array(), array('attributes' => array('string', 'help', 'type')));
{
    "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"
    },
  • 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"));
    }}
));
{
    "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, BizzCloud provides a search_read() shortcut which as its name suggests is equivalent to a search() followed by a read(), but avoids having to perform two requests and keep ids around.

Its arguments are similar to search()‘s, but it can also take a list of fields (like read(), if that list is not provided it will fetch all fields of matched records):

  • Python
models.execute_kw(db, uid, password,
    'res.partner', 'search_read',
    [[['is_company', '=', True], ['customer', '=', True]]],
    {'fields': ['name', 'country_id', 'comment'], 'limit': 5})
[
    {
        "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"
    }
]
  • Ruby
models.execute_kw(db, uid, password,
    'res.partner', 'search_read',
    [[['is_company', '=', true], ['customer', '=', true]]],
    {fields: %w(name country_id comment), limit: 5})
[
    {
        "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"
    }
]
  • 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));
[
    {
        "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"
    }
]
  • 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);
    }}
)));
[
    {
        "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 create(). The method will create a single record and return its database identifier.

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.

  • Python
id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
    'name': "New Partner",
}])
78
  • Ruby
id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
    name: "New Partner",
}])
78
  • PHP
$id = $models->execute_kw($db, $uid, $password,
    'res.partner', 'create',
    array(array('name'=>"New Partner")));
78
  • Java
final Integer id = (Integer)models.execute("execute_kw", asList(
    db, uid, password,
    "res.partner", "create",
    asList(new HashMap() {{ put("name", "New Partner"); }})
));
78

Update records

Records can be updated using write(), it takes a list of records to update and a mapping of updated fields to values similar to 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).

  • 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]])
[[78, "Newer partner"]]
  • 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]])
[[78, "Newer partner"]]
  • 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)));
[[78, "Newer partner"]]
  • 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))
)));
[[78, "Newer partner"]]

Delete records

Records can be deleted in bulk by providing their ids to unlink().

  • 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]]])
[]
  • 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]]])
[]
  • 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))));
[]
  • 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)))
)));
[]

Inspection and introspection

While we previously used fields_get() to query a model and have been using an arbitrary model from the start, BizzCloud 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.

ir.model

Provides information about BizzCloud 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 One2many to ir.model.fields
view_ids
One2many to the Views defined for the model
access_ids
One2many relation to the Access Control 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

a custom model will initially contain only the “built-in” fields available on all models:

  • 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']})
{
    "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"
    }
}
  • 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'))
);
{
    "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"
    }
}
  • 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)})
{
    "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"
    }
}
  • 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"));
        }}
));
{
    "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"
    }
}

ir.model.fields

Provides information about the fields of BizzCloud models and allows adding custom fields without using Python code

model_id
Many2one to ir.model 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 type of field to create
state
whether the field was created via Python code (base) or via ir.model.fields (manual)
requiredreadonlytranslate
enables the corresponding flag on the field
groups
field-level access control, a Many2many to res.groups
selectionsizeon_deleterelationrelation_fielddomain

Like custom models, only new fields created with state="manual" are activated as actual fields on the model.

  • 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]])
[
    {
        "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"
    }
]
  • 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)));
[
    {
        "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"
    }
]
  • 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]])
[
    {
        "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"
    }
]
  • 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))
));
[
    {
        "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"
    }
]

Workflow manipulations

Workflows can be moved along by sending them signals. Instead of using the top-level execute_kw, signals are sent using exec_workflow.

Signals are sent to a specific record, and possibly trigger a transition on the workflow instance associated with the record.

  • Python
client = models.execute_kw(
    db, uid, password,
    'res.partner', 'search_read',
    [[('customer', '=', True)]],
    {'limit': 1, 'fields': [
        'property_account_receivable_id',
        'property_payment_term_id',
        'property_account_position_id']
    })[0]
invoice_id = models.execute_kw(
    db, uid, password,
    'account.invoice', 'create', [{
        'partner_id': client['id'],
        'account_id': client['property_account_receivable_id'][0],
        'invoice_line_ids': [(0, False, {'name': "AAA"})]
    }])

models.exec_workflow(
    db, uid, password, 'account.invoice', 'invoice_open', invoice_id)
  • PHP
$client = $models->execute_kw(
    $db, $uid, $password,
    'res.partner', 'search_read',
    array(array(array('customer', '=', true))),
    array(
        'limit' => 1,
        'fields' => array(
            'property_account_receivable_id',
            'property_payment_term_id',
            'property_account_position_id'
        )))[0];
$invoice_id = $models->execute_kw(
    $db, $uid, $password,
    'account.invoice', 'create', array(array(
        'partner_id' => $client['id'],
        'account_id' => $client['property_account_receivable_id'][0],
        'invoice_line_ids' => array(array(0, false, array('name' => "AAA")))
    )));

$models->exec_workflow(
    $db, $uid, $password,
    'account.invoice', 'invoice_open',
     $invoice_id);
  • Ruby
client = models.execute_kw(
    db, uid, password,
    'res.partner', 'search_read',
    [[['customer', '=', true]]],
    {limit: 1, fields: %w(property_account_receivable_id property_payment_term_id property_account_position_id)}
)[0]
invoice_id = models.execute_kw(
    db, uid, password,
    'account.invoice', 'create', [{
        partner_id: client['id'],
        account_id: client['property_account_receivable_id'][0],
        invoice_line_ids: [[0, false, {name: "AAA"}]]
    }])

models.exec_workflow(
    db, uid, password,
    'account.invoice', 'invoice_open', invoice_id)
  • Java
final Map<String, Object> c = (Map<String, Object>)
    ((Object[])models.execute("execute_kw", asList(
            db, uid, password,
            "res.partner", "search_read",
            asList(
                asList(
                    asList("customer", "=", true))),
            new HashMap<String, Object>() {{
                    put("limit", 1);
                    put("fields", asList(
                        "property_account_receivable_id",
                        "property_payment_term_id",
                        "property_account_position_id"
                    ));
                }}
    )))[0];
final Integer invoice_id = (Integer)models.execute(
    "execute_kw", asList(
        db, uid, password,
        "account.invoice", "create",
        asList(new HashMap<String, Object>() {{
            put("partner_id", c.get("id"));
            put("account_id", ((Object[])c.get("property_account_receivable_id"))[0]);
            put("invoice_line_ids", asList(
                asList(0, false, new HashMap<String, Object>() {{
                    put("name", "AAA");
                }})
            ));
        }})
));

models.execute(
    "exec_workflow", asList(
        db, uid, password,
        "account.invoice", "invoice_open", invoice_id));

Report printing

Available reports can be listed by searching the ir.actions.report.xml 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
  • 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')
  • 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']);
  • 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'])
  • 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"));


Examples

Some examples written in Python but can be easily adapted to other languages to create and update products and stock

import xmlrpclib
url = 'https://mycompany.bizzcloud.nl'
db = 'mycompany'
username = 'your username'
password = 'your password'

common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))

# get products modified after a certain date
products = models.execute_kw(db, uid, password, 'product.product', 'search_read', 
                            [[['write_date', '>', '2020-11-26 12:00:57']]], 
                            {'fields': 
                                ['display_name', 'barcode', 'standard_price', 'list_price', 'virtual_available', 'qty_available']
                            })

print(products)

# get stock changes after a certain date
stock_quant_ids = models.execute_kw(db, uid, password, 'stock.quant', 'search_read', [[['write_date', '>', '2020-11-26 12:00:57']]],
                                                                            {'fields': ['product_id']})

for product in stock_quant_ids:
    product_with_stock = models.execute_kw(db, uid, password, 'product.product', 'search_read', [[['id', '=', product['product_id'][0]]]],
                                                                            {'fields': ['display_name', 'barcode', 'standard_price', 'list_price', 'virtual_available', 'qty_available']})
    
    print(product_with_stock)

# create product
product_id = models.execute_kw(db, uid, password, 'product.product', 'create', [{ 
    'name': "New Product With Stock",
    'standard_price': 120,
    'list_price': 150.50,
    'type':'product', # [product, consu, service] product is stockable product, consu is consumable product, service is a service product
}]) 

# change stock of product 
change_stock_id = models.execute_kw(db, uid, password, 'stock.change.product.qty', 'create', [{ 
                'product_id': product_id,
                'location_id': 15, # can be different when using multiple stock locations
                'new_quantity': 20,
                }])

models.execute_kw(db, uid, password, 'stock.change.product.qty', 'change_product_qty', [change_stock_id])

Was this article helpful to you? Yes No