Создание модуля - Odoo 8.0

Запуск и остановка сервера Odoo

Odoo использует клиент-серверную архитектуру, где клиентами являются web браузеры, которые работают с Odoo сервером через RPC протокол.

Бизнес-логика и расширение обычно выполняются на стороне сервера, хотя к клиенту могут быть добавлены поддерживающие клиентские функции (например, новые представления данных, такие как интерактивные карты).

In order to start the server, simply invoke the command odoo.py in the shell, adding the full path to the file if necessary:

odoo.py

Сервер можно остановить двойным нажатием Ctrl-C в консоли, или убив соответствующий процесс в операционной системе.

Создание модуля в Odoo

Расширения как сервера, так и клиента представляют собой модули, которые могут быть загружены в базу данных.

Odoo модули могут, как добавлять абсолютно новую бизнес-логику, так и расширять существующую: модуль может быть создан для того, чтобы добавить план счетов соответствующей страны таким образом, чтобы Odoo мог поддерживать именно ваш тип бухгалтерского учета. В тоже время, другой модуль добавляет поддержку отображения состояния вашего автобусного парка в режиме реального времени.

Таким образом, все в Odoo начинается и заканчивается модулями.

Состав модуля

Модуль Odoo может содержать следующие элементы:

Бизнес-объекты:
declared as Python classes, these resources are automatically persisted by Odoo based on their configuration
Данные
XML or CSV files declaring metadata (views or workflows), configuration data (modules parameterization), demonstration data and more
Web controllers

Обрабатывать запросы от веб-браузеров

Статические ресурсы

Изображения, CSS или javascript-файлы, используемые веб-интерфейсом или веб-сайтом

Структура модуля

Each module is a directory within a module directory. Module directories are specified by using the --addons-path option.

An Odoo module is declared by its manifest. See the manifest documentation information about it.

Модуль так же является Python пакетом с файлом __init__.py, содержащим инструкции импорта для различных Python файлов в модуле.

Например, если в модуле есть только mymodule.py, тогда файл __init__.py должен содержать:

from . import mymodule

Odoo provides a mechanism to help set up a new module, odoo.py has a subcommand scaffold to create an empty module:

$ odoo.py scaffold <module name> <where to put it>

Команда создаст подкаталог для вашего модуля, и автоматически создаст группу стандартных файлов для модуля. Большинство из них содержит закомментированный Python код или XML. Об использование большинства этих файлов будет рассказано в данном руководстве.

Объектно-реляционное отображение

Ключевой компонент Odoo это ORM. Этот слой избавляет от необходимости писать самому SQL запросы руками и предоставляет гибкие и безопасные сервисы 2.

Business objects are declared as Python classes extending Model which integrates them into the automated persistence system.

Models can be configured by setting a number of attributes at their definition. The most important attribute is _name which is required and defines the name for the model in the Odoo system. Here is a minimally complete definition of a model:

from openerp import models
class MinimalModel(models.Model):
    _name = 'test.model'

Поля модели данных

Поля используются для определения того, что модель данных может хранить и где. Поля определяются как атрибуты в классе модели:

from openerp import models, fields

class LessMinimalModel(models.Model):
    _name = 'test.model2'

    name = fields.Char()

Базовые атрибуты

Подобно самой модели данных, ее поля могут быть настроены путем передачи значений атрибутов в качестве параметров:

name = field.Char(required=True)

Некоторые атрибуты доступны во всех полях, вот самые распространенные из них:

string (unicode, default: field's name)

Надпись для поля в UI (пользовательском интерфейсе).

required (bool, default: False)

Если True, поле не может быть пустым оно должно иметь значение по умолчанию или всегда быть заполнено при создании записи.

help (unicode, default: '')

Портянка, показывает всплывающее поле с описанием объекта для пользователей в UI.

index (bool, default: False)
Requests that Odoo create a database index on the column

Простые поля

Есть два наиболее распространенных вида полей: «простые» поля, которые представляют собой атомарные значения, хранящиеся непосредственно в таблице модели, и «реляционные» поля, связывающие записи (одной модели данных или разных моделей данных).

Example of simple fields are Boolean, Date, Char.

Зарезервированные поля

Odoo создает несколько полей, которые есть во всех моделях данных1. Эти поля управляются системой и их не нужно прописывать, но их можно прочитать если существует такая необходимость:

id (Id)
the unique identifier for a record in its model
create_date (Datetime)
creation date of the record
create_uid (Many2one)
user who created the record
write_date (Datetime)
last modification date of the record
write_uid (Many2one)
user who last modified the record

Специальные поля

By default, Odoo also requires a name field on all models for various display and search behaviors. The field used for these purposes can be overridden by setting _rec_name.

Данные

Odoo - система со сверхточным механизмом управления данными. Несмотря на то что ее поведение управляется при помощи кода Python, часть значений модуля находится в данных, которые он устанавливает при загрузке.

Данные модуля описываются через data files, XML файлы с элементами <record>. Каждый элемент <record> создает или модифицирует записи в базе данных.

<openerp>
    <data>
        <record model="{model name}" id="{record identifier}">
            <field name="{a field name}">{a value}</field>
        </record>
    </data>
<openerp>
  • model is the name of the Odoo model for the record
  • id is an external identifier, it allows referring to the record (without having to know its in-database identifier)
  • <field> элементы имеют параметр name который является именем поля в модели данных (например description). Тело элемента и есть значение поля.

Файлы данных должны быть описаны в файле манифеста, для того, чтобы они были загружены их нужно записать в 'data' список (загрузка данных происходит всегда) или в 'demo' список (загрузка данных происходит только в режиме "Загрузка демо-данных").

Действия и пункты меню

Действия и пункты меню являются регулярными записями в базе данных, обычно объявляемыми через файлы данных. Действия могут быть инициированы тремя способами:

  1. нажатием на пункт меню (который связан с конкретным действием)

  2. нажатием на кнопки в формах представлений данных (если они связаны с конкретным действием)

  3. как контекстное действие над объектом

Поскольку пункты меню могут иметь сложную структуру для их описания есть параметр <menuitem> это наиболее простой способ создать описание меню в ir.ui.menu и подключить его к соответствующему действию.

<record model="ir.actions.act_window" id="action_list_ideas">
    <field name="name">Ideas</field>
    <field name="res_model">idea.idea</field>
    <field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_ideas" parent="menu_root" name="Ideas" sequence="10"
          action="action_list_ideas"/>

Базовые представления данных

Базовые представления данных (далее представления). Представления определяют каким образом записи или модель данных будут отображены. Каждый тип представлений являет собой некий заранее оформленный внешний вид для данных, которые находятся в базе данных Odoo (например в виде списка записей или календаря, и т.д. …). Представления могут быть запрошены через вызов их типа (например список контрагентов) или напрямую через их идентификатор. Для общих запросов будет использовано представление с правильным типом и низким приоритетом (таким образом, представление с наименьшим приоритетом каждого типа, будет являться им по умолчанию

Наследование представлений позволяет изменять представления, объявленные в другом месте (добавлять или удалять содержимое).

Стандартное использование представления

Представление создается как запись модели данных `` ir.ui.view``. Тип преставления назначается корневым элементом поля arch:

<record model="ir.ui.view" id="view_id">
    <field name="name">view.name</field>
    <field name="model">object_name</field>
    <field name="priority" eval="16"/>
    <field name="arch" type="xml">
        <!-- view content: <form>, <tree>, <graph>, ... -->
    </field>
</record>

Преставления в виде Tree

Преставления в виде Tree, так же называются преставлениями в виде списков, отражают записи в табличной форме

Их корневой элемент <tree>. Самая простая форма преставления в виде tree это список всех полей таблицы, которые мы хотим показать на экране (каждое поле это колонка):

<tree string="Idea list">
    <field name="name"/>
    <field name="inventor_id"/>
</tree>

Преставления в виде Form

Преставления в виде Form используются для создания и модификации единичных записей.

Their root element is <form>. They composed of high-level structure elements (groups, notebooks) and interactive elements (buttons and fields):

<form string="Idea form">
    <group colspan="4">
        <group colspan="2" col="2">
            <separator string="General stuff" colspan="2"/>
            <field name="name"/>
            <field name="inventor_id"/>
        </group>

        <group colspan="2" col="2">
            <separator string="Dates" colspan="2"/>
            <field name="active"/>
            <field name="invent_date" readonly="1"/>
        </group>

        <notebook colspan="4">
            <page string="Description">
                <field name="description" nolabel="1"/>
            </page>
        </notebook>

        <field name="state"/>
    </group>
</form>

Представления формы могут также использовать простой HTML для создания своих макетов:

<form string="Idea Form">
    <header>
        <button string="Confirm" type="object" name="action_confirm"
                states="draft" class="oe_highlight" />
        <button string="Mark as done" type="object" name="action_done"
                states="confirmed" class="oe_highlight"/>
        <button string="Reset to draft" type="object" name="action_draft"
                states="confirmed,done" />
        <field name="state" widget="statusbar"/>
    </header>
    <sheet>
        <div class="oe_title">
            <label for="name" class="oe_edit_only" string="Idea Name" />
            <h1><field name="name" /></h1>
        </div>
        <separator string="General" colspan="2" />
        <group colspan="2" col="2">
            <field name="description" placeholder="Idea description..." />
        </group>
    </sheet>
</form>

Преставления в виде Search

Преставления в виде Search настраивают поля search для связи с преставлением в виде списка (а так же другими совокупными представлениями). Их корневой элемент <search> и он состоит из полей определяющих какие поля могут участвовать в поиске:

<search>
    <field name="name"/>
    <field name="inventor_id"/>
</search>

Если для модели данных не существует поискового представления, Odoo генерирует одно, которое позволяет только поиск в поле `` name``.

Отношения между моделями данных

Запись из одной модели данных может быть связана с записью в другой модели данных. Например запись коммерческого предложения связана с записью клиента, которая содержит данные о клиента; и она (запись клиента) так же связана с записями коммерческого предложения.

Реляционные поля

Реляционные поля связывают записи, как внутри самой модели данных (иерархические), так и между записями в разных моделях данных.

Типы реляционных полей:

Many2one(other_model, ondelete='set null')

Простая ссылка на другой объект:

print foo.other_id.name
One2many(other_model, related_field)

A virtual relationship, inverse of a Many2one. A One2many behaves as a container of records, accessing it results in a (possibly empty) set of records:

for other in foo.other_ids:
    print other.name
Many2many(other_model)

Двунаправленная множественная связь, любая запись на одной стороне может быть связана с любым количеством записей на другой стороне. Ведет себя как контейнер записей, предоставляя доступ, возможно пустой, к набору записей:

for other in foo.other_ids:
    print other.name

Наследование.

Наследование моделей данных

Odoo предлагает механизм наследования в двух вариантах для расширения существующей модели данных путем создания дополнительного модуля

Первый механизм наследования позволяет модулю изменять поведение модели данных, определенной в другом модуле:

  • добавлять поля к модели данных

  • Переопределить определения полей в модели данных

  • Добавить ограничения в модель данных

  • Добавить методы в модель данных

  • Переопределить существующие методы в модели данных.

Второй механизм наследования (делегирование) позволяет связать каждую запись модели с записью в родительской модели и обеспечивает прозрачный доступ к полям родительской записи.

Наследование представления

Помимо модификации существующих представлений (путем перезаписи), Odoo позволяет наследовать представления где дочерние "расширения" представлений могут быть быть закреплены над корневыми представлениями и могут добавлять или удалять содержимое своего родителя.

Расширение представления соотносится со своим родителем, используя поле inherit_id, и во отличии от одиночного представления его поле arch состоит из любого количества элементов xpath, предоставляя возможность выбора альтернативного наполнения родительского представления:

<!-- improved idea categories list -->
<record id="idea_category_list2" model="ir.ui.view">
    <field name="name">id.category.list2</field>
    <field name="model">idea.category</field>
    <field name="inherit_id" ref="id_category_list"/>
    <field name="arch" type="xml">
        <!-- find field description and add the field
             idea_ids after it -->
        <xpath expr="//field[@name='description']" position="after">
          <field name="idea_ids" string="Number of ideas"/>
        </xpath>
    </field>
</record>
expr

Выражение XPath, выбирает определенный элемент родительского представления. Вызывает ошибку, если он не соответствует ни одному элементу или более одного.

position

Команда для применения к конкретному элементу:

inside

присоединяет тело внутри контейнера xpath после выбранного элемента

replace
replaces the matched element by the xpath's body
before

вставляет контейнер xpath, как неотъемлемую часть в начале выбранного элемента

after

вставляет контейнер xpaths, как неотъемлемую часть в конце выбранного элемента

attributes

предоставляет альтенативные атрибуты выбранного элемента используя специальную команду attribute внутри контейнера xpath

Домены

В Odoo, Domains это значения в которых закодировано состояние записей. Домен это список критериев используемых для выбора из подмножества записей в модели данных. Каждый критерий представляет собой треугольник где вершинами являются имя поля, оператор и значение.

К примеру, при использовании в модели данных Product домен выбирает все services цена которых выше 1000 за одну позицию:

[('product_type', '=', 'service'), ('unit_price', '>', 1000)]

По умолчанию, критерии тесно взаимосвязаны с безусловным AND. Логические операторы & (AND), | (OR) и ! (NOT) могут использоваться для явного объединения критериев. Они используются в позиции префикса (оператор вставляется перед своими аргументами, а не между ними). Например, чтобы выбрать продукты "которые являются услугами ИЛИ имеют цену за единицу, которая НЕ попадает между 1000 и 2000":

['|',
    ('product_type', '=', 'service'),
    '!', '&',
        ('unit_price', '>=', 1000),
        ('unit_price', '<', 2000)]

Параметр domain может быть добавлен к зависимым полям, с целью отделения действительных записей для работы, в процессе выбора записей в базе для работы с клиентским интерфейсом.

Вычисляемые поля и значения по умолчанию

Помимо того, что поля могут сохраняться и быть в прямом доступе непосредственно из базы данных, они также могут вычислены. В этом случае, значения полей не извлекаются непосредственно из базы, а вычисляются 'на лету' путем вызова метода модели данных.

To create a computed field, create a field and set its attribute compute to the name of a method. The computation method should simply set the value of the field to compute on every record in self.

import random
from openerp import models, fields

class ComputedModel(models.Model):
    _name = 'test.computed'

    name = fields.Char(compute='_compute_name')

    @api.multi
    def _compute_name(self):
        for record in self:
            record.name = str(random.randint(1, 1e6))

Зависимости

The value of a computed field usually depends on the values of other fields on the computed record. The ORM expects the developer to specify those dependencies on the compute method with the decorator depends(). The given dependencies are used by the ORM to trigger the recomputation of the field whenever some of its dependencies have been modified:

from openerp import models, fields, api

class ComputedModel(models.Model):
    _name = 'test.computed'

    name = fields.Char(compute='_compute_name')
    value = fields.Integer()

    @api.depends('value')
    def _compute_name(self):
        for record in self:
            self.name = "Record with value %s" % self.value

Значения по умолчанию

Любому полю может быть присвоено значение по умолчанию. В определении поля добавьте опцию default=X, где X является либо литеральным значением Python (логическое, целочисленное, float, string), либо функцией, берущей набор записей и возвращающей значение:

name = fields.Char(default="Unknown")
user_id = fields.Many2one('res.users', default=lambda self: self.env.user)

Onchange

Механизм «onchange» предоставляет возможность для клиентского интерфейса обновлять форму, когда пользователь заполняет значение в поле, не сохраняя ничего в базе данных.

For instance, suppose a model has three fields amount, unit_price and price, and you want to update the price on the form when any of the other fields is modified. To achieve this, define a method where self represents the record in the form view, and decorate it with onchange() to specify on which field it has to be triggered. Any change you make on self will be reflected on the form.

<!-- content of form view -->
<field name="amount"/>
<field name="unit_price"/>
<field name="price" readonly="1"/>
# onchange handler
@api.onchange('amount', 'unit_price')
def _onchange_price(self):
    # set auto-changing field
    self.price = self.amount * self.unit_price
    # Can optionally return a warning and domains
    return {
        'warning': {
            'title': "Something bad happened",
            'message': "It was very bad indeed",
        }
    }

Поведение вычисляемых полей, обозначенных тегом onchange ет быть предугадано путем отслеживания изменений в форме Session измените количество мест или присутствующих, и taken_seats индикатор прогресса обновиться автоматически.

Ограничения модели данных

Odoo provides two ways to set up automatically verified invariants: Python constraints and SQL constraints.

A Python constraint is defined as a method decorated with constrains(), and invoked on a recordset. The decorator specifies which fields are involved in the constraint, so that the constraint is automatically evaluated when one of them is modified. The method is expected to raise an exception if its invariant is not satisfied:

from openerp.exceptions import ValidationError

@api.constrains('age')
def _check_something(self):
    for record in self:
        if record.age > 20:
            raise ValidationError("Your record is too old: %s" % record.age)
    # all records passed the test, don't return anything

SQL constraints are defined through the model attribute _sql_constraints. The latter is assigned to a list of triples of strings (name, sql_definition, message), where name is a valid SQL constraint name, sql_definition is a table_constraint expression, and message is the error message.

Расширенные представления

Преставления в виде Tree

Представления вида Tree могут принимать дополнительные атрибуты для дальнейшей настройки их поведения:

colors

mappings of colors to conditions. If the condition evaluates to True, the corresponding color is applied to the row:

<tree string="Idea Categories" colors="blue:state=='draft';red:state=='trashed'">
    <field name="name"/>
    <field name="state"/>
</tree>

Clauses are separated by ;, the color and condition are separated by :.

editable

"top" или "bottom". Делает представления вида Tree доступным для редактирования в самих строках (вместо того, чтобы просматривать форму), значение - это позиция, где появляются новые строки.

Представления вида Calendar

Отображает записи, как события календаря. Их корневым элементом является <calendar>, а их наиболее распространенными атрибутами являются:

color

Имя поля, используемое для сегментации цветом. Цвета автоматически распределяются по событиям. События в одном цветовом сегменте (записи, имеющие одинаковое значение для их поля @color) будут иметь одинаковый цвет.

date_start

Поле записи, содержащее дату/время начала события

date_stop (опционально)

Поле записи, содержащее конечную дату/время события

field (to define the label for each calendar event)

<calendar string="Ideas" date_start="invent_date" color="inventor_id">
    <field name="name"/>
</calendar>

Преставления в виде Search

Элементы <field> представления вида Search могут иметь filter_domain, который переопределяет домен, сгенерированный для поиска по данному полю. В данной области self представляет собой значение, введенное пользователем. В приведенном ниже примере он используется для поиска по обоим полям name и``description``.

Представление вида Search также могут содержать элементы <filter>, которые действуют как кнопки предопределенных поисков. Фильтры должны иметь один из следующих атрибутов:

domain

Добавит данный домен в текущий поиск

context

Добавит некоторый контекст в текущий поиск; Используйте ключ group_by для группировки результатов по данному имени поля

<search string="Ideas">
    <field name="name"/>
    <field name="description" string="Name and description"
           filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"/>
    <field name="inventor_id"/>
    <field name="country_id" widget="selection"/>

    <filter name="my_ideas" string="My Ideas"
            domain="[('inventor_id', '=', uid)]"/>
    <group string="Group By">
        <filter name="group_by_inventor" string="Inventor"
                context="{'group_by': 'inventor_id'}"/>
    </group>
</search>

Чтобы использовать в действии нестандартное представление вида Search, нужно указать связь, используя поле search_view_id в записи действия.

Действие также может устанавливать значения по умолчанию для полей поиска через поле context: контекстные ключи формы search_default_field_name будут инициализировать field_name с предоставленным значением. Чтобы иметь значение по умолчанию и вести себя как логические значения (их можно включить только по умолчанию), в фильтре поиска должно быть определено необязательное @name.

Gantt

Горизонтальные гистограммы, которые обычно используются для отображения планирования и продвижения проекта, их корневым элементом является <gantt>.

<gantt string="Ideas" date_start="invent_date" color="inventor_id">
    <level object="idea.idea" link="id" domain="[]">
        <field name="inventor_id"/>
    </level>
</gantt>

Представление вида Graph

Представления вида Graph позволяют делать сборный обзор и анализ моделей данных, их корневым элементом является <graph>.

Представления вида Graph имеют 4 режима отображения, режим по умолчанию выбирается с помощью атрибута @type.

Pivot
a multidimensional table, allows the selection of filers and dimensions to get the right aggregated dataset before moving to a more graphical overview
Bar (по умолчанию)

Гистограмма, первое измерение используется для определения групп по горизонтальной оси, другие измерения определяют агрегированные бары внутри каждой группы.

По умолчанию столбцы расположены бок о бок, они могут быть сложены с помощью @stacked="True" на <graph>

Line

2-мерная линейная диаграмма

Pie

2-мерный круговая диаграмма, разделенная на сектора

Представления вида Graph содержат <field> с обязательным атрибутом @type, принимающим значения:

row (по умолчанию)

Поле по умолчанию, в отношении которого будет совершен сбор данных

measure

объединяет значения величин всех дочерних объектов, игнорируя их группы

<graph string="Total idea score by Inventor">
    <field name="inventor_id"/>
    <field name="score" type="measure"/>
</graph>

Kanban

Используется для организации задач, производственных процессов и т.д ... их корневым элементом является <kanban>.

Представление вида Kanban показывает набор карточек, которые могут быть сгруппированы в столбцы. Каждая карточка представляет собой запись, а в каждом столбце - значения поля состояния.

Например, задачи проекта могут быть организованы поэтапно (каждый столбец - это этап) или ответственным (каждый столбец является пользователем) и т.д.

Представления вида Kanban определяют структуру каждой карточки, как сочетание элементов формы (включая базовый HTML) и QWeb.

Workflows

Workflows are models associated to business objects describing their dynamics. Workflows are also used to track processes that evolve over time.

Workflows may be associated with any object in Odoo, and are entirely customizable. Workflows are used to structure and manage the lifecycles of business objects and documents, and define transitions, triggers, etc. with graphical tools. Workflows, activities (nodes or actions) and transitions (conditions) are declared as XML records, as usual. The tokens that navigate in workflows are called workitems.

Безопасность

Чтобы политика безопасности была согласована (без противоречий), необходимо правильно настроить контроль доступа.

Контроль доступа, основанный на группах пользователей

Группы создаются как записи модели данных res.groups, и предоставляют доступ к меню через определение меню (в соответствующем XML файле). Однако даже без меню объекты могут все еще быть доступны косвенно, поэтому для групп должны быть определены разрешения на уровне объекта (чтение, запись, создание, отключение). Они обычно вставляются через CSV-файлы внутри модулей. Также можно ограничить доступ к определенным полям для представления или объекта, используя атрибут групп полей.

Права доступа

Права доступа определяются, как записи в `` ir.model.access``. каждое правило связано с определенной моделью данных, группой (или же no group для глобальных ресурсов), а также набором разрешений: чтение, запись, создание, отключение. Обычно, такие правила заданы в файле CSV, названном по имени модели данных: ir.model.access.csv.

id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_idea_idea,idea.idea,model_idea_idea,base.group_user,1,1,1,0
access_idea_vote,idea.vote,model_idea_vote,base.group_user,1,1,1,0

Правила записи

Права записи определяют ограничения доступа к списку записей конкретной модели данных. Правило представляет собой запись модели данных ir.rule и связано с моделью данных, группами (поле many2many), разрешениями, к которым применяется ограничение, а также с domain. Domain указывает, к каким записям права доступа ограничены.

Here is an example of a rule that prevents the deletion of leads that are not in state cancel. Notice that the value of the field groups must follow the same convention as the method write() of the ORM.

<record id="delete_cancelled_only" model="ir.rule">
    <field name="name">Only cancelled leads may be deleted</field>
    <field name="model_id" ref="crm.model_crm_lead"/>
    <field name="groups" eval="[(4, ref('base.group_sale_manager'))]"/>
    <field name="perm_read" eval="0"/>
    <field name="perm_write" eval="0"/>
    <field name="perm_create" eval="0"/>
    <field name="perm_unlink" eval="1" />
    <field name="domain_force">[('state','=','cancel')]</field>
</record>

Помощники

Wizards describe interactive sessions with the user (or dialog boxes) through dynamic forms. A wizard is simply a model that extends the class TransientModel instead of Model. The class TransientModel extends Model and reuse all its existing mechanisms, with the following particularities:

  • Записи мастера не являются постоянными; Они автоматически удаляются из базы данных через определенное время. Вот почему они называются transient (транзитные).

  • Модели помощников не нуждаются в явных объявлениях прав доступа: пользователи имеют все права доступа к записям помощников.

  • Записи мастера могут относиться как к обычным записям, так и к записям полей many2one, а регулярные записи не могут ссылаться на записи мастера через поле many2one.

Мы хотим создать помощника, который позволит пользователям становиться участниками определенного Курса или списка Курсов одновременно.

Запуск помощников

Запустить помощника можно через ir.actions.act_window, указав в поле target значение new. Последний открывает окно помощника в новом всплывающем окне. Действие может быть вызвано пунктом меню.

There is another way to launch the wizard: using an ir.actions.act_window record like above, but with an extra field src_model that specifies in the context of which model the action is available. The wizard will appear in the contextual actions of the model, above the main view. Because of some internal hooks in the ORM, such an action is declared in XML with the tag act_window.

<act_window id="launch_the_wizard"
            name="Launch the Wizard"
            src_model="context_model_name"
            res_model="wizard_model_name"
            view_mode="form"
            target="new"
            key2="client_action_multi"/>

Помощник использует стандартное представление, а его кнопки могут снабжаться атрибутом special = "cancel ", чтобы закрыть окно помощника без сохранения.

Переводы

Каждый модуль может иметь несколько вариантов перевода. Все они находятся в папке i18n в виде LANG.po файлов, где LANG - код локали для языка, или же, комбинация Язык_Страна, в случае, если они отличаются (пример: pt.po или pt_BR.po). Перевод будет автоматически втянут в Odoo для всех отмеченных языков. Разработчики используют английский для создания модулей, затем экспортируют термины модуля в Odoo's через gettext POT export (Settings ‣ Translations ‣ Import/Export ‣ Export Translation без указания языка), создавая пустой шаблон POT, добавляя затем еще и файлы переводов PO. Множество IDE's снабжены специальными инструментами для работы с файлами PO/POT.

|- idea/ # The module directory
   |- i18n/ # Translation files
      | - idea.pot # Translation Template (exported from Odoo)
      | - fr.po # French translation
      | - pt_BR.po # Brazilian Portuguese translation
      | (...)

Отчеты

Отчеты для печати

Odoo 8.0 comes with a new report engine based on QWeb, Twitter Bootstrap and Wkhtmltopdf.

Отчет представляет собой комбинацию двух элементов:

  • an ir.actions.report.xml, for which a <report> shortcut element is provided, it sets up various basic parameters for the report (default type, whether the report should be saved to the database after generation,…)

    <report
        id="account_invoices"
        model="account.invoice"
        string="Invoices"
        report_type="qweb-pdf"
        name="account.report_invoice"
        file="account.report_invoice"
        attachment_use="True"
        attachment="(object.state in ('open','paid')) and
            ('INV'+(object.number or '').replace('/','')+'.pdf')"
    />
    
  • Стандартный вид QWeb view для отчета:

    <t t-call="report.html_container">
        <t t-foreach="docs" t-as="o">
            <t t-call="report.external_layout">
                <div class="page">
                    <h2>Report title</h2>
                </div>
            </t>
        </t>
    </t>
    
    the standard rendering context provides a number of elements, the most
    important being:
    
    ``docs``
        the records for which the report is printed
    ``user``
        the user printing the report
    

Поскольку отчеты являются стандартными веб-страницами, они доступны через URL, а выходные параметры могут обрабатываться по этому URL-адресу, например, HTML-версия отчета Invoice доступна через http://localhost:8069/report/html/account.report_invoice/1 (если установлен модуль ​​``account``) и версия PDF через http://localhost:8069/report/pdf/account.report_invoice/1.

Сводные отчеты

Веб сервисы

Модуль веб-сервиса предлагает общий интерфейс для всех веб-сервисов

  • XML-RPC
  • JSON-RPC

Бизнес-объекты также могут быть доступны через механизм распределенных объектов. Все они могут быть изменены с помощью клиентского интерфейса в контекстных представлениях.

Odoo доступна через интерфейсы XML-RPC/JSON-RPC, для которых библиотеки существуют на многих языках.

Библиотека XML-RPC

The following example is a Python program that interacts with an Odoo server with the library xmlrpclib:

import xmlrpclib

root = 'http://%s:%d/xmlrpc/' % (HOST, PORT)

uid = xmlrpclib.ServerProxy(root + 'common').login(DB, USER, PASS)
print "Logged in as %s (uid: %d)" % (USER, uid)

# Create a new note
sock = xmlrpclib.ServerProxy(root + 'object')
args = {
    'color' : 8,
    'memo' : 'This is a note',
    'create_uid': uid,
}
note_id = sock.execute(DB, uid, PASS, 'note.note', 'create', args)

Библиотека JSON-RPC

The following example is a Python program that interacts with an Odoo server with the standard Python libraries urllib2 and json:

import json
import random
import urllib2

def json_rpc(url, method, params):
    data = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": random.randint(0, 1000000000),
    }
    req = urllib2.Request(url=url, data=json.dumps(data), headers={
        "Content-Type":"application/json",
    })
    reply = json.load(urllib2.urlopen(req))
    if reply.get("error"):
        raise Exception(reply["error"])
    return reply["result"]

def call(url, service, method, *args):
    return json_rpc(url, "call", {"service": service, "method": method, "args": args})

# log in the given database
url = "http://%s:%s/jsonrpc" % (HOST, PORT)
uid = call(url, "common", "login", DB, USER, PASS)

# create a new note
args = {
    'color' : 8,
    'memo' : 'This is another note',
    'create_uid': uid,
}
note_id = call(url, "object", "execute", DB, uid, PASS, 'note.note', 'create', args)

Here is the same program, using the library jsonrpclib:

import jsonrpclib

# server proxy object
url = "http://%s:%s/jsonrpc" % (HOST, PORT)
server = jsonrpclib.Server(url)

# log in the given database
uid = server.call(service="common", method="login", args=[DB, USER, PASS])

# helper function for invoking model methods
def invoke(model, method, *args):
    args = [DB, uid, PASS, model, method] + list(args)
    return server.call(service="object", method="execute", args=args)

# create a new note
args = {
    'color' : 8,
    'memo' : 'This is another note',
    'create_uid': uid,
}
note_id = invoke('note.note', 'create', args)

Примеры могут быть легко адаптированы из XML-RPC в JSON-RPC.

[2]

Запись прямых SQL-запросов возможна, но требует осторожности, поскольку обходит все механизмы аутентификации и безопасности Odoo.