0.00
21 читатель, 45 топиков

Установка домена для поля many2one

Есть объект «Телефонный звонок».
Есть два поля-списка: «Партнёры» и «Телефонные номера».
«Партнёры» относятся к «Телефонные номера» как one2many (у одного Партнёра может быть n-ное количество Телефонных номеров).
Задача: необходимо, чтобы при выборе Партнёра из списка «Партнёры», в списке «Телефонные номера» отображались только телефонные номера, принадлежащие данному Партнёру. Понимаю, что это возможно выкрутить, но как именно — так и не понял.
P.S. Пока удалось сделать только обратное: при выборе Телефонного номера в списке «Телефонные номера» устанавливается домен для списка «Партнёры», код ниже:

from openerp.osv import fields, osv

class crm_phonecall(osv.osv):

    _inherit = "crm.phonecall"

    _columns = {
        'phonenumber': fields.many2one('phonenumber.phonenumber', 'Phone number', required=True, ondelete='cascade'),

    } 

# Update partner's domain. Leave the only partner that owns selected phonenumber

    def onchange_phonenumber(self, cr, uid, ids, ph_selected):
	if ph_selected > 0:
	    record=self.pool.get('phonenumber.phonenumber').browse(cr, uid, ph_selected, context=None)
	    return {'value': {'partner_id': None},'domain': {'partner_id': [('id','=',record.partner_id.id)]}}  
        return {'value': {'partner_id': None},'domain': {'partner_id':''}} 
 
crm_phonecall();

erppeek - утилита для просмотра данных openerp из командной строки

Точнее, это утилита и одноименная библиотека, представляющая обертку поверх стандартного XML-RPC интерфейса openerp. Утилита позволяет быстро получить данные или список полей модели.

Устанавливаем через pip:
pip install erppeek

или через github:
git clone https://github.com/florentx/erppeek/
cd erppeek
python setup.py install


Внимательно читаем документацию, или примеры для ленивых:

Можно получить все поля пользователя с id=1
erppeek -d openerp -u admin -p admin -m res.users 1
{'action_id': False,
  'active': True,
  'alias_defaults': '{}',
  'alias_domain': '',
  'alias_force_thread_id': 1,
  'alias_id': [1, 'admin@'],
  'alias_model_id': [76, 'Users'],
  'alias_name': 'admin',
  'alias_user_id': [1, 'Administrator'],
  'bank_ids': [],
  'birthdate': False,
  'category_id': [],
...

или например, посмотреть активные задания:
erppeek -d openerp -u admin -p admin -m ir.cron -f id -f name 'active=True'
[{'id': 1, 'name': 'AutoVacuum osv_memory objects'},
 {'id': 2, 'name': 'Email Queue Manager'},
 {'id': 4, 'name': 'Garbage Collect Mail Attachments'},
 {'id': 3, 'name': 'Update Notification'}]

посмотреть какие-то параметры:
erppeek -d openerp -u admin -p admin -m ir.config_parameter 'key like database'
[{'id': 2, 'key': 'database.create_date', 'value': '2013-12-24 19:47:55'},
 {'id': 3,
  'key': 'database.uuid',
  'value': '48b49114-6cd4-11e3-aa45-64b9e8c647f8'}]


в целом, эта небольшая утилита очень упрощает жизнь.

OpenERP и related поля

В официальной документации очень мало написано про то, как использовать поля типа related.
Прототип в официальной документации и его описание:

Sometimes you need to refer to the relation of a relation. For example, supposing you have objects: City -> State -> Country, and you need to refer to the Country from a City, you can define a field as below in the City object:
'country_id': fields.related(
    'state_id',
    'country_id',
    type="many2one",
    relation="res.country",
    string="Country",
    store=False)

Where:
— The first set of parameters are the chain of reference fields to follow, with the desired field at the end.
— type is the type of that desired field.
— Use relation if the desired field is still some kind of reference. relation is the table to look up that reference in.

Но как показывает практика этого описания недостаточно.
Есть, например, два класса invoce и contract.

class invoice(osv.osv):
    _name = "invoice"
    _columns = {
        'name_invoice': fields.char('Name'),
        'date_invoice': fields.datetime('Date')
        #'invoice_line': fields.one2many(....)
        #..... Список других полей .....
    }

class contract(osv.osv):
    _name = "contract"
    _columns = {
        'name_contract': fields.char('Name'),
        'date_contract': fields.datetime('Date')
        #..... Список других полей .....
    }

Нам необходимо, что бы пи создании новой записи в invoice происходила запись полей date_invoice и name_invoice в поля date_contract и name_contract объекта contract.

Для этого описываем дополнительные поля в классе invoice:
'name_lnk': fields.related('name_invoice', 'name_contract', type="char", relation="contract", string="Name")
'date_lnk': fields.related('date_invoice', 'date_contract', type="datetime", relation="contract", string="Date")

Теперь автоматически при создании invoice будет делаться запись в contract.

Вообще, лучше описать прототип так:
'country_id': fields.related(
    <поле_источника>,
    <поле_приёмника>,
    type=<тип_поля>,
    relation=<модель_приёмника>,
    string=<строковое_описание>,
    store=False)


Аргумент store служит для сохранения значений в базе:
Если True — данные сохраняются в базе данных
Если False — то это просто поле-функция, без сохранения данных в БД

Решение проблемы с иерархическим списком (деревом)

Нам нужно было сделать иерархический список по спецификациям, при разработке столкнулись с такой проблемой:
если в списке есть элемент, относящийся к разным спецификациям, и у него есть дочерние элементы, то при клике на него открываются дочерние элементы только первого элемента с подобным названием, который в списке. Причина — строки для скрытия/открытия в структуре DOM имеют одинаковые id и действие срабатывает для первых найденных.
Решение было найдено путём изменения функции hook_row_click, которая находится в файле addons/web/static/src/js/view_tree.js

Код для переопределения функции:
openerp.open_products_mrp = function(instance) {
    var module = instance.web;
    var QWeb = instance.web.qweb;


    module.TreeView = module.TreeView.extend({
    hook_row_click: function () {
        var self = this;
        this.$el.delegate('.treeview-td span, .treeview-tr span', 'click', function (e) {
            e.stopImmediatePropagation();
            self.activate($(this).closest('tr').data('id'));
        });

        this.$el.delegate('.treeview-tr', 'click', function () {
            var is_loaded = 0,
                $this = $(this),
                record_id = $this.data('id'),
                record = self.records[record_id],
                children_ids = record[self.children_field];

                if (!$this.parent().hasClass('oe_open')) {
                    self.getdata(record_id, children_ids, $this.parent());
                }
                else{
                    var datalevel = parseInt($this.parent().attr('data-level'));
                    $($this.parent().nextAll('tr')).each(function() {
                        datalevel_this = parseInt($(this).attr('data-level'));
                        if(datalevel_this>datalevel){
                            $(this).remove();
                        }
                        else return false;
                    });
                    $this.parent().removeClass();
                }
        });
    },
    getdata: function (id, children_ids, curr_node) {
        var self = this;

        self.dataset.read_ids(children_ids, this.fields_list()).done(function(records) {
            _(records).each(function (record) {
                self.records[record.id] = record;
            });

            if (curr_node) {
                var $curr_node = $(curr_node);
            } else {
                var $curr_node = self.$el.find('#treerow_' + id);
            }

            var children_rows = QWeb.render('TreeView.rows', {
                'records': records,
                'children_field': self.children_field,
                'fields_view': self.fields_view.arch.children,
                'fields': self.fields,
                'level': $curr_node.data('level') || 0,
                'render': instance.web.format_value,
                'color_for': self.color_for
            });

            if ($curr_node.length) {
                $curr_node.addClass('oe_open');
                $curr_node.after(children_rows);
            } else {
                self.$el.find('tbody').html(children_rows);
            }
        });
    }
    });

};


UPD: готовый модуль для версии 7.0 доступен по адресу openerp-russia.ru/download/tt_mrp_bom_tree_view.tar.gz

Усовершенствования в структуре

Новость за 9 апреля 2012 года с официального блога OpenERP
Мы собираемся разработать значительные усовершенствования структуры для версии 7.0, ожидаемой в сентябре 2012. Эти усовершенствования позволят OpenERP быть более модульным, быть более легким для изучения новыми разработчиками, разработав модуль с меньшим количеством линий кода и более pythonic.

Наши первые тесты позволили нам уменьшать простой модуль («идея») от 300 линий кода к 200 линиям (на 33 % меньше). Мы также значительно сократили количество методов алгоритмов, чтобы изучение было более понятным, более независимым и общим. Это понизит кривую обучения для новых разработчиков.

Среди всех усовершенствований самые важные:
Читать дальше →

Создание модуля локализации l10n_ru. Вы можете помочь!

UPD: уже имеется модуль локализации для версии 7.0 а также печатные формы. Кому интересно — пишите в комментариях. Сейчас можно помочь сделать формы на QWeb для версии 8.0 а также улучшить модуль локализации. Текст ниже уже не актуален, в данный момент разработка ведется на GitHub: https://github.com/odoo-russia/odoo-russia

Было решено создать свободный модуль локализации для России, и добиться включения его в официальный дистрибутив.

Что для этого требуется вы можете прочитать в оригинале тут: doc.openerp.com/v6.1/contribute/15_guidelines/l10n_guidelines.html
Перевод на русский язык тут: codup.com/sistemi/svobodnie/openerp/rukovodstva/132-rukovodstvo-po-lokalizacii.html

В результате создана команда OpenERP Russian Localization Team: https://launchpad.net/~openerp-l10n-ru

В ней создана ветка l10n_ru, которая привязана к проекту openobject-addons. Все как по правилам на этой странице.

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

Когда посчитаем что локализация выполнена, пошлем запрос на слияние с транком.

Читать дальше →

Заметка о переводе - седьмая (термины перевода)

Пакет универсален и сильно масштабируем — от ИП до корпораций. Поэтому в переводе нужно выбирать возможно универсальные варианты.
customer — наиболее универсально — покупатель, но это может быть клиент при постоянных закупках партий товаров или же заказчик какого-либо продукта производства или какого-либо проекта. В зависимости от модуля переводы различны.
stock — запас, но никак не склад (warehouse). Запас может находиться даже на разных континентах и даже не на ваших складах и вам его может не хватать в конкретном расположении при общей сумме покрывающей многократно заказанное.
Названия подразделений, отделов и прочее не имеют смысла в случае ИП. Как вы будете называть в этом случае начальника отдела кадров? И наоборот, если это корпорация, то уже не группа или отдел, а департамент.
product — это не ТМЦ. Это продукт, возможно и продукт отходов жизнедеятельности с отрицательной стоимостью, который нужно утилизировать (га...).
company — компания, предприятие, организация? Всё зависит от масштаба и принадлежности (частное, государственное).
Особое место занимает понятие ID. Это идентификатор объекта. Это номер, но с возможным префиксом и инфиксом. Для его использования (особенно в заголовках таблиц) я бы использовал *№* (номер в погонах). На этом самом ID построена вся логика пакета. Его предлагали переводить как артикул, но это мелковато. ID присваивается продукту, действию, счёту, налогу, событию, форме, шаблону формы и в конце концов полю формы. Да всему.
В связи со сказанным, конкретика переводов весьма не желательна. Можно создать несколько вариантов перевода в зависимости от масштабов компании (да и не компании в данном случае, а предприятии, организации и т.д.).

Эта статья входит в цикл статей «Заметки по русификации». Все заметки:
Предлагаю заметки по русификации OpenERP
Заметка о переводе — первая (технические средства)
Заметка о переводе — вторая (что нужно, и что не нужно переводить)
Заметка о переводе — третья (стиль перевода)
Заметка о переводе — четвёртая (локализация)
Заметка о переводе — пятая (горячие клавиши)
Заметка о переводе — шестая (как пристроить перевод)
Заметка о переводе — седьмая (термины перевода)

Заметка о переводе - шестая (как пристроить перевод)

Судя по вопросам в форуме у новичков есть трудности с пристройкой перевода.
Здесь важно понять механику. Дело в том, что из модулей перевод берётся только 1 раз — при создании БД и записывается в БД вместе с данными. На лету поменять перевод не получится. И на одном сервере могут находиться несколько БД с разными переводами! Выход в создании новой базы или перезапуске сервера с использованием строкового параметра обновления БД (используйте --help для получения списка параметров).
На форуме дали подсказку и скорее всего сработает самый простой вариант: после копирования файлов перевода в действующий пакет с созданной БД загружаем из пакета (не из инета) официальный перевод с установленной галкой замены терминов, перезапускаем сервер и всё. Этот шаг в связи с косяками разработчиков всё равно обязателен для чистого перевода всех пунктов меню.
Мои файлы переводов соответствуют структуре каталогов системы и могут быть установлены простым копированием каталогов (Server и Client) с заменой файлов. Но учтите, что для Linux сначала нужно установить правильного владельца каталогов и файлов (через chown) и, может быть права доступа (в разных Linux по разному).
GTK-клиент скорее всего можно корректировать на лету (но только клиент, не модули пакета). Дело в том, что этот клиент использует и .po и транслированный файл .mo.

Эта статья входит в цикл статей «Заметки по русификации». Все заметки:
Предлагаю заметки по русификации OpenERP
Заметка о переводе — первая (технические средства)
Заметка о переводе — вторая (что нужно, и что не нужно переводить)
Заметка о переводе — третья (стиль перевода)
Заметка о переводе — четвёртая (локализация)
Заметка о переводе — пятая (горячие клавиши)
Заметка о переводе — шестая (как пристроить перевод)
Заметка о переводе — седьмая (термины перевода)