Стандартным механизмом для расширения функционала Odoo является использование модулей, но многие его функции и все данные доступны извне для анализа или интеграции с различными инструментами. Часть API Model Reference доступна через XML-RPC и может быть задействована на разных языках программирования.
Соединение
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))
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
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)));
}});
}};
Настройка
Если у вас уже есть установленные сервер Odoo, то вы может использовать следующие параметры
Предупреждение
Для экземпляров Odoo Online (<домен> .odoo.com) пользователи создаются без локального пароля (вы авторизуетесь как пользователь, вошедший в систему через систему аутентификации Odoo Online, а не на самом сервере). Чтобы использовать XML-RPC на экземплярах Odoo Online, вам необходимо установить пароль для учетной записи пользователя, которую вы хотите использовать:
Зайдите как администратор
Перейдите
Кликните на пользователя, которому хотите предоставить доступ с помощью XML-RPC
Кликните по кнопке Изменить пароль
Введите в поле Новый пароль собственно сам пароль а затем нажмине Изменить пароль.
Параметр url будет таким же как ссылка к вашему экземпляру Odoo Online (например https://mycompany.odoo.com), параметр database name это имя экземпляра (например mycompany). Парметр username это логин пользователя, для которого вы меняли пароль.
- Python
- Ruby
- PHP
- Java
url = <insert server URL>
db = <insert database name>
username = 'admin'
password = <insert password for your admin user (default: admin)>
url = <insert server URL>
db = <insert database name>
username = "admin"
password = <insert password for your admin user (default: admin)>
$url = <insert server URL>;
$db = <insert database name>;
$username = "admin";
$password = <insert password for your admin user (default: admin)>;
final String url = <insert server URL>,
db = <insert database name>,
username = "admin",
password = <insert password for your admin user (default: admin)>;
Демо
Чтобы упростить себе жизнь, вы также можете запросить тестовую базу данных по этой ссылке https://demo.odoo.com:
- Python
- Ruby
- PHP
- Java
import xmlrpclib
info = xmlrpclib.ServerProxy('https://demo.odoo.com/start').start()
url, db, username, password = \
info['host'], info['database'], info['user'], info['password']
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']
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']);
Примечание
Этот пример использует Ripcord библиотеку, которая предоставляет простое XML-RPC API. Ripcord требует` использование XML-RPC должно быть включено <http://php.net/manual/en/xmlrpc.installation.php>`_ в вашем PHP окружении.
Помните что вызовы через`HTTPS <http://en.wikipedia.org/wiki/HTTP_Secure>`_, требуют так же наличие подключенного расширения OpenSSL .
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");
Авторизация
Odoo требует чтобы пользователи API проходили авторизацию прежде чем они смогут делать запросы.
Эндпоинт xmlrpc/2/common
предоставляет доступ к вызовам, которые не требуют аутентификации, например сама аутентификация или запрос информации о версии. Самый простой способ проверить правильность информации о соединении перед аутентификацией - запросить версию сервера. Сама аутентификация выполняется через функцию``authenticate`` и возвращает идентификатор пользователя (uid
) используемый в дальнейшем вместо логина.
- Python
- Ruby
- PHP
- Java
common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url))
common.version()
common = XMLRPC::Client.new2("#{url}/xmlrpc/2/common")
common.call('version')
$common = ripcord::client("$url/xmlrpc/2/common");
$common->version();
final XmlRpcClientConfigImpl common_config = new XmlRpcClientConfigImpl();
common_config.setServerURL(
new URL(String.format("%s/xmlrpc/2/common", url)));
client.execute(common_config, "version", emptyList());
{
"server_version": "8.0",
"server_version_info": [8, 0, 0, "final", 0],
"server_serie": "8.0",
"protocol_version": 1,
}
- Python
- Ruby
- PHP
- Java
uid = common.authenticate(db, username, password, {})
uid = common.call('authenticate', db, username, password, {})
$uid = $common->authenticate($db, $username, $password, array());
int uid = (int)client.execute(
common_config, "authenticate", asList(
db, username, password, emptyMap()));
Методы
Вторым эндпоинтом является xmlrpc/2/object
, он используется для вызова методов моделей с помощью функции удаленного вызова процедур(RPC) execute_kw
.
Каждый вызов execute_kw
принимает следующие параметры:
имя базы данных - string
идентификатор пользователя (полученный с помощью функции
authenticate
) - integerпароль пользователя - строка
имя модели - строка
имя вызываемого метода внутри модели - строка
список позиционных параметров - массив/список
ключевые параметры - словарь
Например, если мы имеет доступ для чтения к модели res.partner
мы можем вызвать метод check_access_rights
с позиционным аргументом operation
и ключевым аргуметом raise_exception
(чтобы получить результат true/false , а не true/error):
- Python
- Ruby
- PHP
- Java
models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
models.execute_kw(db, uid, password,
'res.partner', 'check_access_rights',
['read'], {'raise_exception': False})
models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
models.execute_kw(db, uid, password,
'res.partner', 'check_access_rights',
['read'], {raise_exception: false})
$models = ripcord::client("$url/xmlrpc/2/object");
$models->execute_kw($db, $uid, $password,
'res.partner', 'check_access_rights',
array('read'), array('raise_exception' => false));
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
Список записей
Записи могут быть получены в виде списка и отфильтрованы с помощью search()
.
search()
. содержит обязательный domain фильтр (возможно пустой), и возвращает идентификаторы всех записей, которые удовлетворяют данному фильтру/Например список всех клиентов, которые являются компаниями:
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', True], ['customer', '=', True]]])
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', true], ['customer', '=', true]]])
$models->execute_kw($db, $uid, $password,
'res.partner', 'search', array(
array(array('is_company', '=', true),
array('customer', '=', true))));
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]
Разбиение на страницы
По умолчанию поиск вернет идентификаторы всех записей, соответствующих условию, которое может быть очень велико. Параметры offset
и limit
позволяют возвращать подмножества всех записей, удовлетворяющих запросу.
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', True], ['customer', '=', True]]],
{'offset': 10, 'limit': 5})
models.execute_kw(db, uid, password,
'res.partner', 'search',
[[['is_company', '=', true], ['customer', '=', true]]],
{offset: 10, limit: 5})
$models->execute_kw($db, $uid, $password,
'res.partner', 'search',
array(array(array('is_company', '=', true),
array('customer', '=', true))),
array('offset'=>10, 'limit'=>5));
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); }}
)));
[13, 20, 30, 22, 29]
Количество записей
Вместо того, чтобы запросить гигантский список записей, а затем посчитать их, search_count()
запрос может быть использован для получения только количества записей удовлетворяющих условию. Он использует такой же domain фильтр, как и search()
и никаких других параметров.
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search_count',
[[['is_company', '=', True], ['customer', '=', True]]])
models.execute_kw(db, uid, password,
'res.partner', 'search_count',
[[['is_company', '=', true], ['customer', '=', true]]])
$models->execute_kw($db, $uid, $password,
'res.partner', 'search_count',
array(array(array('is_company', '=', true),
array('customer', '=', true))));
(Integer)models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "search_count",
asList(asList(
asList("is_company", "=", true),
asList("customer", "=", true)))
));
19
Предупреждение
Запрос search
, а затем search_count
(или в обратном порядке) может не выдать согласованного результата, если другие пользователи используют сервер: сохраненные данные могли быть изменены между запросами
Чтение записей
Доступ к записи данных осуществляется с помощью метода read()
, который содержит список идентификаторов (которые были возвращены по запросу: search()
) и опционально список полей, данные из которых мы хотим получить. По умолчанию вы получите значение всех полей, к которым имеет доступ текущий пользователь, количество которых может быть очень большим.
- Python
- Ruby
- PHP
- Java
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)
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
$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]);
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
В случае, если нам интересны только три поля.
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'read',
[ids], {'fields': ['name', 'country_id', 'comment']})
models.execute_kw(db, uid, password,
'res.partner', 'read',
[ids], {fields: %w(name country_id comment)})
$models->execute_kw($db, $uid, $password,
'res.partner', 'read',
array($ids),
array('fields'=>array('name', 'country_id', 'comment')));
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"}]
Примечание
Даже если id
поля не был запрошен, его значение всегда будет содержаться в ответе
Список полей записи
fields_get()
может быть использован для для проверки полей модели данных на наличие интересующей информации.
Поскольку данный запрос возвращает большое количество мета-информации (он так же используется программами-клиентами), она должна быть отфильтрована перед печатью, наиболее интересные элементы для человеческого восприятия это string
(описание поля), help
(справочный текст, если имеется) и type
(чтобы знать какое значение ожидать или посылать при обновлении записи):
- Python
- Ruby
- PHP
- Java
models.execute_kw(
db, uid, password, 'res.partner', 'fields_get',
[], {'attributes': ['string', 'help', 'type']})
models.execute_kw(
db, uid, password, 'res.partner', 'fields_get',
[], {attributes: %w(string help type)})
$models->execute_kw($db, $uid, $password,
'res.partner', 'fields_get',
array(), array('attributes' => array('string', 'help', 'type')));
(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"
},
Поиск и чтение
Поскольку это очень распространенная задача, Odoo предоставляет search_read()
запрос, который согласно его наименованию, эквивалентен search()
, следует за read()
, но вместо двух запросов позволяет сделать один и сохранить идентификаторы.
Его аргументы такие же как и у search()
, но он так же понимает список fields
(например read()
, если в этом списке нет критериев выбора, он вернет все поля совпадающих условиям поиска записей):
- Python
- Ruby
- PHP
- Java
models.execute_kw(db, uid, password,
'res.partner', 'search_read',
[[['is_company', '=', True], ['customer', '=', True]]],
{'fields': ['name', 'country_id', 'comment'], 'limit': 5})
models.execute_kw(db, uid, password,
'res.partner', 'search_read',
[[['is_company', '=', true], ['customer', '=', true]]],
{fields: %w(name country_id comment), limit: 5})
$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));
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()
. Метод создаст одну запись и вернет ее идентификатор базы данных.
create()
принимает сопоставления полей и их значений и использует их для инициализации записи. Для каждого поля, для которого не указано сопоставление со значением, будет присвоено значение по умолчанию.
- Python
- Ruby
- PHP
- Java
id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
'name': "New Partner",
}])
id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
name: "New Partner",
}])
$id = $models->execute_kw($db, $uid, $password,
'res.partner', 'create',
array(array('name'=>"New Partner")));
final Integer id = (Integer)models.execute("execute_kw", asList(
db, uid, password,
"res.partner", "create",
asList(new HashMap() {{ put("name", "New Partner"); }})
));
78
Предупреждение
в то время как большинство значений типов называются так же как и сами типы (integer для Integer
, string для:class:[UNKNOWN NODE title_reference] или Text
),
One2many
andMany2many
используют специальную команду протокола, подробно описанный вдокументации к методу записи
.
Обновление записей
Значение записей могут быть обновлены используя метод write()
, он принимает список записей и сопоставление обновляемых полей и их значений точно так же, как и метод create()
.
Несколько записей могут обновляться одновременно, но все они получат одинаковые значения для всех указанных полей. В настоящее время невозможно выполнить «вычисляемые» обновления (когда устанавливаемое значение зависит от существующего значения записи).
- Python
- Ruby
- PHP
- Java
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]])
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]])
$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)));
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"]]
Удаление записей
Записи могут быть удалены массово, путем указании их идентификаторов unlink()
.
- Python
- Ruby
- PHP
- Java
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]]])
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]]])
$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))));
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)))
)));
[]
Контроль и самоанализ
Ранее мы использовали fields_get()
для запроса модели и с самого начала использовали произвольную модель , Odoo хранит большинство метаданных модели внутри нескольких метамоделей, что позволяет делать как запрос к системе так и изменять данные в полях модели(с некоторыми ограничениями) на лету через XML-RPC.
ir.model
Предоставляет информацию о моделях Odoo через различные поля
name
понятное человеку описание модели
model
имя каждой модели в системе
state
Была ли модель сгенерирована в коде Python (
base
) или же создана запись вir.model
(manual
)field_id
Список полей модели данных связанных через
One2many
с ir.model.fieldsview_ids
One2many
с Представления, определенными для модели данныхaccess_ids
One2many
ссылается на Контроль доступа, установленного для модели
ir.model
можно использовать для
опрашивать систему об установленных моделях (в качестве предварительного условия для работы с моделью или для изучения содержимого системы)
получить информацию о конкретной модели (как правило, путем перечисления полей, связанных с ней)
динамически создавать новые модели с помощью удаленного вызова процедур (RPC)
Предупреждение
"произвольное" имя модели данных должно начинаться с
x_
поле
state
должно иметь значениеmanual
, в противном случае модель данных не загрузитсяНевозможно добавлять новые методы в пользовательскую модель, только поля
Пользовательская модель данных первоначально будет содержать только «встроенные» поля, доступные для всех моделей:
- Python
- PHP
- Ruby
- Java
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']})
$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'))
);
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)})
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
Предоставляет информацию о полях моделей Odoo и позволяет добавлять настраиваемые поля без использования кода Python
model_id
name
техническое имя поля (используется в работе методов``read`` или
write
)field_description
понятное для человека описание поля (например
string
вfields_get
)ttype
type (тип) создаваемого поля
state
было ли поле создано с помощью кода Python (
base
) или черезir.model.fields
(manual
)required
,readonly
,translate
Включает соответствующий флаг на поле
groups
- field-level access control, a
Many2many
tores.groups
selection
,size
,on_delete
,relation
,relation_field
,domain
типозависимые свойства и настройки, смотрите детальное описание полей для более подробного понимания
Как и в пользовательских моделях , в качестве фактических полей модели активируются только новые поля, созданные с помощью state="manual"
.
Предупреждение
Вычисленные поля не могут быть добавлены через ir.model.fields
, некоторая мета-информация поля (defaults, onchange)) не может быть установлена
- Python
- PHP
- Ruby
- Java
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]])
$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)));
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]])
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"
}
]
Манипуляция бизнес-процессами
Workflows можно перемещать из одного состояния в другое, отправляя им сигналы. Вместо использования высокоуровнего execute_kw
, вы можете отправить сигнал с помощью``exec_workflow``.
Сигналы отправляются в определенную запись и, по возможности, инициируют переход на нужный этап бизнес-процесса, связанного с записью.
Предупреждение
Для этого примера необходим установленный модуль account
- Python
- PHP
- Ruby
- Java
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)
$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);
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)
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));
Печать отчетов
Доступные отчеты могут быть перечислены путем поиска по модели данных ir.actions.report.xml
, просматривая поля, представляющие интерес,
model
модель данных, к которой относится отчет, можно использовать для поиска доступных отчетов по конкретной модели данных
name
человекочитаемое имя печатной формы
report_name
техническое имя печатной формы, используется для его печати
Печатные формы могут быть распечатаны через RPC используя следующие данные:
имя печатной формы (
report_name
)Идентификаторы записей для включения в отчет
- Python
- PHP
- Ruby
- Java
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')
$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']);
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'])
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"));
Примечание
Отчет отправляется как двоичные данные PDF, закодированные в base64, он должен быть декодирован и, возможно, его потребуется сохранить на диск перед использованием