Browse Source
Merge pull request #357 from leemannd/9.0-mig-partner_changeset
Merge pull request #357 from leemannd/9.0-mig-partner_changeset
[9.0][Port] mig partner changesetpull/257/merge
Pedro M. Baeza
8 years ago
committed by
GitHub
27 changed files with 3345 additions and 0 deletions
-
168partner_changeset/README.rst
-
4partner_changeset/__init__.py
-
24partner_changeset/__openerp__.py
-
49partner_changeset/demo/changeset_field_rule.xml
-
324partner_changeset/i18n/es.po
-
333partner_changeset/i18n/fr.po
-
289partner_changeset/i18n/partner_changeset.pot
-
331partner_changeset/i18n/sl.po
-
7partner_changeset/models/__init__.py
-
144partner_changeset/models/changeset_field_rule.py
-
50partner_changeset/models/res_partner.py
-
514partner_changeset/models/res_partner_changeset.py
-
10partner_changeset/security/ir.model.access.csv
-
29partner_changeset/security/security.xml
-
BINpartner_changeset/static/description/icon.png
-
BINpartner_changeset/static/src/img/changeset.png
-
BINpartner_changeset/static/src/img/rules.png
-
6partner_changeset/tests/__init__.py
-
77partner_changeset/tests/common.py
-
78partner_changeset/tests/test_changeset_field_rule.py
-
281partner_changeset/tests/test_changeset_field_type.py
-
246partner_changeset/tests/test_changeset_flow.py
-
118partner_changeset/tests/test_changeset_origin.py
-
61partner_changeset/views/changeset_field_rule_views.xml
-
8partner_changeset/views/menu.xml
-
157partner_changeset/views/res_partner_changeset_views.xml
-
37partner_changeset/views/res_partner_views.xml
@ -0,0 +1,168 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
================== |
||||
|
Partner Changesets |
||||
|
================== |
||||
|
|
||||
|
This module extends the functionality of partners. It allows to create |
||||
|
changesets that must be validated when a partner is modified instead of direct |
||||
|
modifications. Rules allow to configure which field must be validated. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
Access Rights |
||||
|
------------- |
||||
|
|
||||
|
The changesets rules must be edited by users with the group ``Changesets |
||||
|
Configuration``. The changesets can be applied or canceled only by users |
||||
|
with the group ``Changesets Validations`` |
||||
|
|
||||
|
Changesets Rules |
||||
|
---------------- |
||||
|
|
||||
|
The changesets rules can be configured in ``Sales > Configuration > |
||||
|
Partner Changesets > Fields Rules``. For each partner field, an |
||||
|
action can be defined: |
||||
|
|
||||
|
* Auto: the changes made on this field are always applied |
||||
|
* Validate: the changes made on this field must be manually confirmed by |
||||
|
a 'Changesets User' user |
||||
|
* Never: the changes made on this field are always refused |
||||
|
|
||||
|
In any case, all the changes made by the users are always applied |
||||
|
directly on the users, but a 'validated' changeset is created for the |
||||
|
history. |
||||
|
|
||||
|
The supported fields are: |
||||
|
|
||||
|
* Char |
||||
|
* Text |
||||
|
* Date |
||||
|
* Datetime |
||||
|
* Integer |
||||
|
* Float |
||||
|
* Boolean |
||||
|
* Many2one |
||||
|
|
||||
|
Rules can be global (no source model) or configured by source model. |
||||
|
Rules by source model have the priority. If a field is not configured |
||||
|
for the source model, it will use the global rule (if existing). |
||||
|
|
||||
|
If a field has no rule, it is written to the partner without changeset. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
General case |
||||
|
------------ |
||||
|
|
||||
|
The first step is to create the changeset rules, once that done, writes on |
||||
|
partners will be created as changesets. |
||||
|
|
||||
|
Finding changesets |
||||
|
------------------ |
||||
|
|
||||
|
A menu lists all the changesets in ``Sales > Configuration > Partner |
||||
|
Changesets > Changesets``. |
||||
|
|
||||
|
However, it is more convenient to access them directly from the |
||||
|
partners. Pending changesets can be accessed directly from the top right |
||||
|
of the partners' view. A new filter on the partners shows the partners |
||||
|
having at least one pending changeset. |
||||
|
|
||||
|
Handling changesets |
||||
|
------------------- |
||||
|
|
||||
|
A changeset shows the list of the changes made on a partner. Some of the |
||||
|
changes may be 'Pending', some 'Accepted' or 'Rejected' according to the |
||||
|
changeset rules. The only changes that need an action from the user are |
||||
|
'Pending' changes. When a change is accepted, the value is written on |
||||
|
the user. |
||||
|
|
||||
|
The changes view shows the name of the partner's field, the Origin value |
||||
|
and the New value alongside the state of the change. By clicking on the |
||||
|
change in some cases a more detailed view is displayed, for instance, |
||||
|
links for relations can be clicked on. |
||||
|
|
||||
|
A button on a changeset allows to apply or reject all the changes at |
||||
|
once. |
||||
|
|
||||
|
Custom source rules in your addon |
||||
|
--------------------------------- |
||||
|
|
||||
|
Addons wanting to create changeset with their own rules should pass the |
||||
|
following keys in the context when they write on the partner: |
||||
|
|
||||
|
* ``__changeset_rules_source_model``: name of the model which asks for |
||||
|
the change |
||||
|
* ``__changeset_rules_source_id``: id of the record which asks for the |
||||
|
change |
||||
|
|
||||
|
Also, they should extend the selection in |
||||
|
``ChangesetFieldRule._domain_source_models`` to add their model (the |
||||
|
same that is passed in ``__changeset_rules_source_model``). |
||||
|
|
||||
|
The source is used for the application of the rules, allowing to have a |
||||
|
different rule for a different source. It is also stored on the changeset for |
||||
|
information. |
||||
|
|
||||
|
Screenshot: |
||||
|
----------- |
||||
|
|
||||
|
* Configuration of rules |
||||
|
|
||||
|
.. image:: partner_changeset/static/src/img/rules.png |
||||
|
|
||||
|
* Changeset waiting for validation |
||||
|
|
||||
|
.. image:: partner_changeset/static/src/img/changeset.png |
||||
|
|
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/134/9.0 |
||||
|
|
||||
|
Known issues / Roadmap |
||||
|
====================== |
||||
|
|
||||
|
* Only a subset of the type of fields is actually supported |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues |
||||
|
<https://github.com/OCA/partner-contact/issues>`_. In case of trouble, please |
||||
|
check there if your issue has already been reported. If you spotted it first, |
||||
|
help us smashing it by providing a detailed and welcomed `feedback |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Images |
||||
|
------ |
||||
|
|
||||
|
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Guewen Baconnier <guewen.baconnier@camptocamp.com> |
||||
|
* Denis Leemann <denis.leemann@camptocamp.com> |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from . import models |
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
{'name': 'Partner Changesets', |
||||
|
'version': '9.0.1.0.0', |
||||
|
'author': 'Camptocamp, Odoo Community Association (OCA)', |
||||
|
'license': 'AGPL-3', |
||||
|
'category': 'Sales Management', |
||||
|
'depends': ['base', |
||||
|
'sale', |
||||
|
], |
||||
|
'website': 'http://www.camptocamp.com', |
||||
|
'data': ['security/security.xml', |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/menu.xml', |
||||
|
'views/res_partner_changeset_views.xml', |
||||
|
'views/changeset_field_rule_views.xml', |
||||
|
'views/res_partner_views.xml', |
||||
|
], |
||||
|
'demo': ['demo/changeset_field_rule.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo noupdate="1"> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_name"> |
||||
|
<field name="field_id" ref="base.field_res_partner_name"/> |
||||
|
<field name="action">auto</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_street"> |
||||
|
<field name="field_id" ref="base.field_res_partner_street"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_street2"> |
||||
|
<field name="field_id" ref="base.field_res_partner_street2"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_zip"> |
||||
|
<field name="field_id" ref="base.field_res_partner_zip"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_city"> |
||||
|
<field name="field_id" ref="base.field_res_partner_city"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_email"> |
||||
|
<field name="field_id" ref="base.field_res_partner_email"/> |
||||
|
<field name="action">never</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_ref"> |
||||
|
<field name="field_id" ref="base.field_res_partner_ref"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_country_id"> |
||||
|
<field name="field_id" ref="base.field_res_partner_country_id"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="changeset.field.rule" id="changeset_field_rule_credit_limit"> |
||||
|
<field name="field_id" ref="base.field_res_partner_credit_limit"/> |
||||
|
<field name="action">validate</field> |
||||
|
</record> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1,324 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * partner_changeset |
||||
|
# |
||||
|
# Translators: |
||||
|
# Oihane Crucelaegui <oihanecruce@gmail.com>, 2016 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-07-03 07:56+0000\n" |
||||
|
"PO-Revision-Date: 2016-07-03 07:56+0000\n" |
||||
|
"Last-Translator: Oihane Crucelaegui <oihanecruce@gmail.com>, 2016\n" |
||||
|
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: es\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: sql_constraint:changeset.field.rule:0 |
||||
|
msgid "A rule already exists for this field." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Accepted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,action:0 |
||||
|
msgid "Action" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Apply" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Apply pending changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,action:0 |
||||
|
msgid "" |
||||
|
"Auto: always apply a change.\n" |
||||
|
"Validate: manually applied by an administrator.\n" |
||||
|
"Never: change never applied." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.res_partner_view_buttons |
||||
|
#: field:res.partner,count_pending_changesets:0 |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: field:res.partner.changeset,change_ids:0 |
||||
|
msgid "Changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,changeset_id:0 |
||||
|
msgid "Changeset" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_manager |
||||
|
msgid "Changeset Configuration" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_changeset_field_rule |
||||
|
msgid "Changeset Field Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_form |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_search |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_tree |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_changeset_field_rule_view |
||||
|
msgid "Changeset Fields Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_res_partner_changeset |
||||
|
#: field:res.partner,changeset_ids:0 |
||||
|
msgid "Changesets" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_user |
||||
|
msgid "Changesets Validations " |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_uid:0 |
||||
|
#: field:res.partner.changeset,create_uid:0 |
||||
|
#: field:res.partner.changeset.change,create_uid:0 |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_date:0 |
||||
|
#: field:res.partner.changeset,create_date:0 |
||||
|
#: field:res.partner.changeset.change,create_date:0 |
||||
|
msgid "Created on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,date:0 |
||||
|
msgid "Date" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,display_name:0 |
||||
|
#: field:res.partner.changeset,display_name:0 |
||||
|
#: field:res.partner.changeset.change,display_name:0 |
||||
|
msgid "Display Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
msgid "Done" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,field_id:0 |
||||
|
#: field:res.partner.changeset.change,field_id:0 |
||||
|
msgid "Field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset_field_rule |
||||
|
msgid "Field Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,field_type:0 |
||||
|
msgid "Field Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
msgid "Group By" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,id:0 field:res.partner.changeset,id:0 |
||||
|
#: field:res.partner.changeset.change,id:0 |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,source_model_id:0 |
||||
|
msgid "" |
||||
|
"If a source model is defined, the rule will be applied only when the change is made from this origin. Rules without source model are global and applies to all backends.\n" |
||||
|
"Rules with a source model have precedence over global rules, but if a field has no rule with a source model, the global rule is used." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,__last_update:0 |
||||
|
#: field:res.partner.changeset,__last_update:0 |
||||
|
#: field:res.partner.changeset.change,__last_update:0 |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_uid:0 |
||||
|
#: field:res.partner.changeset,write_uid:0 |
||||
|
#: field:res.partner.changeset.change,write_uid:0 |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_date:0 |
||||
|
#: field:res.partner.changeset,write_date:0 |
||||
|
#: field:res.partner.changeset.change,write_date:0 |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,new_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,new_value_char:0 |
||||
|
#: field:res.partner.changeset.change,new_value_date:0 |
||||
|
#: field:res.partner.changeset.change,new_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,new_value_display:0 |
||||
|
#: field:res.partner.changeset.change,new_value_float:0 |
||||
|
#: field:res.partner.changeset.change,new_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,new_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,new_value_text:0 |
||||
|
msgid "New" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,note:0 |
||||
|
msgid "Note" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,old_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,old_value_char:0 |
||||
|
#: field:res.partner.changeset.change,old_value_date:0 |
||||
|
#: field:res.partner.changeset.change,old_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,old_value_float:0 |
||||
|
#: field:res.partner.changeset.change,old_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,old_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,old_value_text:0 |
||||
|
msgid "Old" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,partner_id:0 |
||||
|
msgid "Partner" |
||||
|
msgstr "Empresa" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_res_partner_changeset_view |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_tree |
||||
|
msgid "Partner Changeset" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset_change |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Partner Changeset Change" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset |
||||
|
msgid "Partner Changesets" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Pending" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.view_res_partner_filter |
||||
|
msgid "Pending Changesets" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: field:res.partner.changeset.change,origin_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_char:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_date:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_display:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_float:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_text:0 |
||||
|
msgid "Previous" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Reject" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Reject pending changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Rejected" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,source_model_id:0 |
||||
|
msgid "Source Model" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,source:0 |
||||
|
msgid "Source of the change" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,state:0 |
||||
|
#: field:res.partner.changeset.change,state:0 |
||||
|
msgid "State" |
||||
|
msgstr "Estado" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_user |
||||
|
msgid "The user will be able to apply or reject changesets." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_manager |
||||
|
msgid "" |
||||
|
"The user will have an access to the configuration of the changeset rules." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:401 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"This change cannot be applied because a previous changeset for the same partner is pending.\n" |
||||
|
"Apply all the anterior changesets before applying this one." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:416 |
||||
|
#, python-format |
||||
|
msgid "This change has already be applied." |
||||
|
msgstr "" |
@ -0,0 +1,333 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * partner_changeset |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2016 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-07-03 00:45+0000\n" |
||||
|
"PO-Revision-Date: 2016-07-03 00:45+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n" |
||||
|
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: fr\n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: sql_constraint:changeset.field.rule:0 |
||||
|
msgid "A rule already exists for this field." |
||||
|
msgstr "Une règle existe déjà pour ce champ." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Accepted" |
||||
|
msgstr "Accepté" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,action:0 |
||||
|
msgid "Action" |
||||
|
msgstr "Action" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Apply" |
||||
|
msgstr "Appliquer" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Apply pending changes" |
||||
|
msgstr "Appliquer les modifications en attente" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,action:0 |
||||
|
msgid "" |
||||
|
"Auto: always apply a change.\n" |
||||
|
"Validate: manually applied by an administrator.\n" |
||||
|
"Never: change never applied." |
||||
|
msgstr "" |
||||
|
"Auto: toujours appliquer une modification.\n" |
||||
|
"Validation: modification manuellement appliquée par un administrateur.\n" |
||||
|
"Jamais: modification jamais appliquée." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.res_partner_view_buttons |
||||
|
#: field:res.partner,count_pending_changesets:0 |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: field:res.partner.changeset,change_ids:0 |
||||
|
msgid "Changes" |
||||
|
msgstr "Modifications" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,changeset_id:0 |
||||
|
msgid "Changeset" |
||||
|
msgstr "Jeu de modifications" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_manager |
||||
|
msgid "Changeset Configuration" |
||||
|
msgstr "Configuration des modifications" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_changeset_field_rule |
||||
|
msgid "Changeset Field Rules" |
||||
|
msgstr "Règles de modifications par champ" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_form |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_search |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_tree |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_changeset_field_rule_view |
||||
|
msgid "Changeset Fields Rules" |
||||
|
msgstr "Règles de modifications par champ" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_res_partner_changeset |
||||
|
#: field:res.partner,changeset_ids:0 |
||||
|
msgid "Changesets" |
||||
|
msgstr "Modifications" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_user |
||||
|
msgid "Changesets Validations " |
||||
|
msgstr "Validations des modifications" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_uid:0 |
||||
|
#: field:res.partner.changeset,create_uid:0 |
||||
|
#: field:res.partner.changeset.change,create_uid:0 |
||||
|
msgid "Created by" |
||||
|
msgstr "Créé par" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_date:0 |
||||
|
#: field:res.partner.changeset,create_date:0 |
||||
|
#: field:res.partner.changeset.change,create_date:0 |
||||
|
msgid "Created on" |
||||
|
msgstr "Créé le" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,date:0 |
||||
|
msgid "Date" |
||||
|
msgstr "Date" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,display_name:0 |
||||
|
#: field:res.partner.changeset,display_name:0 |
||||
|
#: field:res.partner.changeset.change,display_name:0 |
||||
|
msgid "Display Name" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
msgid "Done" |
||||
|
msgstr "Fait" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,field_id:0 |
||||
|
#: field:res.partner.changeset.change,field_id:0 |
||||
|
msgid "Field" |
||||
|
msgstr "Champ" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset_field_rule |
||||
|
msgid "Field Rules" |
||||
|
msgstr "Règle par champ" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,field_type:0 |
||||
|
msgid "Field Type" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
msgid "Group By" |
||||
|
msgstr "Grouper par" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,id:0 field:res.partner.changeset,id:0 |
||||
|
#: field:res.partner.changeset.change,id:0 |
||||
|
msgid "ID" |
||||
|
msgstr "Id." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,source_model_id:0 |
||||
|
msgid "" |
||||
|
"If a source model is defined, the rule will be applied only when the change is made from this origin. Rules without source model are global and applies to all backends.\n" |
||||
|
"Rules with a source model have precedence over global rules, but if a field has no rule with a source model, the global rule is used." |
||||
|
msgstr "" |
||||
|
"Si un modèle source est défini, la règle ne sera appliquée que lorsque le changement vient de cette source. Les règles sans modèle source sont globales et sont appliquées à toutes les sources.\n" |
||||
|
" Les règles avec une souce ont la précédence sur les règles globales. Si un champ n'a pas de règle avec source, la règle globale est utilisée." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,__last_update:0 |
||||
|
#: field:res.partner.changeset,__last_update:0 |
||||
|
#: field:res.partner.changeset.change,__last_update:0 |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_uid:0 |
||||
|
#: field:res.partner.changeset,write_uid:0 |
||||
|
#: field:res.partner.changeset.change,write_uid:0 |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_date:0 |
||||
|
#: field:res.partner.changeset,write_date:0 |
||||
|
#: field:res.partner.changeset.change,write_date:0 |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,new_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,new_value_char:0 |
||||
|
#: field:res.partner.changeset.change,new_value_date:0 |
||||
|
#: field:res.partner.changeset.change,new_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,new_value_display:0 |
||||
|
#: field:res.partner.changeset.change,new_value_float:0 |
||||
|
#: field:res.partner.changeset.change,new_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,new_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,new_value_text:0 |
||||
|
msgid "New" |
||||
|
msgstr "Nouveau" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,note:0 |
||||
|
msgid "Note" |
||||
|
msgstr "Note" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,old_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,old_value_char:0 |
||||
|
#: field:res.partner.changeset.change,old_value_date:0 |
||||
|
#: field:res.partner.changeset.change,old_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,old_value_float:0 |
||||
|
#: field:res.partner.changeset.change,old_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,old_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,old_value_text:0 |
||||
|
msgid "Old" |
||||
|
msgstr "Ancien" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,partner_id:0 |
||||
|
msgid "Partner" |
||||
|
msgstr "Partenaire" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_res_partner_changeset_view |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_tree |
||||
|
msgid "Partner Changeset" |
||||
|
msgstr "Modifications de partenaire" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset_change |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Partner Changeset Change" |
||||
|
msgstr "Modification de partenaire" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset |
||||
|
msgid "Partner Changesets" |
||||
|
msgstr "Modifications de partenaire" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Pending" |
||||
|
msgstr "En attente" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.view_res_partner_filter |
||||
|
msgid "Pending Changesets" |
||||
|
msgstr "Modifications en attente" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: field:res.partner.changeset.change,origin_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_char:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_date:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_display:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_float:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_text:0 |
||||
|
msgid "Previous" |
||||
|
msgstr "Précédent" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Reject" |
||||
|
msgstr "Rejeter" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Reject pending changes" |
||||
|
msgstr "Rejeter les modifications en attente" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Rejected" |
||||
|
msgstr "Rejeté" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,source_model_id:0 |
||||
|
msgid "Source Model" |
||||
|
msgstr "Modèle source" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,source:0 |
||||
|
msgid "Source of the change" |
||||
|
msgstr "Source du changement" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,state:0 |
||||
|
#: field:res.partner.changeset.change,state:0 |
||||
|
msgid "State" |
||||
|
msgstr "État" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_user |
||||
|
msgid "The user will be able to apply or reject changesets." |
||||
|
msgstr "L'utilisateur pourra appliquer ou rejeter les jeux de modifications." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_manager |
||||
|
msgid "" |
||||
|
"The user will have an access to the configuration of the changeset rules." |
||||
|
msgstr "" |
||||
|
"L'utilisateur aura accès à la configuration des règles de jeux de " |
||||
|
"modifications." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:401 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"This change cannot be applied because a previous changeset for the same partner is pending.\n" |
||||
|
"Apply all the anterior changesets before applying this one." |
||||
|
msgstr "" |
||||
|
"The changement ne peux pas être appliqué car un précédent jeu de modification pour le même partenaire est toujours en attente.\n" |
||||
|
"Il est nécessaire d'appliquer tous les précédents jeux de modification avant d'applique celui-ci." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:416 |
||||
|
#, python-format |
||||
|
msgid "This change has already be applied." |
||||
|
msgstr "The changement est déjà appliqué." |
@ -0,0 +1,289 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * partner_changeset |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2015-11-25 08:31+0000\n" |
||||
|
"PO-Revision-Date: 2015-11-25 08:31+0000\n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: sql_constraint:changeset.field.rule:0 |
||||
|
msgid "A rule already exists for this field." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Accepted" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,action:0 |
||||
|
msgid "Action" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Apply" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Apply pending changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,action:0 |
||||
|
msgid "Auto: always apply a change.\n" |
||||
|
"Validate: manually applied by an administrator.\n" |
||||
|
"Never: change never applied." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner:partner_changeset.res_partner_view_buttons |
||||
|
#: field:res.partner.changeset,change_ids:0 |
||||
|
msgid "Changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,changeset_id:0 |
||||
|
msgid "Changeset" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_manager |
||||
|
msgid "Changeset Configuration" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_changeset_field_rule |
||||
|
msgid "Changeset Field Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_form |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_search |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_tree |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_changeset_field_rule_view |
||||
|
msgid "Changeset Fields Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_res_partner_changeset |
||||
|
#: field:res.partner,changeset_ids:0 |
||||
|
msgid "Changesets" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_user |
||||
|
msgid "Changesets Validations " |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_uid:0 |
||||
|
#: field:res.partner.changeset,create_uid:0 |
||||
|
#: field:res.partner.changeset.change,create_uid:0 |
||||
|
msgid "Created by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_date:0 |
||||
|
#: field:res.partner.changeset,create_date:0 |
||||
|
#: field:res.partner.changeset.change,create_date:0 |
||||
|
msgid "Created on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,date:0 |
||||
|
msgid "Date" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
msgid "Done" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,field_id:0 |
||||
|
#: field:res.partner.changeset.change,field_id:0 |
||||
|
msgid "Field" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset_field_rule |
||||
|
msgid "Field Rules" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
msgid "Group By" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,id:0 |
||||
|
#: field:res.partner.changeset,id:0 |
||||
|
#: field:res.partner.changeset.change,id:0 |
||||
|
msgid "ID" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,source_model_id:0 |
||||
|
msgid "If a source model is defined, the rule will be applied only when the change is made from this origin. Rules without source model are global and applies to all backends.\n" |
||||
|
"Rules with a source model have precedence over global rules, but if a field has no rule with a source model, the global rule is used." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_uid:0 |
||||
|
#: field:res.partner.changeset,write_uid:0 |
||||
|
#: field:res.partner.changeset.change,write_uid:0 |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_date:0 |
||||
|
#: field:res.partner.changeset,write_date:0 |
||||
|
#: field:res.partner.changeset.change,write_date:0 |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,new_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,new_value_char:0 |
||||
|
#: field:res.partner.changeset.change,new_value_date:0 |
||||
|
#: field:res.partner.changeset.change,new_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,new_value_float:0 |
||||
|
#: field:res.partner.changeset.change,new_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,new_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,new_value_text:0 |
||||
|
msgid "New" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,note:0 |
||||
|
msgid "Note" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,old_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,old_value_char:0 |
||||
|
#: field:res.partner.changeset.change,old_value_date:0 |
||||
|
#: field:res.partner.changeset.change,old_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,old_value_float:0 |
||||
|
#: field:res.partner.changeset.change,old_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,old_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,old_value_text:0 |
||||
|
msgid "Old" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,partner_id:0 |
||||
|
msgid "Partner" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_res_partner_changeset_view |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_tree |
||||
|
msgid "Partner Changeset" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset_change |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Partner Changeset Change" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset |
||||
|
msgid "Partner Changesets" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Pending" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.view_res_partner_filter |
||||
|
msgid "Pending Changesets" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Previous" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Reject" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Reject pending changes" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Rejected" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,source_model_id:0 |
||||
|
msgid "Source Model" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,source:0 |
||||
|
msgid "Source of the change" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,state:0 |
||||
|
#: field:res.partner.changeset.change,state:0 |
||||
|
msgid "State" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_user |
||||
|
msgid "The user will be able to apply or reject changesets." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_manager |
||||
|
msgid "The user will have an access to the configuration of the changeset rules." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:418 |
||||
|
#, python-format |
||||
|
msgid "This change cannot be applied because a previous changeset for the same partner is pending.\n" |
||||
|
"Apply all the anterior changesets before applying this one." |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:433 |
||||
|
#, python-format |
||||
|
msgid "This change has already be applied." |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,331 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * partner_changeset |
||||
|
# |
||||
|
# Translators: |
||||
|
# Matjaž Mozetič <m.mozetic@matmoz.si>, 2016 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 8.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2016-07-03 07:56+0000\n" |
||||
|
"PO-Revision-Date: 2016-07-03 07:56+0000\n" |
||||
|
"Last-Translator: Matjaž Mozetič <m.mozetic@matmoz.si>, 2016\n" |
||||
|
"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Language: sl\n" |
||||
|
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: sql_constraint:changeset.field.rule:0 |
||||
|
msgid "A rule already exists for this field." |
||||
|
msgstr "Za to polje že obstaja pravilo." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Accepted" |
||||
|
msgstr "Sprejeto" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,action:0 |
||||
|
msgid "Action" |
||||
|
msgstr "Ukrep" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Apply" |
||||
|
msgstr "Uveljavi" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Apply pending changes" |
||||
|
msgstr "Uveljavi čakajoče spremembe" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,action:0 |
||||
|
msgid "" |
||||
|
"Auto: always apply a change.\n" |
||||
|
"Validate: manually applied by an administrator.\n" |
||||
|
"Never: change never applied." |
||||
|
msgstr "" |
||||
|
"Samodejno: vedno uveljavi spremembo.\n" |
||||
|
"Overi: ročno uveljavi administrator.\n" |
||||
|
"Nikoli: sprememba ni nikoli uveljavljena." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.res_partner_view_buttons |
||||
|
#: field:res.partner,count_pending_changesets:0 |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: field:res.partner.changeset,change_ids:0 |
||||
|
msgid "Changes" |
||||
|
msgstr "Spremembe" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,changeset_id:0 |
||||
|
msgid "Changeset" |
||||
|
msgstr "Niz sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_manager |
||||
|
msgid "Changeset Configuration" |
||||
|
msgstr "Nastavitve niza sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_changeset_field_rule |
||||
|
msgid "Changeset Field Rules" |
||||
|
msgstr "Pravila polja niza sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_form |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_search |
||||
|
#: view:changeset.field.rule:partner_changeset.view_changeset_field_rule_tree |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_changeset_field_rule_view |
||||
|
msgid "Changeset Fields Rules" |
||||
|
msgstr "Pravila polj niza sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_res_partner_changeset |
||||
|
#: field:res.partner,changeset_ids:0 |
||||
|
msgid "Changesets" |
||||
|
msgstr "Nizi sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,name:partner_changeset.group_changeset_user |
||||
|
msgid "Changesets Validations " |
||||
|
msgstr "Overitve nizov sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_uid:0 |
||||
|
#: field:res.partner.changeset,create_uid:0 |
||||
|
#: field:res.partner.changeset.change,create_uid:0 |
||||
|
msgid "Created by" |
||||
|
msgstr "Ustvaril" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,create_date:0 |
||||
|
#: field:res.partner.changeset,create_date:0 |
||||
|
#: field:res.partner.changeset.change,create_date:0 |
||||
|
msgid "Created on" |
||||
|
msgstr "Ustvarjeno" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,date:0 |
||||
|
msgid "Date" |
||||
|
msgstr "Datum" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,display_name:0 |
||||
|
#: field:res.partner.changeset,display_name:0 |
||||
|
#: field:res.partner.changeset.change,display_name:0 |
||||
|
msgid "Display Name" |
||||
|
msgstr "Prikazni naziv" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
msgid "Done" |
||||
|
msgstr "Opravljeno" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,field_id:0 |
||||
|
#: field:res.partner.changeset.change,field_id:0 |
||||
|
msgid "Field" |
||||
|
msgstr "Polje" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset_field_rule |
||||
|
msgid "Field Rules" |
||||
|
msgstr "Pravila polja" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,field_type:0 |
||||
|
msgid "Field Type" |
||||
|
msgstr "Tip polja" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
msgid "Group By" |
||||
|
msgstr "Združi po" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,id:0 field:res.partner.changeset,id:0 |
||||
|
#: field:res.partner.changeset.change,id:0 |
||||
|
msgid "ID" |
||||
|
msgstr "ID" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: help:changeset.field.rule,source_model_id:0 |
||||
|
msgid "" |
||||
|
"If a source model is defined, the rule will be applied only when the change is made from this origin. Rules without source model are global and applies to all backends.\n" |
||||
|
"Rules with a source model have precedence over global rules, but if a field has no rule with a source model, the global rule is used." |
||||
|
msgstr "" |
||||
|
"Če je izvorni model določen, se pravilo uveljavi le za spremembe iz tega izvora. Pravila brez izvornega modela so globalna in se uveljavijo na vseh ozadjih.\n" |
||||
|
"Pravila izvornega modela imajo prednost pred globalnimi pravili, a če polje nima pravila z izvornim modelom, se uporabi globalno pravilo." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,__last_update:0 |
||||
|
#: field:res.partner.changeset,__last_update:0 |
||||
|
#: field:res.partner.changeset.change,__last_update:0 |
||||
|
msgid "Last Modified on" |
||||
|
msgstr "Zadnjič spremenjeno" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_uid:0 |
||||
|
#: field:res.partner.changeset,write_uid:0 |
||||
|
#: field:res.partner.changeset.change,write_uid:0 |
||||
|
msgid "Last Updated by" |
||||
|
msgstr "Zadnji posodobil" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,write_date:0 |
||||
|
#: field:res.partner.changeset,write_date:0 |
||||
|
#: field:res.partner.changeset.change,write_date:0 |
||||
|
msgid "Last Updated on" |
||||
|
msgstr "Zadnjič posodobljeno" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,new_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,new_value_char:0 |
||||
|
#: field:res.partner.changeset.change,new_value_date:0 |
||||
|
#: field:res.partner.changeset.change,new_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,new_value_display:0 |
||||
|
#: field:res.partner.changeset.change,new_value_float:0 |
||||
|
#: field:res.partner.changeset.change,new_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,new_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,new_value_text:0 |
||||
|
msgid "New" |
||||
|
msgstr "Novo" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,note:0 |
||||
|
msgid "Note" |
||||
|
msgstr "Opomba" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset.change,old_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,old_value_char:0 |
||||
|
#: field:res.partner.changeset.change,old_value_date:0 |
||||
|
#: field:res.partner.changeset.change,old_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,old_value_float:0 |
||||
|
#: field:res.partner.changeset.change,old_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,old_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,old_value_text:0 |
||||
|
msgid "Old" |
||||
|
msgstr "Staro" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,partner_id:0 |
||||
|
msgid "Partner" |
||||
|
msgstr "Partner" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.actions.act_window,name:partner_changeset.action_res_partner_changeset_view |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_tree |
||||
|
msgid "Partner Changeset" |
||||
|
msgstr "Niz sprememb partnerja" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.model,name:partner_changeset.model_res_partner_changeset_change |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Partner Changeset Change" |
||||
|
msgstr "Sprememba niza sprememb partnerja" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:ir.ui.menu,name:partner_changeset.menu_changeset |
||||
|
msgid "Partner Changesets" |
||||
|
msgstr "Nizi sprememb partnerja" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: selection:res.partner.changeset,state:0 |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Pending" |
||||
|
msgstr "Čakanje" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner:partner_changeset.view_res_partner_filter |
||||
|
msgid "Pending Changesets" |
||||
|
msgstr "Čakajoči nizi sprememb" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: field:res.partner.changeset.change,origin_value_boolean:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_char:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_date:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_datetime:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_display:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_float:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_integer:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_reference:0 |
||||
|
#: field:res.partner.changeset.change,origin_value_text:0 |
||||
|
msgid "Previous" |
||||
|
msgstr "Prejšnji" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
#: view:res.partner.changeset.change:partner_changeset.view_res_partner_changeset_change_form |
||||
|
msgid "Reject" |
||||
|
msgstr "Zavrni" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_form |
||||
|
msgid "Reject pending changes" |
||||
|
msgstr "Zavrni čakajoče spremembe" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: selection:res.partner.changeset.change,state:0 |
||||
|
msgid "Rejected" |
||||
|
msgstr "Zavrnjeno" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:changeset.field.rule,source_model_id:0 |
||||
|
msgid "Source Model" |
||||
|
msgstr "Izvorni model" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: field:res.partner.changeset,source:0 |
||||
|
msgid "Source of the change" |
||||
|
msgstr "Izvor spremembe" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: view:res.partner.changeset:partner_changeset.view_res_partner_changeset_search |
||||
|
#: field:res.partner.changeset,state:0 |
||||
|
#: field:res.partner.changeset.change,state:0 |
||||
|
msgid "State" |
||||
|
msgstr "Stanje" |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_user |
||||
|
msgid "The user will be able to apply or reject changesets." |
||||
|
msgstr "Uporabnik bo lahko uveljavljal ali zavračal nize sprememb." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: model:res.groups,comment:partner_changeset.group_changeset_manager |
||||
|
msgid "" |
||||
|
"The user will have an access to the configuration of the changeset rules." |
||||
|
msgstr "Uporabnik bo imel dostop do nastavitev pravil niza sprememb." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:401 |
||||
|
#, python-format |
||||
|
msgid "" |
||||
|
"This change cannot be applied because a previous changeset for the same partner is pending.\n" |
||||
|
"Apply all the anterior changesets before applying this one." |
||||
|
msgstr "" |
||||
|
"Te spremembe ni mogoče uveljaviti, ker obstaja za istega partnerja prejšnji čakajoč niz sprememb.\n" |
||||
|
"Pred uveljavitvijo tega uveljavite vse predhodne nize sprememb." |
||||
|
|
||||
|
#. module: partner_changeset |
||||
|
#: code:addons/partner_changeset/models/res_partner_changeset.py:416 |
||||
|
#, python-format |
||||
|
msgid "This change has already be applied." |
||||
|
msgstr "Ta sprememba je že uveljavljena." |
@ -0,0 +1,7 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from . import res_partner |
||||
|
from . import res_partner_changeset |
||||
|
from . import changeset_field_rule |
@ -0,0 +1,144 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from openerp import models, fields, api |
||||
|
from openerp.tools.cache import ormcache |
||||
|
|
||||
|
|
||||
|
class ChangesetFieldRule(models.Model): |
||||
|
_name = 'changeset.field.rule' |
||||
|
_description = 'Changeset Field Rules' |
||||
|
_rec_name = 'field_id' |
||||
|
|
||||
|
field_id = fields.Many2one( |
||||
|
comodel_name='ir.model.fields', |
||||
|
string='Field', |
||||
|
domain="[('model_id.model', '=', 'res.partner'), " |
||||
|
" ('ttype', 'in', ('char', 'selection', 'date', 'datetime', " |
||||
|
" 'float', 'integer', 'text', 'boolean', " |
||||
|
" 'many2one')), " |
||||
|
" ('readonly', '=', False)]", |
||||
|
ondelete='cascade', |
||||
|
required=True, |
||||
|
) |
||||
|
action = fields.Selection( |
||||
|
selection='_selection_action', |
||||
|
string='Action', |
||||
|
required=True, |
||||
|
help="Auto: always apply a change.\n" |
||||
|
"Validate: manually applied by an administrator.\n" |
||||
|
"Never: change never applied.", |
||||
|
) |
||||
|
source_model_id = fields.Many2one( |
||||
|
comodel_name='ir.model', |
||||
|
string='Source Model', |
||||
|
ondelete='cascade', |
||||
|
domain=lambda self: [('id', 'in', self._domain_source_models().ids)], |
||||
|
help="If a source model is defined, the rule will be applied only " |
||||
|
"when the change is made from this origin. " |
||||
|
"Rules without source model are global and applies to all " |
||||
|
"backends.\n" |
||||
|
"Rules with a source model have precedence over global rules, " |
||||
|
"but if a field has no rule with a source model, the global rule " |
||||
|
"is used." |
||||
|
) |
||||
|
|
||||
|
_sql_constraints = [ |
||||
|
('model_field_uniq', |
||||
|
'unique (source_model_id, field_id)', |
||||
|
'A rule already exists for this field.'), |
||||
|
] |
||||
|
|
||||
|
@api.model |
||||
|
def _domain_source_models(self): |
||||
|
""" Returns the models for which we can define rules. |
||||
|
|
||||
|
Example for submodules (replace by the xmlid of the model): |
||||
|
|
||||
|
:: |
||||
|
models = super(ChangesetFieldRule, self)._domain_source_models() |
||||
|
return models | self.env.ref('base.model_res_users') |
||||
|
|
||||
|
Rules without model are global and apply for all models. |
||||
|
|
||||
|
""" |
||||
|
return self.env.ref('base.model_res_users') |
||||
|
|
||||
|
@api.model |
||||
|
def _selection_action(self): |
||||
|
return [('auto', 'Auto'), |
||||
|
('validate', 'Validate'), |
||||
|
('never', 'Never'), |
||||
|
] |
||||
|
|
||||
|
@ormcache(skiparg=1) |
||||
|
@api.model |
||||
|
def _get_rules(self, source_model_name): |
||||
|
""" Cache rules |
||||
|
|
||||
|
Keep only the id of the rules, because if we keep the recordsets |
||||
|
in the ormcache, we won't be able to browse them once their |
||||
|
cursor is closed. |
||||
|
|
||||
|
The public method ``get_rules`` return the rules with the recordsets |
||||
|
when called. |
||||
|
|
||||
|
""" |
||||
|
model_rules = self.search( |
||||
|
['|', ('source_model_id.model', '=', source_model_name), |
||||
|
('source_model_id', '=', False)], |
||||
|
# using 'ASC' means that 'NULLS LAST' is the default |
||||
|
order='source_model_id ASC', |
||||
|
) |
||||
|
# model's rules have precedence over global ones so we iterate |
||||
|
# over rules which have a source model first, then we complete |
||||
|
# them with the global rules |
||||
|
result = {} |
||||
|
for rule in model_rules: |
||||
|
# we already have a model's rule |
||||
|
if result.get(rule.field_id.name): |
||||
|
continue |
||||
|
result[rule.field_id.name] = rule.id |
||||
|
return result |
||||
|
|
||||
|
@api.model |
||||
|
def get_rules(self, source_model_name): |
||||
|
""" Return the rules for a model |
||||
|
|
||||
|
When a model is specified, it will return the rules for this |
||||
|
model. Fields that have no rule for this model will use the |
||||
|
global rules (those without source). |
||||
|
|
||||
|
The source model is the model which ask for a change, it will be |
||||
|
for instance ``res.users``, ``lefac.backend`` or |
||||
|
``magellan.backend``. |
||||
|
|
||||
|
The second argument (``source_model_name``) is optional but |
||||
|
cannot be an optional keyword argument otherwise it would not be |
||||
|
in the key for the cache. The callers have to pass ``None`` if |
||||
|
they want only global rules. |
||||
|
""" |
||||
|
rules = {} |
||||
|
cached_rules = self._get_rules(source_model_name) |
||||
|
for field, rule_id in cached_rules.iteritems(): |
||||
|
rules[field] = self.browse(rule_id) |
||||
|
return rules |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, vals): |
||||
|
record = super(ChangesetFieldRule, self).create(vals) |
||||
|
self.clear_caches() |
||||
|
return record |
||||
|
|
||||
|
@api.multi |
||||
|
def write(self, vals): |
||||
|
result = super(ChangesetFieldRule, self).write(vals) |
||||
|
self.clear_caches() |
||||
|
return result |
||||
|
|
||||
|
@api.multi |
||||
|
def unlink(self): |
||||
|
result = super(ChangesetFieldRule, self).unlink() |
||||
|
self.clear_caches() |
||||
|
return result |
@ -0,0 +1,50 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from openerp import models, fields, api |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
_inherit = 'res.partner' |
||||
|
|
||||
|
changeset_ids = fields.One2many(comodel_name='res.partner.changeset', |
||||
|
inverse_name='partner_id', |
||||
|
string='Changesets', |
||||
|
readonly=True) |
||||
|
count_pending_changesets = fields.Integer( |
||||
|
string='Changes', |
||||
|
compute='_count_pending_changesets', |
||||
|
search='_search_count_pending_changesets') |
||||
|
|
||||
|
@api.one |
||||
|
@api.depends('changeset_ids', 'changeset_ids.state') |
||||
|
def _count_pending_changesets(self): |
||||
|
changesets = self.changeset_ids.filtered( |
||||
|
lambda rev: rev.state == 'draft' and rev.partner_id == self |
||||
|
) |
||||
|
self.count_pending_changesets = len(changesets) |
||||
|
|
||||
|
@api.multi |
||||
|
def write(self, values): |
||||
|
if self.env.context.get('__no_changeset'): |
||||
|
return super(ResPartner, self).write(values) |
||||
|
else: |
||||
|
changeset_model = self.env['res.partner.changeset'] |
||||
|
for record in self: |
||||
|
local_values = changeset_model.add_changeset(record, values) |
||||
|
super(ResPartner, record).write(local_values) |
||||
|
return True |
||||
|
|
||||
|
def _search_count_pending_changesets(self, operator, value): |
||||
|
if operator not in ('=', '!=', '<', '<=', '>', '>=', 'in', 'not in'): |
||||
|
return [] |
||||
|
query = ("SELECT p.id " |
||||
|
"FROM res_partner p " |
||||
|
"INNER JOIN res_partner_changeset r ON r.partner_id = p.id " |
||||
|
"WHERE r.state = 'draft' " |
||||
|
"GROUP BY p.id " |
||||
|
"HAVING COUNT(r.id) %s %%s ") % operator |
||||
|
self.env.cr.execute(query, (value,)) |
||||
|
ids = [row[0] for row in self.env.cr.fetchall()] |
||||
|
return [('id', 'in', ids)] |
@ -0,0 +1,514 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from itertools import groupby |
||||
|
from lxml import etree |
||||
|
from operator import attrgetter |
||||
|
|
||||
|
from openerp import models, fields, api, exceptions, _ |
||||
|
from openerp.osv.orm import setup_modifiers |
||||
|
|
||||
|
# sentinel object to be sure that no empty value was passed to |
||||
|
# ResPartnerChangesetChange._value_for_changeset |
||||
|
_NO_VALUE = object() |
||||
|
|
||||
|
|
||||
|
class ResPartnerChangeset(models.Model): |
||||
|
_name = 'res.partner.changeset' |
||||
|
_description = 'Partner Changeset' |
||||
|
_order = 'date desc' |
||||
|
_rec_name = 'date' |
||||
|
|
||||
|
partner_id = fields.Many2one(comodel_name='res.partner', |
||||
|
string='Partner', |
||||
|
select=True, |
||||
|
required=True, |
||||
|
readonly=True, |
||||
|
ondelete='cascade') |
||||
|
change_ids = fields.One2many(comodel_name='res.partner.changeset.change', |
||||
|
inverse_name='changeset_id', |
||||
|
string='Changes', |
||||
|
readonly=True) |
||||
|
date = fields.Datetime(default=fields.Datetime.now, |
||||
|
select=True, |
||||
|
readonly=True) |
||||
|
state = fields.Selection( |
||||
|
compute='_compute_state', |
||||
|
selection=[('draft', 'Pending'), |
||||
|
('done', 'Done')], |
||||
|
string='State', |
||||
|
store=True, |
||||
|
) |
||||
|
note = fields.Text() |
||||
|
source = fields.Reference( |
||||
|
string='Source of the change', |
||||
|
selection='_reference_models', |
||||
|
readonly=True, |
||||
|
) |
||||
|
|
||||
|
@api.model |
||||
|
def _reference_models(self): |
||||
|
models = self.env['ir.model'].search([]) |
||||
|
return [(model.model, model.name) for model in models] |
||||
|
|
||||
|
@api.one |
||||
|
@api.depends('change_ids', 'change_ids.state') |
||||
|
def _compute_state(self): |
||||
|
if all(change.state in ('done', 'cancel') for change |
||||
|
in self.mapped('change_ids')): |
||||
|
self.state = 'done' |
||||
|
else: |
||||
|
self.state = 'draft' |
||||
|
|
||||
|
@api.multi |
||||
|
def apply(self): |
||||
|
self.mapped('change_ids').apply() |
||||
|
|
||||
|
@api.multi |
||||
|
def cancel(self): |
||||
|
self.mapped('change_ids').cancel() |
||||
|
|
||||
|
@api.multi |
||||
|
def add_changeset(self, record, values): |
||||
|
""" Add a changeset on a partner |
||||
|
|
||||
|
By default, when a partner is modified by a user or by the |
||||
|
system, the the changeset will follow the rules configured for |
||||
|
the 'Users' / global rules. |
||||
|
|
||||
|
A caller should pass the following keys in the context: |
||||
|
|
||||
|
* ``__changeset_rules_source_model``: name of the model which |
||||
|
asks for the change |
||||
|
* ``__changeset_rules_source_id``: id of the record which asks |
||||
|
for the change |
||||
|
|
||||
|
When the source model and id are not defined, the current user |
||||
|
is considered as the origin of the change. |
||||
|
|
||||
|
Should be called before the execution of ``write`` on the record |
||||
|
so we can keep track of the existing value and also because the |
||||
|
returned values should be used for ``write`` as some of the |
||||
|
values may have been removed. |
||||
|
|
||||
|
:param values: the values being written on the partner |
||||
|
:type values: dict |
||||
|
|
||||
|
:returns: dict of values that should be wrote on the partner |
||||
|
(fields with a 'Validate' or 'Never' rule are excluded) |
||||
|
|
||||
|
""" |
||||
|
record.ensure_one() |
||||
|
|
||||
|
source_model = self.env.context.get('__changeset_rules_source_model') |
||||
|
source_id = self.env.context.get('__changeset_rules_source_id') |
||||
|
if not source_model: |
||||
|
# if the changes source is not defined, log the user who |
||||
|
# made the change |
||||
|
source_model = 'res.users' |
||||
|
if not source_id: |
||||
|
source_id = self.env.uid |
||||
|
if source_model and source_id: |
||||
|
source = '%s,%s' % (source_model, source_id) |
||||
|
else: |
||||
|
source = False |
||||
|
|
||||
|
change_model = self.env['res.partner.changeset.change'] |
||||
|
write_values = values.copy() |
||||
|
changes = [] |
||||
|
rules = self.env['changeset.field.rule'].get_rules( |
||||
|
source_model_name=source_model, |
||||
|
) |
||||
|
for field in values: |
||||
|
rule = rules.get(field) |
||||
|
if not rule: |
||||
|
continue |
||||
|
if field in values: |
||||
|
if not change_model._has_field_changed(record, field, |
||||
|
values[field]): |
||||
|
continue |
||||
|
change, pop_value = change_model._prepare_changeset_change( |
||||
|
record, rule, field, values[field] |
||||
|
) |
||||
|
if pop_value: |
||||
|
write_values.pop(field) |
||||
|
changes.append(change) |
||||
|
if changes: |
||||
|
self.env['res.partner.changeset'].create({ |
||||
|
'partner_id': record.id, |
||||
|
'change_ids': [(0, 0, vals) for vals in changes], |
||||
|
'date': fields.Datetime.now(), |
||||
|
'source': source, |
||||
|
}) |
||||
|
return write_values |
||||
|
|
||||
|
|
||||
|
class ResPartnerChangesetChange(models.Model): |
||||
|
""" Store the change of one field for one changeset on one partner |
||||
|
|
||||
|
This model is composed of 3 sets of fields: |
||||
|
|
||||
|
* 'origin' |
||||
|
* 'old' |
||||
|
* 'new' |
||||
|
|
||||
|
The 'new' fields contain the value that needs to be validated. |
||||
|
The 'old' field copies the actual value of the partner when the |
||||
|
change is either applied either canceled. This field is used as a storage |
||||
|
place but never shown by itself. |
||||
|
The 'origin' fields is a related field towards the actual values of |
||||
|
the partner until the change is either applied either canceled, past |
||||
|
that it shows the 'old' value. |
||||
|
The reason behind this is that the values may change on a partner between |
||||
|
the moment when the changeset is created and when it is applied. |
||||
|
|
||||
|
On the views, we show the origin fields which represent the actual |
||||
|
partner values or the old values and we show the new fields. |
||||
|
|
||||
|
The 'origin' and 'new_value_display' are displayed on |
||||
|
the tree view where we need a unique of field, the other fields are |
||||
|
displayed on the form view so we benefit from their widgets. |
||||
|
|
||||
|
""" |
||||
|
_name = 'res.partner.changeset.change' |
||||
|
_description = 'Partner Changeset Change' |
||||
|
_rec_name = 'field_id' |
||||
|
|
||||
|
changeset_id = fields.Many2one(comodel_name='res.partner.changeset', |
||||
|
required=True, |
||||
|
string='Changeset', |
||||
|
ondelete='cascade', |
||||
|
readonly=True) |
||||
|
field_id = fields.Many2one(comodel_name='ir.model.fields', |
||||
|
string='Field', |
||||
|
required=True, |
||||
|
readonly=True) |
||||
|
field_type = fields.Selection(related='field_id.ttype', |
||||
|
string='Field Type', |
||||
|
readonly=True) |
||||
|
|
||||
|
origin_value_display = fields.Char( |
||||
|
string='Previous', |
||||
|
compute='_compute_value_display', |
||||
|
) |
||||
|
new_value_display = fields.Char( |
||||
|
string='New', |
||||
|
compute='_compute_value_display', |
||||
|
) |
||||
|
|
||||
|
# Fields showing the origin partner's value or the 'old' value if |
||||
|
# the change is applied or canceled. |
||||
|
origin_value_char = fields.Char(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_date = fields.Date(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_datetime = fields.Datetime(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_float = fields.Float(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_integer = fields.Integer(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_text = fields.Text(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_boolean = fields.Boolean(compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
readonly=True) |
||||
|
origin_value_reference = fields.Reference( |
||||
|
compute='_compute_origin_values', |
||||
|
string='Previous', |
||||
|
selection='_reference_models', |
||||
|
readonly=True, |
||||
|
) |
||||
|
|
||||
|
# Fields storing the previous partner's values (saved when the |
||||
|
# changeset is applied) |
||||
|
old_value_char = fields.Char(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_date = fields.Date(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_datetime = fields.Datetime(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_float = fields.Float(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_integer = fields.Integer(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_text = fields.Text(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_boolean = fields.Boolean(string='Old', |
||||
|
readonly=True) |
||||
|
old_value_reference = fields.Reference(string='Old', |
||||
|
selection='_reference_models', |
||||
|
readonly=True) |
||||
|
|
||||
|
# Fields storing the value applied on the partner |
||||
|
new_value_char = fields.Char(string='New', |
||||
|
readonly=True) |
||||
|
new_value_date = fields.Date(string='New', |
||||
|
readonly=True) |
||||
|
new_value_datetime = fields.Datetime(string='New', |
||||
|
readonly=True) |
||||
|
new_value_float = fields.Float(string='New', |
||||
|
readonly=True) |
||||
|
new_value_integer = fields.Integer(string='New', |
||||
|
readonly=True) |
||||
|
new_value_text = fields.Text(string='New', |
||||
|
readonly=True) |
||||
|
new_value_boolean = fields.Boolean(string='New', |
||||
|
readonly=True) |
||||
|
new_value_reference = fields.Reference(string='New', |
||||
|
selection='_reference_models', |
||||
|
readonly=True) |
||||
|
|
||||
|
state = fields.Selection( |
||||
|
selection=[('draft', 'Pending'), |
||||
|
('done', 'Accepted'), |
||||
|
('cancel', 'Rejected'), |
||||
|
], |
||||
|
required=True, |
||||
|
default='draft', |
||||
|
readonly=True, |
||||
|
) |
||||
|
|
||||
|
@api.model |
||||
|
def _reference_models(self): |
||||
|
models = self.env['ir.model'].search([]) |
||||
|
return [(model.model, model.name) for model in models] |
||||
|
|
||||
|
_suffix_to_types = { |
||||
|
'char': ('char', 'selection'), |
||||
|
'date': ('date',), |
||||
|
'datetime': ('datetime',), |
||||
|
'float': ('float',), |
||||
|
'integer': ('integer',), |
||||
|
'text': ('text',), |
||||
|
'boolean': ('boolean',), |
||||
|
'reference': ('many2one',), |
||||
|
} |
||||
|
|
||||
|
_type_to_suffix = {ftype: suffix |
||||
|
for suffix, ftypes in _suffix_to_types.iteritems() |
||||
|
for ftype in ftypes} |
||||
|
|
||||
|
_origin_value_fields = ['origin_value_%s' % suffix |
||||
|
for suffix in _suffix_to_types] |
||||
|
_old_value_fields = ['old_value_%s' % suffix |
||||
|
for suffix in _suffix_to_types] |
||||
|
_new_value_fields = ['new_value_%s' % suffix |
||||
|
for suffix in _suffix_to_types] |
||||
|
_value_fields = (_origin_value_fields + |
||||
|
_old_value_fields + |
||||
|
_new_value_fields) |
||||
|
|
||||
|
@api.one |
||||
|
@api.depends('changeset_id.partner_id') |
||||
|
def _compute_origin_values(self): |
||||
|
field_name = self.get_field_for_type(self.field_id, 'origin') |
||||
|
if self.state == 'draft': |
||||
|
value = self.changeset_id.partner_id[self.field_id.name] |
||||
|
else: |
||||
|
old_field = self.get_field_for_type(self.field_id, 'old') |
||||
|
value = self[old_field] |
||||
|
setattr(self, field_name, value) |
||||
|
|
||||
|
@api.one |
||||
|
@api.depends(lambda self: self._value_fields) |
||||
|
def _compute_value_display(self): |
||||
|
for prefix in ('origin', 'new'): |
||||
|
value = getattr(self, 'get_%s_value' % prefix)() |
||||
|
if self.field_id.ttype == 'many2one' and value: |
||||
|
value = value.display_name |
||||
|
setattr(self, '%s_value_display' % prefix, value) |
||||
|
|
||||
|
@api.model |
||||
|
def get_field_for_type(self, field, prefix): |
||||
|
assert prefix in ('origin', 'old', 'new') |
||||
|
field_type = self._type_to_suffix.get(field.ttype) |
||||
|
if not field_type: |
||||
|
raise NotImplementedError( |
||||
|
'field type %s is not supported' % field_type |
||||
|
) |
||||
|
return '%s_value_%s' % (prefix, field_type) |
||||
|
|
||||
|
@api.multi |
||||
|
def get_origin_value(self): |
||||
|
self.ensure_one() |
||||
|
field_name = self.get_field_for_type(self.field_id, 'origin') |
||||
|
return self[field_name] |
||||
|
|
||||
|
@api.multi |
||||
|
def get_new_value(self): |
||||
|
self.ensure_one() |
||||
|
field_name = self.get_field_for_type(self.field_id, 'new') |
||||
|
return self[field_name] |
||||
|
|
||||
|
@api.multi |
||||
|
def set_old_value(self): |
||||
|
""" Copy the value of the partner to the 'old' field """ |
||||
|
for change in self: |
||||
|
# copy the existing partner's value for the history |
||||
|
old_value_for_write = self._value_for_changeset( |
||||
|
change.changeset_id.partner_id, |
||||
|
change.field_id.name |
||||
|
) |
||||
|
old_field_name = self.get_field_for_type(change.field_id, 'old') |
||||
|
change.write({old_field_name: old_value_for_write}) |
||||
|
|
||||
|
@api.multi |
||||
|
def apply(self): |
||||
|
""" Apply the change on the changeset's partner |
||||
|
|
||||
|
It is optimized thus that it makes only one write on the partner |
||||
|
per changeset if many changes are applied at once. |
||||
|
""" |
||||
|
changes_ok = self.browse() |
||||
|
key = attrgetter('changeset_id') |
||||
|
for changeset, changes in groupby(self.sorted(key=key), key=key): |
||||
|
values = {} |
||||
|
partner = changeset.partner_id |
||||
|
for change in changes: |
||||
|
if change.state in ('cancel', 'done'): |
||||
|
continue |
||||
|
|
||||
|
field = change.field_id |
||||
|
value_for_write = change._convert_value_for_write( |
||||
|
change.get_new_value() |
||||
|
) |
||||
|
values[field.name] = value_for_write |
||||
|
|
||||
|
change.set_old_value() |
||||
|
|
||||
|
changes_ok |= change |
||||
|
|
||||
|
if not values: |
||||
|
continue |
||||
|
|
||||
|
previous_changesets = self.env['res.partner.changeset'].search( |
||||
|
[('date', '<', changeset.date), |
||||
|
('state', '=', 'draft'), |
||||
|
('partner_id', '=', changeset.partner_id.id), |
||||
|
], |
||||
|
limit=1, |
||||
|
) |
||||
|
if previous_changesets: |
||||
|
raise exceptions.Warning( |
||||
|
_('This change cannot be applied because a previous ' |
||||
|
'changeset for the same partner is pending.\n' |
||||
|
'Apply all the anterior changesets before applying ' |
||||
|
'this one.') |
||||
|
) |
||||
|
|
||||
|
partner.with_context(__no_changeset=True).write(values) |
||||
|
|
||||
|
changes_ok.write({'state': 'done'}) |
||||
|
|
||||
|
@api.multi |
||||
|
def cancel(self): |
||||
|
""" Reject the change """ |
||||
|
if any(change.state == 'done' for change in self): |
||||
|
raise exceptions.Warning( |
||||
|
_('This change has already be applied.') |
||||
|
) |
||||
|
self.set_old_value() |
||||
|
self.write({'state': 'cancel'}) |
||||
|
|
||||
|
@api.model |
||||
|
def _has_field_changed(self, record, field, value): |
||||
|
field_def = record._fields[field] |
||||
|
current_value = field_def.convert_to_write(record[field]) |
||||
|
if not (current_value or value): |
||||
|
return False |
||||
|
return current_value != value |
||||
|
|
||||
|
@api.multi |
||||
|
def _convert_value_for_write(self, value): |
||||
|
if not value: |
||||
|
return value |
||||
|
model = self.env[self.field_id.model_id.model] |
||||
|
model_field_def = model._fields[self.field_id.name] |
||||
|
return model_field_def.convert_to_write(value) |
||||
|
|
||||
|
@api.model |
||||
|
def _value_for_changeset(self, record, field_name, value=_NO_VALUE): |
||||
|
""" Return a value from the record ready to write in a changeset field |
||||
|
|
||||
|
:param record: modified record |
||||
|
:param field_name: name of the modified field |
||||
|
:param value: if no value is given, it is read from the record |
||||
|
""" |
||||
|
field_def = record._fields[field_name] |
||||
|
if value is _NO_VALUE: |
||||
|
# when the value is read from the record, we need to prepare |
||||
|
# it for the write (e.g. extract .id from a many2one record) |
||||
|
value = field_def.convert_to_write(record[field_name]) |
||||
|
if field_def.type == 'many2one': |
||||
|
# store as 'reference' |
||||
|
comodel = field_def.comodel_name |
||||
|
return "%s,%s" % (comodel, value) if value else False |
||||
|
else: |
||||
|
return value |
||||
|
|
||||
|
@api.multi |
||||
|
def _prepare_changeset_change(self, record, rule, field_name, value): |
||||
|
""" Prepare data for a changeset change |
||||
|
|
||||
|
It returns a dict of the values to write on the changeset change |
||||
|
and a boolean that indicates if the value should be popped out |
||||
|
of the values to write on the model. |
||||
|
|
||||
|
:returns: dict of values, boolean |
||||
|
""" |
||||
|
new_field_name = self.get_field_for_type(rule.field_id, 'new') |
||||
|
new_value = self._value_for_changeset(record, field_name, value=value) |
||||
|
change = { |
||||
|
new_field_name: new_value, |
||||
|
'field_id': rule.field_id.id, |
||||
|
} |
||||
|
if rule.action == 'auto': |
||||
|
change['state'] = 'done' |
||||
|
pop_value = False |
||||
|
elif rule.action == 'validate': |
||||
|
change['state'] = 'draft' |
||||
|
pop_value = True # change to apply manually |
||||
|
elif rule.action == 'never': |
||||
|
change['state'] = 'cancel' |
||||
|
pop_value = True # change never applied |
||||
|
|
||||
|
if change['state'] in ('cancel', 'done'): |
||||
|
# Normally the 'old' value is set when we use the 'apply' |
||||
|
# button, but since we short circuit the 'apply', we |
||||
|
# directly set the 'old' value here |
||||
|
old_field_name = self.get_field_for_type(rule.field_id, 'old') |
||||
|
# get values ready to write as expected by the changeset |
||||
|
# (for instance, a many2one is written in a reference |
||||
|
# field) |
||||
|
origin_value = self._value_for_changeset(record, field_name) |
||||
|
change[old_field_name] = origin_value |
||||
|
|
||||
|
return change, pop_value |
||||
|
|
||||
|
def fields_view_get(self, *args, **kwargs): |
||||
|
_super = super(ResPartnerChangesetChange, self) |
||||
|
result = _super.fields_view_get(*args, **kwargs) |
||||
|
if result['type'] != 'form': |
||||
|
return |
||||
|
doc = etree.XML(result['arch']) |
||||
|
for suffix, ftypes in self._suffix_to_types.iteritems(): |
||||
|
for prefix in ('origin', 'old', 'new'): |
||||
|
field_name = '%s_value_%s' % (prefix, suffix) |
||||
|
field_nodes = doc.xpath("//field[@name='%s']" % field_name) |
||||
|
for node in field_nodes: |
||||
|
node.set( |
||||
|
'attrs', |
||||
|
"{'invisible': " |
||||
|
"[('field_type', 'not in', %s)]}" % (ftypes,) |
||||
|
) |
||||
|
setup_modifiers(node) |
||||
|
result['arch'] = etree.tostring(doc) |
||||
|
return result |
@ -0,0 +1,10 @@ |
|||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
access_view_changeset_field_rule_partner_manager,changeset field rules for partner managers,model_changeset_field_rule,base.group_partner_manager,1,0,0,0 |
||||
|
access_view_changeset_field_rule_user,changeset field rules for changeset users,model_changeset_field_rule,group_changeset_user,1,0,0,0 |
||||
|
access_view_changeset_field_rule_manager,changeset field rules for changeset managers,model_changeset_field_rule,group_changeset_user,1,1,1,1 |
||||
|
access_view_res_partner_changeset_partner_manager,changeset for partner managers,model_res_partner_changeset,base.group_partner_manager,1,0,1,0 |
||||
|
access_view_res_partner_changeset_change_partner_manager,changeset change for partner managers,model_res_partner_changeset_change,base.group_partner_manager,1,0,1,0 |
||||
|
access_view_res_partner_changeset_user,changeset for changeset users,model_res_partner_changeset,group_changeset_user,1,1,1,0 |
||||
|
access_view_res_partner_changeset_change_user,changeset change for changeset users,model_res_partner_changeset_change,group_changeset_user,1,1,1,0 |
||||
|
access_view_res_partner_changeset_manager,changeset for changeset managers,model_res_partner_changeset,group_changeset_manager,1,1,1,1 |
||||
|
access_view_res_partner_changeset_change_manager,changeset change for changeset managers,model_res_partner_changeset_change,group_changeset_manager,1,1,1,1 |
@ -0,0 +1,29 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
|
||||
|
<record id="group_changeset_manager" model="res.groups"> |
||||
|
<field name="name">Changeset Configuration</field> |
||||
|
<field name="comment">The user will have an access to the configuration of the changeset rules.</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="group_changeset_user" model="res.groups"> |
||||
|
<field name="name">Changesets Validations </field> |
||||
|
<field name="comment">The user will be able to apply or reject changesets.</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
|
||||
|
<data noupdate="1"> |
||||
|
|
||||
|
<record id="group_changeset_manager" model="res.groups"> |
||||
|
<field name="users" eval="[(4, ref('base.user_root'))]"/> |
||||
|
</record> |
||||
|
|
||||
|
<record id="group_changeset_user" model="res.groups"> |
||||
|
<field name="implied_ids" eval="[(4, ref('group_changeset_manager'))]"/> |
||||
|
<field name="users" eval="[(4, ref('base.user_root'))]"/> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</openerp> |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
After Width: 1252 | Height: 577 | Size: 85 KiB |
After Width: 996 | Height: 557 | Size: 60 KiB |
@ -0,0 +1,6 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import test_changeset_flow |
||||
|
from . import test_changeset_field_type |
||||
|
from . import test_changeset_origin |
||||
|
from . import test_changeset_field_rule |
@ -0,0 +1,77 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
|
||||
|
class ChangesetMixin(object): |
||||
|
|
||||
|
def assert_changeset(self, partner, expected_source, expected_changes): |
||||
|
""" Check if a changeset has been created according to expected values |
||||
|
|
||||
|
The partner should have no prior changeset than the one created in the |
||||
|
test (so it has exactly 1 changeset). |
||||
|
|
||||
|
The expected changes are tuples with (field, origin_value, |
||||
|
new_value, state) |
||||
|
|
||||
|
:param partner: record of partner having a changeset |
||||
|
:param expected_changes: contains tuples with the changes |
||||
|
:type expected_changes: list(tuple)) |
||||
|
""" |
||||
|
changeset = self.env['res.partner.changeset'].search( |
||||
|
[('partner_id', '=', partner.id)], |
||||
|
) |
||||
|
self.assertEqual(len(changeset), 1, |
||||
|
"1 changeset expected, got %s" % (changeset,)) |
||||
|
self.assertEqual(changeset.source, expected_source) |
||||
|
changes = changeset.change_ids |
||||
|
missing = [] |
||||
|
for expected_change in expected_changes: |
||||
|
for change in changes: |
||||
|
if (change.field_id, |
||||
|
change.get_origin_value(), |
||||
|
change.get_new_value(), |
||||
|
change.state) == expected_change: |
||||
|
changes -= change |
||||
|
break |
||||
|
else: |
||||
|
missing.append(expected_change) |
||||
|
message = u'' |
||||
|
for field, origin_value, new_value, state in missing: |
||||
|
message += ("- field: '%s', origin_value: '%s', " |
||||
|
"new_value: '%s', state: '%s'\n" % |
||||
|
(field.name, origin_value, new_value, state)) |
||||
|
for change in changes: |
||||
|
message += ("+ field: '%s', origin_value: '%s', " |
||||
|
"new_value: '%s', state: '%s'\n" % |
||||
|
(change.field_id.name, |
||||
|
change.get_origin_value(), |
||||
|
change.get_new_value(), |
||||
|
change.state)) |
||||
|
if message: |
||||
|
raise AssertionError('Changes do not match\n\n:%s' % message) |
||||
|
|
||||
|
def _create_changeset(self, partner, changes): |
||||
|
""" Create a changeset and its associated changes |
||||
|
|
||||
|
:param partner: 'res.partner' record |
||||
|
:param changes: list of changes [(field, new value, state)] |
||||
|
:returns: 'res.partner.changeset' record |
||||
|
""" |
||||
|
ChangesetChange = self.env['res.partner.changeset.change'] |
||||
|
get_field = ChangesetChange.get_field_for_type |
||||
|
change_values = [] |
||||
|
for field, value, state in changes: |
||||
|
change = { |
||||
|
'field_id': field.id, |
||||
|
# write in the field of the appropriate type for the |
||||
|
# origin field (char, many2one, ...) |
||||
|
get_field(field, 'new'): value, |
||||
|
'state': state, |
||||
|
} |
||||
|
change_values.append((0, 0, change)) |
||||
|
values = { |
||||
|
'partner_id': partner.id, |
||||
|
'change_ids': change_values, |
||||
|
} |
||||
|
return self.env['res.partner.changeset'].create(values) |
@ -0,0 +1,78 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from openerp.tests import common |
||||
|
|
||||
|
|
||||
|
class TestChangesetFieldRule(common.TransactionCase): |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestChangesetFieldRule, self).setUp() |
||||
|
self.company_model_id = self.env.ref('base.model_res_company').id |
||||
|
self.field_name = self.env.ref('base.field_res_partner_name') |
||||
|
self.field_street = self.env.ref('base.field_res_partner_street') |
||||
|
|
||||
|
def test_get_rules(self): |
||||
|
ChangesetFieldRule = self.env['changeset.field.rule'] |
||||
|
ChangesetFieldRule.search([]).unlink() |
||||
|
rule1 = ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_name.id, |
||||
|
'action': 'validate', |
||||
|
}) |
||||
|
rule2 = ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_street.id, |
||||
|
'action': 'never', |
||||
|
}) |
||||
|
get_rules = ChangesetFieldRule.get_rules(None) |
||||
|
self.assertEqual(get_rules, {'name': rule1, 'street': rule2}) |
||||
|
|
||||
|
def test_get_rules_source(self): |
||||
|
ChangesetFieldRule = self.env['changeset.field.rule'] |
||||
|
ChangesetFieldRule.search([]).unlink() |
||||
|
rule1 = ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_name.id, |
||||
|
'action': 'validate', |
||||
|
}) |
||||
|
rule2 = ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_street.id, |
||||
|
'action': 'never', |
||||
|
}) |
||||
|
rule3 = ChangesetFieldRule.create({ |
||||
|
'source_model_id': self.company_model_id, |
||||
|
'field_id': self.field_street.id, |
||||
|
'action': 'never', |
||||
|
}) |
||||
|
model = ChangesetFieldRule |
||||
|
rules = model.get_rules(None) |
||||
|
self.assertEqual(rules, {u'name': rule1, u'street': rule2}) |
||||
|
rules = model.get_rules('res.company') |
||||
|
self.assertEqual(rules, {u'name': rule1, u'street': rule3}) |
||||
|
|
||||
|
def test_get_rules_cache(self): |
||||
|
ChangesetFieldRule = self.env['changeset.field.rule'] |
||||
|
ChangesetFieldRule.search([]).unlink() |
||||
|
rule = ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_name.id, |
||||
|
'action': 'validate', |
||||
|
}) |
||||
|
self.assertEqual( |
||||
|
ChangesetFieldRule.get_rules(None)['name'].action, |
||||
|
'validate', |
||||
|
) |
||||
|
# Write on cursor to bypass the cache invalidation for the |
||||
|
# matter of the test |
||||
|
self.env.cr.execute("UPDATE changeset_field_rule " |
||||
|
"SET action = 'never' " |
||||
|
"WHERE id = %s", (rule.id,)) |
||||
|
self.assertEqual( |
||||
|
ChangesetFieldRule.get_rules(None)['name'].action, |
||||
|
'validate', |
||||
|
) |
||||
|
rule.action = 'auto' |
||||
|
self.assertEqual( |
||||
|
ChangesetFieldRule.get_rules(None)['name'].action, |
||||
|
'auto', |
||||
|
) |
||||
|
rule.unlink() |
||||
|
self.assertFalse(ChangesetFieldRule.get_rules(None)) |
@ -0,0 +1,281 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from openerp.tests import common |
||||
|
from .common import ChangesetMixin |
||||
|
|
||||
|
|
||||
|
class TestChangesetFieldType(ChangesetMixin, common.TransactionCase): |
||||
|
""" Check that changeset changes are stored expectingly to their types """ |
||||
|
|
||||
|
def _setup_rules(self): |
||||
|
ChangesetFieldRule = self.env['changeset.field.rule'] |
||||
|
ChangesetFieldRule.search([]).unlink() |
||||
|
fields = (('char', 'ref'), |
||||
|
('text', 'comment'), |
||||
|
('boolean', 'customer'), |
||||
|
('date', 'date'), |
||||
|
('integer', 'color'), |
||||
|
('float', 'credit_limit'), |
||||
|
('selection', 'type'), |
||||
|
('many2one', 'country_id'), |
||||
|
('many2many', 'category_id'), |
||||
|
('one2many', 'user_ids'), |
||||
|
('binary', 'image'), |
||||
|
) |
||||
|
for field_type, field in fields: |
||||
|
attr_name = 'field_%s' % field_type |
||||
|
field_record = self.env['ir.model.fields'].search([ |
||||
|
('model', '=', 'res.partner'), |
||||
|
('name', '=', field), |
||||
|
]) |
||||
|
# set attribute such as 'self.field_char' is a |
||||
|
# ir.model.fields record of the field res_partner.ref |
||||
|
setattr(self, attr_name, field_record) |
||||
|
ChangesetFieldRule.create({ |
||||
|
'field_id': field_record.id, |
||||
|
'action': 'validate', |
||||
|
}) |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestChangesetFieldType, self).setUp() |
||||
|
self._setup_rules() |
||||
|
self.partner = self.env['res.partner'].create({ |
||||
|
'name': 'Original Name', |
||||
|
'street': 'Original Street', |
||||
|
}) |
||||
|
|
||||
|
def test_new_changeset_char(self): |
||||
|
""" Add a new changeset on a Char field """ |
||||
|
self.partner.write({ |
||||
|
self.field_char.name: 'New value', |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_char, self.partner[self.field_char.name], |
||||
|
'New value', 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_text(self): |
||||
|
""" Add a new changeset on a Text field """ |
||||
|
self.partner.write({ |
||||
|
self.field_text.name: 'New comment\non 2 lines', |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_text, self.partner[self.field_text.name], |
||||
|
'New comment\non 2 lines', 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_boolean(self): |
||||
|
""" Add a new changeset on a Boolean field """ |
||||
|
# ensure the changeset has to change the value |
||||
|
self.partner.with_context(__no_changeset=True).write({ |
||||
|
self.field_boolean.name: False, |
||||
|
}) |
||||
|
|
||||
|
self.partner.write({ |
||||
|
self.field_boolean.name: True, |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_boolean, self.partner[self.field_boolean.name], |
||||
|
True, 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_date(self): |
||||
|
""" Add a new changeset on a Date field """ |
||||
|
self.partner.write({ |
||||
|
self.field_date.name: '2015-09-15', |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_date, self.partner[self.field_date.name], |
||||
|
'2015-09-15', 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_integer(self): |
||||
|
""" Add a new changeset on a Integer field """ |
||||
|
self.partner.write({ |
||||
|
self.field_integer.name: 42, |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_integer, self.partner[self.field_integer.name], |
||||
|
42, 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_float(self): |
||||
|
""" Add a new changeset on a Float field """ |
||||
|
self.partner.write({ |
||||
|
self.field_float.name: 3.1415, |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_float, self.partner[self.field_float.name], |
||||
|
3.1415, 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_selection(self): |
||||
|
""" Add a new changeset on a Selection field """ |
||||
|
self.partner.write({ |
||||
|
self.field_selection.name: 'delivery', |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_selection, self.partner[self.field_selection.name], |
||||
|
'delivery', 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_many2one(self): |
||||
|
""" Add a new changeset on a Many2one field """ |
||||
|
self.partner.with_context(__no_changeset=True).write({ |
||||
|
self.field_many2one.name: self.env.ref('base.fr').id, |
||||
|
|
||||
|
}) |
||||
|
self.partner.write({ |
||||
|
self.field_many2one.name: self.env.ref('base.ch').id, |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_many2one, self.partner[self.field_many2one.name], |
||||
|
self.env.ref('base.ch'), 'draft'), |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
def test_new_changeset_many2many(self): |
||||
|
""" Add a new changeset on a Many2many field is not supported """ |
||||
|
with self.assertRaises(NotImplementedError): |
||||
|
self.partner.write({ |
||||
|
self.field_many2many.name: [self.env.ref('base.ch').id], |
||||
|
}) |
||||
|
|
||||
|
def test_new_changeset_one2many(self): |
||||
|
""" Add a new changeset on a One2many field is not supported """ |
||||
|
with self.assertRaises(NotImplementedError): |
||||
|
self.partner.write({ |
||||
|
self.field_one2many.name: [self.env.ref('base.user_root').id], |
||||
|
}) |
||||
|
|
||||
|
def test_new_changeset_binary(self): |
||||
|
""" Add a new changeset on a Binary field is not supported """ |
||||
|
with self.assertRaises(NotImplementedError): |
||||
|
self.partner.write({ |
||||
|
self.field_binary.name: 'xyz', |
||||
|
}) |
||||
|
|
||||
|
def test_apply_char(self): |
||||
|
""" Apply a change on a Char field """ |
||||
|
changes = [(self.field_char, 'New Ref', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner[self.field_char.name], 'New Ref') |
||||
|
|
||||
|
def test_apply_text(self): |
||||
|
""" Apply a change on a Text field """ |
||||
|
changes = [(self.field_text, 'New comment\non 2 lines', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner[self.field_text.name], |
||||
|
'New comment\non 2 lines') |
||||
|
|
||||
|
def test_apply_boolean(self): |
||||
|
""" Apply a change on a Boolean field """ |
||||
|
# ensure the changeset has to change the value |
||||
|
self.partner.write({self.field_boolean.name: False}) |
||||
|
|
||||
|
changes = [(self.field_boolean, True, 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner[self.field_boolean.name], True) |
||||
|
|
||||
|
# Cannot do this while it is on the same transaction. The cache may not |
||||
|
# be updated |
||||
|
# changes = [(self.field_boolean, False, 'draft')] |
||||
|
# changeset = self._create_changeset(self.partner, changes) |
||||
|
# changeset.change_ids.apply() |
||||
|
# self.assertEqual(self.partner[self.field_boolean.name], False) |
||||
|
|
||||
|
def test_apply_date(self): |
||||
|
""" Apply a change on a Date field """ |
||||
|
changes = [(self.field_date, '2015-09-15', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertAlmostEqual(self.partner[self.field_date.name], |
||||
|
'2015-09-15') |
||||
|
|
||||
|
def test_apply_integer(self): |
||||
|
""" Apply a change on a Integer field """ |
||||
|
changes = [(self.field_integer, 42, 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertAlmostEqual(self.partner[self.field_integer.name], 42) |
||||
|
|
||||
|
def test_apply_float(self): |
||||
|
""" Apply a change on a Float field """ |
||||
|
changes = [(self.field_float, 52.47, 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertAlmostEqual(self.partner[self.field_float.name], 52.47) |
||||
|
|
||||
|
def test_apply_selection(self): |
||||
|
""" Apply a change on a Selection field """ |
||||
|
changes = [(self.field_selection, 'delivery', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertAlmostEqual(self.partner[self.field_selection.name], |
||||
|
'delivery') |
||||
|
|
||||
|
def test_apply_many2one(self): |
||||
|
""" Apply a change on a Many2one field """ |
||||
|
self.partner.with_context(__no_changeset=True).write({ |
||||
|
self.field_many2one.name: self.env.ref('base.fr').id, |
||||
|
|
||||
|
}) |
||||
|
changes = [(self.field_many2one, |
||||
|
'res.country,%d' % self.env.ref('base.ch').id, |
||||
|
'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner[self.field_many2one.name], |
||||
|
self.env.ref('base.ch')) |
||||
|
|
||||
|
def test_apply_many2many(self): |
||||
|
""" Apply a change on a Many2many field is not supported """ |
||||
|
changes = [(self.field_many2many, |
||||
|
self.env.ref('base.ch').id, |
||||
|
'draft')] |
||||
|
with self.assertRaises(NotImplementedError): |
||||
|
self._create_changeset(self.partner, changes) |
||||
|
|
||||
|
def test_apply_one2many(self): |
||||
|
""" Apply a change on a One2many field is not supported """ |
||||
|
changes = [(self.field_one2many, |
||||
|
[self.env.ref('base.user_root').id, |
||||
|
self.env.ref('base.user_demo').id, |
||||
|
], |
||||
|
'draft')] |
||||
|
with self.assertRaises(NotImplementedError): |
||||
|
self._create_changeset(self.partner, changes) |
||||
|
|
||||
|
def test_apply_binary(self): |
||||
|
""" Apply a change on a Binary field is not supported """ |
||||
|
changes = [(self.field_one2many, '', 'draft')] |
||||
|
with self.assertRaises(NotImplementedError): |
||||
|
self._create_changeset(self.partner, changes) |
@ -0,0 +1,246 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from datetime import datetime, timedelta |
||||
|
|
||||
|
from openerp import fields, exceptions |
||||
|
from openerp.tests import common |
||||
|
from .common import ChangesetMixin |
||||
|
|
||||
|
|
||||
|
class TestChangesetFlow(ChangesetMixin, common.TransactionCase): |
||||
|
""" Check how changeset are generated and applied based on the rules. |
||||
|
|
||||
|
We do not really care about the types of the fields in this test |
||||
|
suite, so we only use 'char' fields. We have to ensure that the |
||||
|
general changeset flows work as expected, that is: |
||||
|
|
||||
|
* create a changeset when a manual/system write is made on partner |
||||
|
* create a changeset according to the changeset rules when a source model |
||||
|
is specified |
||||
|
* apply a changeset change writes the value on the partner |
||||
|
* apply a whole changeset writes all the changes' values on the partner |
||||
|
* changes in state 'cancel' or 'done' do not write on the partner |
||||
|
* when all the changes are either 'cancel' or 'done', the changeset |
||||
|
becomes 'done' |
||||
|
""" |
||||
|
|
||||
|
def _setup_rules(self): |
||||
|
ChangesetFieldRule = self.env['changeset.field.rule'] |
||||
|
ChangesetFieldRule.search([]).unlink() |
||||
|
self.field_name = self.env.ref('base.field_res_partner_name') |
||||
|
self.field_street = self.env.ref('base.field_res_partner_street') |
||||
|
self.field_street2 = self.env.ref('base.field_res_partner_street2') |
||||
|
ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_name.id, |
||||
|
'action': 'auto', |
||||
|
}) |
||||
|
ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_street.id, |
||||
|
'action': 'validate', |
||||
|
}) |
||||
|
ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_street2.id, |
||||
|
'action': 'never', |
||||
|
}) |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestChangesetFlow, self).setUp() |
||||
|
self._setup_rules() |
||||
|
self.partner = self.env['res.partner'].create({ |
||||
|
'name': 'X', |
||||
|
'street': 'street X', |
||||
|
'street2': 'street2 X', |
||||
|
}) |
||||
|
|
||||
|
def test_new_changeset(self): |
||||
|
""" Add a new changeset on a partner |
||||
|
|
||||
|
A new changeset is created when we write on a partner |
||||
|
""" |
||||
|
self.partner.write({ |
||||
|
'name': 'Y', |
||||
|
'street': 'street Y', |
||||
|
'street2': 'street2 Y', |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_name, 'X', 'Y', 'done'), |
||||
|
(self.field_street, 'street X', 'street Y', 'draft'), |
||||
|
(self.field_street2, 'street2 X', 'street2 Y', 'cancel'), |
||||
|
], |
||||
|
) |
||||
|
self.assertEqual(self.partner.name, 'Y') |
||||
|
self.assertEqual(self.partner.street, 'street X') |
||||
|
self.assertEqual(self.partner.street2, 'street2 X') |
||||
|
|
||||
|
def test_new_changeset_empty_value(self): |
||||
|
""" Create a changeset change that empty a value """ |
||||
|
self.partner.write({ |
||||
|
'street': False, |
||||
|
}) |
||||
|
self.assert_changeset( |
||||
|
self.partner, |
||||
|
self.env.user, |
||||
|
[(self.field_street, 'street X', False, 'draft')] |
||||
|
) |
||||
|
|
||||
|
def test_no_changeset_empty_value_both_sides(self): |
||||
|
""" No changeset created when both sides have an empty value """ |
||||
|
# we have to ensure that even if we write '' to a False field, we won't |
||||
|
# write a changeset |
||||
|
self.partner.with_context(__no_changeset=True).write({ |
||||
|
'street': False, |
||||
|
}) |
||||
|
self.partner.write({ |
||||
|
'street': '', |
||||
|
}) |
||||
|
self.assertFalse(self.partner.changeset_ids) |
||||
|
|
||||
|
def test_apply_change(self): |
||||
|
""" Apply a changeset change on a partner """ |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'draft'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner.name, 'Y') |
||||
|
self.assertEqual(changeset.change_ids.state, 'done') |
||||
|
|
||||
|
def test_apply_done_change(self): |
||||
|
""" Done changes do not apply (already applied) """ |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'done'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner.name, 'X') |
||||
|
|
||||
|
def test_apply_cancel_change(self): |
||||
|
""" Cancel changes do not apply """ |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'cancel'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner.name, 'X') |
||||
|
|
||||
|
def test_apply_empty_value(self): |
||||
|
""" Apply a change that empty a value """ |
||||
|
changes = [ |
||||
|
(self.field_street, False, 'draft'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertFalse(self.partner.street) |
||||
|
|
||||
|
def test_apply_change_loop(self): |
||||
|
""" Test @api.multi on the changes """ |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'draft'), |
||||
|
(self.field_street, 'street Y', 'draft'), |
||||
|
(self.field_street2, 'street2 Y', 'draft'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(self.partner.name, 'Y') |
||||
|
self.assertEqual(self.partner.street, 'street Y') |
||||
|
self.assertEqual(self.partner.street2, 'street2 Y') |
||||
|
|
||||
|
def test_apply(self): |
||||
|
""" Apply a full changeset on a partner """ |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'draft'), |
||||
|
(self.field_street, 'street Y', 'draft'), |
||||
|
(self.field_street2, 'street2 Y', 'draft'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
changeset.apply() |
||||
|
self.assertEqual(self.partner.name, 'Y') |
||||
|
self.assertEqual(self.partner.street, 'street Y') |
||||
|
self.assertEqual(self.partner.street2, 'street2 Y') |
||||
|
|
||||
|
def test_changeset_state_on_done(self): |
||||
|
""" Check that changeset state becomes done when changes are done """ |
||||
|
changes = [(self.field_name, 'Y', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
self.assertEqual(changeset.state, 'draft') |
||||
|
changeset.change_ids.apply() |
||||
|
self.assertEqual(changeset.state, 'done') |
||||
|
|
||||
|
def test_changeset_state_on_cancel(self): |
||||
|
""" Check that rev. state becomes done when changes are canceled """ |
||||
|
changes = [(self.field_name, 'Y', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
self.assertEqual(changeset.state, 'draft') |
||||
|
changeset.change_ids.cancel() |
||||
|
self.assertEqual(changeset.state, 'done') |
||||
|
|
||||
|
def test_changeset_state(self): |
||||
|
""" Check that changeset state becomes done with multiple changes """ |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'draft'), |
||||
|
(self.field_street, 'street Y', 'draft'), |
||||
|
(self.field_street2, 'street2 Y', 'draft'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
self.assertEqual(changeset.state, 'draft') |
||||
|
changeset.apply() |
||||
|
self.assertEqual(changeset.state, 'done') |
||||
|
|
||||
|
def test_apply_changeset_with_other_pending(self): |
||||
|
""" Error when applying when previous pending changesets exist """ |
||||
|
changes = [(self.field_name, 'Y', 'draft')] |
||||
|
old_changeset = self._create_changeset(self.partner, changes) |
||||
|
# if the date is the same, both changeset can be applied |
||||
|
to_string = fields.Datetime.to_string |
||||
|
old_changeset.date = to_string(datetime.now() - timedelta(days=1)) |
||||
|
changes = [(self.field_name, 'Z', 'draft')] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
with self.assertRaises(exceptions.Warning): |
||||
|
changeset.change_ids.apply() |
||||
|
|
||||
|
def test_apply_different_changesets(self): |
||||
|
""" Apply different changesets at once """ |
||||
|
partner2 = self.env['res.partner'].create({'name': 'P2'}) |
||||
|
changes = [ |
||||
|
(self.field_name, 'Y', 'draft'), |
||||
|
(self.field_street, 'street Y', 'draft'), |
||||
|
(self.field_street2, 'street2 Y', 'draft'), |
||||
|
] |
||||
|
changeset = self._create_changeset(self.partner, changes) |
||||
|
self.assertEqual(self.partner.count_pending_changesets, 1) |
||||
|
changeset2 = self._create_changeset(partner2, changes) |
||||
|
self.assertEqual(changeset.state, 'draft') |
||||
|
self.assertEqual(changeset2.state, 'draft') |
||||
|
(changeset + changeset2).apply() |
||||
|
self.assertEqual(self.partner.name, 'Y') |
||||
|
self.assertEqual(self.partner.street, 'street Y') |
||||
|
self.assertEqual(self.partner.street2, 'street2 Y') |
||||
|
self.assertEqual(partner2.name, 'Y') |
||||
|
self.assertEqual(partner2.street, 'street Y') |
||||
|
self.assertEqual(partner2.street2, 'street2 Y') |
||||
|
self.assertEqual(changeset.state, 'done') |
||||
|
self.assertEqual(changeset2.state, 'done') |
||||
|
|
||||
|
def test_new_changeset_source(self): |
||||
|
""" Source is the user who made the change """ |
||||
|
self.partner.write({ |
||||
|
'street': False, |
||||
|
}) |
||||
|
changeset = self.partner.changeset_ids |
||||
|
self.assertEqual(changeset.source, self.env.user) |
||||
|
|
||||
|
def test_new_changeset_source_other_model(self): |
||||
|
""" Define source from another model """ |
||||
|
company = self.env.ref('base.main_company') |
||||
|
keys = { |
||||
|
'__changeset_rules_source_model': 'res.company', |
||||
|
'__changeset_rules_source_id': company.id, |
||||
|
} |
||||
|
self.partner.with_context(**keys).write({ |
||||
|
'street': False, |
||||
|
}) |
||||
|
changeset = self.partner.changeset_ids |
||||
|
self.assertEqual(changeset.source, company) |
@ -0,0 +1,118 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015-2016 Camptocamp SA |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
from openerp.tests import common |
||||
|
from .common import ChangesetMixin |
||||
|
|
||||
|
|
||||
|
class TestChangesetOrigin(ChangesetMixin, common.TransactionCase): |
||||
|
""" Check that origin - old fields are stored as expected. |
||||
|
|
||||
|
'origin' fields dynamically read fields from the partner when the state |
||||
|
of the change is 'draft'. Once a change becomes 'done' or 'cancel', the |
||||
|
'old' field copies the value from the partner and then the 'origin' field |
||||
|
displays the 'old' value. |
||||
|
""" |
||||
|
|
||||
|
def _setup_rules(self): |
||||
|
ChangesetFieldRule = self.env['changeset.field.rule'] |
||||
|
ChangesetFieldRule.search([]).unlink() |
||||
|
self.field_name = self.env.ref('base.field_res_partner_name') |
||||
|
ChangesetFieldRule.create({ |
||||
|
'field_id': self.field_name.id, |
||||
|
'action': 'validate', |
||||
|
}) |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestChangesetOrigin, self).setUp() |
||||
|
self._setup_rules() |
||||
|
self.partner = self.env['res.partner'].create({ |
||||
|
'name': 'X', |
||||
|
}) |
||||
|
|
||||
|
def test_origin_value_of_change_with_apply(self): |
||||
|
""" Origin field is read from the parter or 'old' - with apply |
||||
|
|
||||
|
According to the state of the change. |
||||
|
""" |
||||
|
self.partner.write({ |
||||
|
'name': 'Y', |
||||
|
}) |
||||
|
changeset = self.partner.changeset_ids |
||||
|
change = changeset.change_ids |
||||
|
self.assertEqual(self.partner.name, 'X') |
||||
|
self.assertEqual(change.origin_value_char, 'X') |
||||
|
self.assertEqual(change.origin_value_display, 'X') |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'A'}) |
||||
|
# depends cannot trigger all fileds from partner. In real use case, |
||||
|
# the user will probably be in different transaction, he will get the |
||||
|
# new value of the field |
||||
|
self.partner.invalidate_cache() |
||||
|
self.assertEqual(change.origin_value_char, 'A') |
||||
|
self.assertEqual(change.origin_value_display, 'A') |
||||
|
change.apply() |
||||
|
self.assertEqual(change.origin_value_char, 'A') |
||||
|
self.assertEqual(change.origin_value_display, 'A') |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'B'}) |
||||
|
self.assertEqual(change.origin_value_char, 'A') |
||||
|
self.assertEqual(change.origin_value_display, 'A') |
||||
|
|
||||
|
def test_origin_value_of_change_with_cancel(self): |
||||
|
""" Origin field is read from the parter or 'old' - with cancel |
||||
|
|
||||
|
According to the state of the change. |
||||
|
""" |
||||
|
self.partner.write({ |
||||
|
'name': 'Y', |
||||
|
}) |
||||
|
changeset = self.partner.changeset_ids |
||||
|
change = changeset.change_ids |
||||
|
self.assertEqual(self.partner.name, 'X') |
||||
|
self.assertEqual(change.origin_value_char, 'X') |
||||
|
self.assertEqual(change.origin_value_display, 'X') |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'A'}) |
||||
|
# depends cannot trigger all fileds from partner. In real use case, |
||||
|
# the user will probably be in different transaction, he will get the |
||||
|
# new value of the field |
||||
|
self.partner.invalidate_cache() |
||||
|
self.assertEqual(change.origin_value_char, 'A') |
||||
|
self.assertEqual(change.origin_value_display, 'A') |
||||
|
change.cancel() |
||||
|
self.assertEqual(change.origin_value_char, 'A') |
||||
|
self.assertEqual(change.origin_value_display, 'A') |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'B'}) |
||||
|
self.assertEqual(change.origin_value_char, 'A') |
||||
|
self.assertEqual(change.origin_value_display, 'A') |
||||
|
|
||||
|
def test_old_field_of_change_with_apply(self): |
||||
|
""" Old field is stored when the change is applied """ |
||||
|
self.partner.write({ |
||||
|
'name': 'Y', |
||||
|
}) |
||||
|
changeset = self.partner.changeset_ids |
||||
|
change = changeset.change_ids |
||||
|
self.assertEqual(self.partner.name, 'X') |
||||
|
self.assertFalse(change.old_value_char) |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'A'}) |
||||
|
self.assertFalse(change.old_value_char) |
||||
|
change.apply() |
||||
|
self.assertEqual(change.old_value_char, 'A') |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'B'}) |
||||
|
self.assertEqual(change.old_value_char, 'A') |
||||
|
|
||||
|
def test_old_field_of_change_with_cancel(self): |
||||
|
""" Old field is stored when the change is canceled """ |
||||
|
self.partner.write({ |
||||
|
'name': 'Y', |
||||
|
}) |
||||
|
changeset = self.partner.changeset_ids |
||||
|
change = changeset.change_ids |
||||
|
self.assertEqual(self.partner.name, 'X') |
||||
|
self.assertFalse(change.old_value_char) |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'A'}) |
||||
|
self.assertFalse(change.old_value_char) |
||||
|
change.cancel() |
||||
|
self.assertEqual(change.old_value_char, 'A') |
||||
|
self.partner.with_context(__no_changeset=True).write({'name': 'B'}) |
||||
|
self.assertEqual(change.old_value_char, 'A') |
@ -0,0 +1,61 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<record id="view_changeset_field_rule_tree" model="ir.ui.view"> |
||||
|
<field name="name">changeset.field.rule.tree</field> |
||||
|
<field name="model">changeset.field.rule</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Changeset Fields Rules"> |
||||
|
<field name="field_id"/> |
||||
|
<field name="source_model_id"/> |
||||
|
<field name="action"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_changeset_field_rule_form" model="ir.ui.view"> |
||||
|
<field name="name">changeset.field.rule.form</field> |
||||
|
<field name="model">changeset.field.rule</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Changeset Fields Rules"> |
||||
|
<sheet string="Changeset Fields Rules"> |
||||
|
<group> |
||||
|
<field name="field_id" |
||||
|
options="{'no_create_edit': True, 'no_open': True}" |
||||
|
/> |
||||
|
<field name="action"/> |
||||
|
<field name="source_model_id" |
||||
|
widget="selection" /> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_changeset_field_rule_search" model="ir.ui.view"> |
||||
|
<field name="name">changeset.field.rule.search</field> |
||||
|
<field name="model">changeset.field.rule</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Changeset Fields Rules"> |
||||
|
<field name="field_id"/> |
||||
|
<field name="source_model_id"/> |
||||
|
<field name="action"/> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.actions.act_window" id="action_changeset_field_rule_view"> |
||||
|
<field name="name">Changeset Fields Rules</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">changeset.field.rule</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="search_view_id" ref="view_changeset_field_rule_search"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="menu_changeset_field_rule" |
||||
|
parent="menu_changeset" |
||||
|
name="Field Rules" |
||||
|
groups="group_changeset_manager" |
||||
|
sequence="20" |
||||
|
action="action_changeset_field_rule_view"/> |
||||
|
</odoo> |
@ -0,0 +1,8 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<menuitem id="menu_changeset" |
||||
|
name="Partner Changesets" |
||||
|
groups="group_changeset_user" |
||||
|
parent="base.menu_sales_config" |
||||
|
sequence="20"/> |
||||
|
</odoo> |
@ -0,0 +1,157 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<record id="view_res_partner_changeset_tree" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.changeset.tree</field> |
||||
|
<field name="model">res.partner.changeset</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Partner Changeset" delete="false" create="false"> |
||||
|
<field name="partner_id"/> |
||||
|
<field name="date"/> |
||||
|
<field name="state"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_res_partner_changeset_form" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.changeset.form</field> |
||||
|
<field name="model">res.partner.changeset</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Partner Changeset" delete="false" create="false"> |
||||
|
<header> |
||||
|
<button name="apply" |
||||
|
string="Apply pending changes" type="object" |
||||
|
class="oe_highlight" |
||||
|
states="draft"/> |
||||
|
<button name="cancel" |
||||
|
string="Reject pending changes" type="object" |
||||
|
class="oe_highlight" |
||||
|
states="draft"/> |
||||
|
<field name="state" widget="statusbar" |
||||
|
statusbar_visible="draft,done"/> |
||||
|
</header> |
||||
|
<sheet string="Partner Changeset"> |
||||
|
<group> |
||||
|
<field name="partner_id"/> |
||||
|
<field name="source"/> |
||||
|
<field name="date"/> |
||||
|
</group> |
||||
|
<group string="Changes"> |
||||
|
<field name="change_ids" nolabel="1"> |
||||
|
<tree string="Partner Changeset Change"> |
||||
|
<field name="field_id" context="{'no_open': true}"/> |
||||
|
<field name="field_type" invisible="1"/> |
||||
|
|
||||
|
<field name="origin_value_display" string="Previous"/> |
||||
|
<field name="new_value_display"/> |
||||
|
|
||||
|
<field name="state"/> |
||||
|
<button name="apply" |
||||
|
string="Apply" type="object" |
||||
|
icon="gtk-apply" |
||||
|
states="draft"/> |
||||
|
<button name="cancel" |
||||
|
string="Reject" type="object" |
||||
|
icon="gtk-close" |
||||
|
states="draft"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="note"/> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_res_partner_changeset_change_form" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.changeset.change.form</field> |
||||
|
<field name="model">res.partner.changeset.change</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Partner Changeset Change" delete="false" create="false"> |
||||
|
<header> |
||||
|
<button name="apply" |
||||
|
string="Apply" type="object" |
||||
|
class="oe_highlight" |
||||
|
states="draft"/> |
||||
|
<button name="cancel" |
||||
|
string="Reject" type="object" |
||||
|
class="oe_highlight" |
||||
|
states="draft"/> |
||||
|
<field name="state" widget="statusbar" |
||||
|
statusbar_visible="draft,done"/> |
||||
|
</header> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="field_id" options="{'no_open': true}"/> |
||||
|
<field name="field_type" invisible="1"/> |
||||
|
|
||||
|
<!-- attrs are added in fields_view_get --> |
||||
|
<field name="origin_value_char"/> |
||||
|
<field name="new_value_char"/> |
||||
|
|
||||
|
<field name="origin_value_date"/> |
||||
|
<field name="new_value_date"/> |
||||
|
|
||||
|
<field name="origin_value_datetime"/> |
||||
|
<field name="new_value_datetime"/> |
||||
|
|
||||
|
<field name="origin_value_float"/> |
||||
|
<field name="new_value_float"/> |
||||
|
|
||||
|
<field name="origin_value_integer"/> |
||||
|
<field name="new_value_integer"/> |
||||
|
|
||||
|
<field name="origin_value_text"/> |
||||
|
<field name="new_value_text"/> |
||||
|
|
||||
|
<field name="origin_value_boolean"/> |
||||
|
<field name="new_value_boolean"/> |
||||
|
|
||||
|
<field name="origin_value_reference"/> |
||||
|
<field name="new_value_reference"/> |
||||
|
|
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_res_partner_changeset_search" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.changeset.search</field> |
||||
|
<field name="model">res.partner.changeset</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Partner Changeset"> |
||||
|
<field name="partner_id"/> |
||||
|
<filter string="Pending" name="draft" |
||||
|
domain="[('state','=','draft')]"/> |
||||
|
<filter string="Done" name="done" |
||||
|
domain="[('state','=','done')]"/> |
||||
|
<group expand="0" string="Group By"> |
||||
|
<filter string="Partner" |
||||
|
name="groupby_partner_id" |
||||
|
context="{'group_by': 'partner_id'}"/> |
||||
|
<filter string="State" |
||||
|
name="groupby_state" |
||||
|
context="{'group_by': 'state'}"/> |
||||
|
</group> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record model="ir.actions.act_window" id="action_res_partner_changeset_view"> |
||||
|
<field name="name">Partner Changeset</field> |
||||
|
<field name="type">ir.actions.act_window</field> |
||||
|
<field name="res_model">res.partner.changeset</field> |
||||
|
<field name="view_type">form</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="context">{'search_default_draft': 1}</field> |
||||
|
<field name="search_view_id" ref="view_res_partner_changeset_search"/> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="menu_res_partner_changeset" |
||||
|
parent="menu_changeset" |
||||
|
sequence="20" |
||||
|
name="Changesets" |
||||
|
action="action_res_partner_changeset_view"/> |
||||
|
</odoo> |
@ -0,0 +1,37 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<record id="res_partner_view_buttons" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.view.buttons</field> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" ref="base.view_partner_form" /> |
||||
|
<field name="priority" eval="18"/> |
||||
|
<field name="groups_id" eval="[(4, ref('partner_changeset.group_changeset_user'))]"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[@name='button_box']" position="inside"> |
||||
|
<button class="oe_inline oe_stat_button" |
||||
|
type="action" |
||||
|
name="%(partner_changeset.action_res_partner_changeset_view)d" |
||||
|
context="{'search_default_draft': 1, 'search_default_partner_id': active_id}" |
||||
|
icon="fa-code-fork"> |
||||
|
<field string="Changes" |
||||
|
name="count_pending_changesets" |
||||
|
widget="statinfo"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="view_res_partner_filter" model="ir.ui.view"> |
||||
|
<field name="name">res.partner.select</field> |
||||
|
<field name="model">res.partner</field> |
||||
|
<field name="inherit_id" ref="base.view_res_partner_filter" /> |
||||
|
<field name="arch" type="xml"> |
||||
|
<filter name="customer" position="after"> |
||||
|
<separator/> |
||||
|
<filter string="Pending Changesets" |
||||
|
name="pending_changesets" |
||||
|
domain="[('count_pending_changesets', '>', 0)]"/> |
||||
|
</filter> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue