Browse Source

[PORT] from 7.0 to 10.0 version

pull/706/head
Sylvain LE GAL 7 years ago
parent
commit
c5b0c6fb70
  1. 106
      mass_sorting/README.rst
  2. 24
      mass_sorting/__manifest__.py
  3. 12
      mass_sorting/demo/function.xml
  4. 16
      mass_sorting/demo/mass_sort_config.xml
  5. 20
      mass_sorting/demo/mass_sort_config_line.xml
  6. 195
      mass_sorting/i18n/fr.po
  7. 202
      mass_sorting/models/mass_sort_config.py
  8. 42
      mass_sorting/models/mass_sort_config_line.py
  9. 154
      mass_sorting/models/mass_sort_wizard.py
  10. 26
      mass_sorting/models/mass_sort_wizard_line.py
  11. BIN
      mass_sorting/static/description/1_mass_sort_config.png
  12. BIN
      mass_sorting/static/description/2_button.png
  13. BIN
      mass_sorting/static/description/3_mass_sort_wizard.png
  14. BIN
      mass_sorting/static/description/3_mass_sort_wizard_custom.png
  15. BIN
      mass_sorting/static/description/4_before.png
  16. BIN
      mass_sorting/static/description/5_after.png
  17. BIN
      mass_sorting/static/description/icon.png
  18. 6
      mass_sorting/views/menu.xml
  19. 52
      mass_sorting/views/view_mass_sort_config.xml
  20. 11
      mass_sorting/views/view_mass_sort_wizard.xml

106
mass_sorting/README.rst

@ -0,0 +1,106 @@
.. 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
============
Mass Sorting
============
This module extends the functionality of odoo to allow users to sort an
one2many fields in any model.
Typically, you can sort sale order lines on a sale order, using any fields.
Configuration
=============
To configure this module, you need to:
* Go to Settings / Technical / Mass Sorting
* Create a new item and define:
* a name
* the model you want to sort
* the field of the model, you want to sort
* The lists of the fields, by which the sort will be done
.. image:: /mass_sorting/static/description/1_mass_sort_config.png
:width: 70%
(You can allow users to change or not the values, by checking 'Allow custom Setting')
* Click on the button 'Add sidebar button'
Usage
=====
* Go to the form view of the given model, in this sample, a sale order. (or select items in a tree view)
.. image:: /mass_sorting/static/description/4_before.png
* click on the button 'Action' and then select the according action
.. image:: /mass_sorting/static/description/2_button.png
* On the pop up (depending of the configuration), change the fields and the order
.. image:: /mass_sorting/static/description/3_mass_sort_wizard_custom.png
(If changing configuration is not allowed, a simple message is displayed.)
.. image:: /mass_sorting/static/description/3_mass_sort_wizard.png
* The items will be reordered.
.. image:: /mass_sorting/static/description/5_after.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/149/10.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing 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
------------
* Sylvain LE GAL (https://twitter.com/legalsylvain)
Funders
-------
The development of this module has been financially supported by:
* GRAP (http://www.grap.coop)
This module is highly inspired by 'mass_editing' module. (by OCA and SerpentCS)
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.

24
mass_sorting/__openerp__.py → mass_sorting/__manifest__.py

@ -6,30 +6,19 @@
{
'name': 'Mass Sorting',
'version': '1.0',
'version': "10.0.1.0.0",
'author': 'GRAP,Odoo Community Association (OCA)',
'summary': 'Sort any models by any fields list',
'category': 'Tools',
'website': 'http://www.grap.coop',
'license': 'AGPL-3',
"description": """
Mass Sorting
============
This module provides the functionality to sort an one2many fields in any model.
Typically, you can sort sale order line on a sale order, using any fields.
See screenshots in the description folder.
This module is highly inspired by 'mass_editing' module. (by OCA and SerpentCS)
""",
'depends': [
'base',
],
'data': [
'security/ir.model.access.csv',
'views/mass_sort_config_view.xml',
'views/mass_sort_wizard_view.xml',
'views/view_mass_sort_config.xml',
'views/view_mass_sort_wizard.xml',
'views/action.xml',
'views/menu.xml',
],
@ -41,4 +30,9 @@ This module is highly inspired by 'mass_editing' module. (by OCA and SerpentCS)
'static/description/4_before.png',
'static/description/5_after.png',
],
'demo': [
'demo/mass_sort_config.xml',
'demo/mass_sort_config_line.xml',
'demo/function.xml',
],
}

12
mass_sorting/demo/function.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today GRAP (http://www.grap.coop)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo noupdate="1">
<function model="mass.sort.config" name="create_action" eval="[ref('mass_sort_config_demo')]"/>
</odoo>

16
mass_sorting/demo/mass_sort_config.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today GRAP (http://www.grap.coop)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="mass_sort_config_demo" model="mass.sort.config">
<field name="name">Self Mass Sort Demo</field>
<field name="model_id" ref="mass_sorting.model_mass_sort_config"/>
<field name="one2many_field_id" ref="mass_sorting.field_mass_sort_config_line_ids"/>
</record>
</odoo>

20
mass_sorting/demo/mass_sort_config_line.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2016-Today GRAP (http://www.grap.coop)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="mass_sort_config_demo_line_1" model="mass.sort.config.line">
<field name="config_id" ref="mass_sort_config_demo"/>
<field name="field_id" ref="mass_sorting.field_mass_sort_config_line_field_id"/>
</record>
<record id="mass_sort_config_demo_line_2" model="mass.sort.config.line">
<field name="config_id" ref="mass_sort_config_demo"/>
<field name="field_id" ref="mass_sorting.field_mass_sort_config_line_desc"/>
</record>
</odoo>

195
mass_sorting/i18n/fr.po

@ -1,13 +1,13 @@
# Translation of OpenERP Server.
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mass_sorting
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-02-08 09:48+0000\n"
"PO-Revision-Date: 2016-02-08 09:48+0000\n"
"POT-Creation-Date: 2017-01-19 16:46+0000\n"
"PO-Revision-Date: 2017-01-19 16:46+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@ -16,66 +16,129 @@ msgstr ""
"Plural-Forms: \n"
#. module: mass_sorting
#: code:addons/mass_sorting/models/mass_sort_config.py:95
#: code:addons/mass_sorting/models/mass_sort_config.py:84
#, python-format
msgid "%s (copy)"
msgstr "%s (copie)"
#. module: mass_sorting
#: view:mass.sort.config:0
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_config_form
msgid "Add sidebar button"
msgstr "Ajouter un bouton"
#. module: mass_sorting
#: field:mass.sort.config,allow_custom_setting:0
#: field:mass.sort.wizard,allow_custom_setting:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_allow_custom_setting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_allow_custom_setting
msgid "Allow Custom Setting"
msgstr "Autoriser un paramétrage personnalisé"
#. module: mass_sorting
#: view:mass.sort.wizard:0
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_wizard_form
msgid "Cancel"
msgstr "Annuler"
#. module: mass_sorting
#: view:mass.sort.wizard:0
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_wizard_form
msgid "Confirm"
msgstr "Confirmer"
#. module: mass_sorting
#: field:mass.sort.wizard,description:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_create_uid
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_create_uid
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_create_uid
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_create_uid
msgid "Created by"
msgstr "Créé par"
#. module: mass_sorting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_create_date
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_create_date
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_create_date
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_create_date
msgid "Created on"
msgstr "Créé le"
#. module: mass_sorting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_description
msgid "Description"
msgstr "Description"
#. module: mass_sorting
#: view:mass.sort.config:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_display_name
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_display_name
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_display_name
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: mass_sorting
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_config_form
msgid "Display a button in the sidebar of related model to open a wizard"
msgstr "Afficher un bouton dans la barre de menu du modèle pour ouvrir un assistant"
#. module: mass_sorting
#: field:mass.sort.config.line,field_id:0
#: field:mass.sort.wizard.line,field_id:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_field_id
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_field_id
msgid "Field"
msgstr "Champ"
#. module: mass_sorting
#: field:mass.sort.config,one2many_field_id:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_one2many_field_id
msgid "Field to Sort"
msgstr "Champ à trier"
#. module: mass_sorting
#: help:mass.sort.config,allow_custom_setting:0
#: model:ir.model.fields,help:mass_sorting.field_mass_sort_config_one2many_model
#: model:ir.model.fields,help:mass_sorting.field_mass_sort_wizard_one2many_model
msgid "For relationship fields, the technical name of the target model"
msgstr "Pour les champs de relation, le nom technique du modèle cible"
#. module: mass_sorting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_id
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_id
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_id
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_id
msgid "ID"
msgstr "ID"
#. module: mass_sorting
#: model:ir.model.fields,help:mass_sorting.field_mass_sort_config_allow_custom_setting
#: model:ir.model.fields,help:mass_sorting.field_mass_sort_wizard_allow_custom_setting
msgid "If checked, any user could have the possibility to change fields, and use others."
msgstr "Si la case est cochée, chaque utilisateur aura la possibilité de changer les champs et d'en utiliser d'autres."
#. module: mass_sorting
#: field:mass.sort.config.line,desc:0
#: field:mass.sort.wizard.line,desc:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_desc
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_desc
msgid "Inverse Order"
msgstr "Ordre inverse"
#. module: mass_sorting
#: code:addons/mass_sorting/models/mass_sort_config.py:108
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config___last_update
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line___last_update
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard___last_update
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line___last_update
msgid "Last Modified on"
msgstr "Dernière Modification le"
#. module: mass_sorting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_write_uid
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_write_uid
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_write_uid
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_write_uid
msgid "Last Updated by"
msgstr "Dernière mise à jour par"
#. module: mass_sorting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_write_date
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_write_date
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_write_date
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_write_date
msgid "Last Updated on"
msgstr "Dernière mise à jour le"
#. module: mass_sorting
#: code:addons/mass_sorting/models/mass_sort_config.py:93
#, python-format
msgid "Mass Sort (%s)"
msgstr "Tri en masse (%s)"
@ -83,93 +146,98 @@ msgstr "Tri en masse (%s)"
#. module: mass_sorting
#: model:ir.actions.act_window,name:mass_sorting.action_mass_sort_config
#: model:ir.ui.menu,name:mass_sorting.menu_mass_sort_config
#: view:mass.sort.config:0
#: view:mass.sort.wizard:0
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_config_tree
msgid "Mass Sorting"
msgstr "Tri en masse"
#. module: mass_sorting
#: field:mass.sort.config,model_id:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_model_id
msgid "Model"
msgstr "Modèle"
#. module: mass_sorting
#: field:mass.sort.config,one2many_model:0
#: field:mass.sort.wizard,one2many_model:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_one2many_model
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_one2many_model
msgid "Model Name of the Field to Sort"
msgstr "Nom du modèle du champ à trier"
#. module: mass_sorting
#: field:mass.sort.config,name:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_name
msgid "Name"
msgstr "Nom"
#. module: mass_sorting
#: constraint:mass.sort.wizard:0
msgid "Please Select at least ona Sorting Criteria."
#: code:addons/mass_sorting/models/mass_sort_wizard.py:71
#, python-format
msgid "Please Select at least one Sorting Criteria."
msgstr "Veuillez renseigner au moins un critère de tri."
#. module: mass_sorting
#: model:mass.sort.config,name:mass_sorting.mass_sort_config
msgid "Recursive Demo Configuration"
msgstr "Configuration de démo (récursive)"
#. module: mass_sorting
#: view:mass.sort.config:0
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_config_form
msgid "Remove sidebar button"
msgstr "Retirer le bouton"
#. module: mass_sorting
#: field:mass.sort.config.line,sequence:0
#: field:mass.sort.wizard.line,sequence:0
#: model:mass.sort.config,name:mass_sorting.mass_sort_config_demo
msgid "Self Mass Sort Demo"
msgstr "Self Mass Sort Demo"
#. module: mass_sorting
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_sequence
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_sequence
msgid "Sequence"
msgstr "Séquence"
#. module: mass_sorting
#: field:mass.sort.config,ref_ir_act_window:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_ref_ir_act_window
msgid "Sidebar Action"
msgstr "Action"
#. module: mass_sorting
#: field:mass.sort.config,ref_ir_value:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_ref_ir_value
msgid "Sidebar Button"
msgstr "Bouton"
msgstr "Bouton de la barre latérale"
#. module: mass_sorting
#: field:mass.sort.config,line_ids:0
#: view:mass.sort.wizard:0
#: field:mass.sort.wizard,line_ids:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_ids
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_ids
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_config_form
#: model:ir.ui.view,arch_db:mass_sorting.view_mass_sort_wizard_form
msgid "Sorting Criterias"
msgstr "Critères de tri"
#. module: mass_sorting
#: constraint:mass.sort.config:0
msgid "The selected Field to Sort doesn't belong to the selected model."
msgstr "Le champ sélectionné pour le tri n'appartient pas au modèle sélectionné."
#: code:addons/mass_sorting/models/mass_sort_config.py:63
#, python-format
msgid "The selected Field to Sort '%s' doesn't belong to the selected model '%s'."
msgstr "Le champ sélectionné pour le tri '%s' n'appartient pas au modèle sélectionné '%s'."
#. module: mass_sorting
#: constraint:mass.sort.config:0
#: code:addons/mass_sorting/models/mass_sort_config.py:55
#, python-format
msgid "The selected Field to Sort doesn't not have 'sequence' field defined."
msgstr "Le champ sélectionné pour le tri n'a pas de champ séquence défini."
#. module: mass_sorting
#: constraint:mass.sort.config.line:0
msgid "The selected criteria must belong to the parent model."
msgstr "Le critère sélectionné doit appartenir au modèle parent."
#: code:addons/mass_sorting/models/mass_sort_config_line.py:30
#, python-format
msgid "The selected criteria '%s' must belong to the model of the Field to Sort."
msgstr "Le critère sélectionné '%s' doit appartenir au modèle du champ à trier."
#. module: mass_sorting
#: field:mass.sort.config.line,config_id:0
#: field:mass.sort.wizard.line,wizard_id:0
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_config_line_config_id
#: model:ir.model.fields,field_description:mass_sorting.field_mass_sort_wizard_line_wizard_id
msgid "Wizard"
msgstr "Assistant"
#. module: mass_sorting
#: constraint:mass.sort.config:0
#: code:addons/mass_sorting/models/mass_sort_config.py:72
#, python-format
msgid "You have to define field(s) in 'Sorting Criterias' if you uncheck 'Allow Custom Setting'."
msgstr "You have to define field(s) in 'Sorting Criterias' if you uncheck 'Allow Custom Setting'."
msgstr "Vous devez définir des champs dans 'Critères de Tri', si vous décochez 'Autoriser un paramétrage personnalisé'."
#. module: mass_sorting
#: code:addons/mass_sorting/models/mass_sort_wizard.py:44
#: code:addons/mass_sorting/models/mass_sort_wizard.py:54
#, python-format
msgid "You will sort the field '%(field)s' for %(qty)d %(model)s(s). \n"
"\n"
@ -177,3 +245,24 @@ msgid "You will sort the field '%(field)s' for %(qty)d %(model)s(s). \n"
msgstr "Vous allez trier le champ '%(field)s' pour %(qty)d %(model)s(s). \n"
"\n"
"Le tri sera réalisé par %(field_list)s."
#. module: mass_sorting
#: model:ir.model,name:mass_sorting.model_mass_sort_config
msgid "mass.sort.config"
msgstr "mass.sort.config"
#. module: mass_sorting
#: model:ir.model,name:mass_sorting.model_mass_sort_config_line
msgid "mass.sort.config.line"
msgstr "mass.sort.config.line"
#. module: mass_sorting
#: model:ir.model,name:mass_sorting.model_mass_sort_wizard
msgid "mass.sort.wizard"
msgstr "mass.sort.wizard"
#. module: mass_sorting
#: model:ir.model,name:mass_sorting.model_mass_sort_wizard_line
msgid "mass.sort.wizard.line"
msgstr "mass.sort.wizard.line"

202
mass_sorting/models/mass_sort_config.py

@ -1,144 +1,118 @@
# -*- coding: utf-8 -*-
# Copyright (C):
# * 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>)
# * 2016-Today GRAP (http://www.grap.coop)
# * 2012-Today Serpent Consulting Services (<http://www.serpentcs.com>)
# * 2016-Today GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv import fields
from openerp.osv.orm import Model
from openerp.tools.translate import _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class MassSortConfig(Model):
class MassSortConfig(models.Model):
_name = 'mass.sort.config'
# Column Section
_columns = {
'name': fields.char(
string='Name', translate=True, required=True),
'model_id': fields.many2one(
'ir.model', string='Model', required=True),
'allow_custom_setting': fields.boolean(
string='Allow Custom Setting', help="If checked, any user could"
" have the possibility to change fields, and use others."),
'one2many_field_id': fields.many2one(
'ir.model.fields', string='Field to Sort', required=True,
domain="[('model_id', '=', model_id),"
"('ttype', '=', 'one2many')]"),
'one2many_model': fields.related(
'one2many_field_id', 'relation', type='char',
string='Model Name of the Field to Sort', readonly=True),
'ref_ir_act_window': fields.many2one(
'ir.actions.act_window', 'Sidebar Action', readonly=True),
'ref_ir_value': fields.many2one(
'ir.values', 'Sidebar Button', readonly=True),
'line_ids': fields.one2many(
'mass.sort.config.line', 'config_id', 'Sorting Criterias'),
}
_defaults = {
'allow_custom_setting': True,
}
name = fields.Char(string='Name', translate=True, required=True)
model_id = fields.Many2one(
comodel_name='ir.model', string='Model', required=True)
allow_custom_setting = fields.Boolean(
string='Allow Custom Setting', default=True, help="If checked, any"
" user could have the possibility to change fields, and use others.")
one2many_field_id = fields.Many2one(
comodel_name='ir.model.fields', string='Field to Sort', required=True,
domain="[('model_id', '=', model_id),('ttype', '=', 'one2many')]")
one2many_model = fields.Char(
related='one2many_field_id.relation', readonly=True,
string='Model Name of the Field to Sort', hel="Technical field,"
"used in the model 'mass.sort.config.line'", store=True)
ref_ir_act_window = fields.Many2one(
comodel_name='ir.actions.act_window', string='Sidebar Action',
readonly=True, copy=False)
ref_ir_value = fields.Many2one(
comodel_name='ir.values', string='Sidebar Button', readonly=True,
copy=False)
line_ids = fields.One2many(
comodel_name='mass.sort.config.line', inverse_name='config_id',
string='Sorting Criterias')
# Constraint Section
def _check_model_sequence(self, cr, uid, ids, context=None):
field_obj = self.pool['ir.model.fields']
for config in self.browse(cr, uid, ids, context=context):
if len(field_obj.search(cr, uid, [
@api.constrains('one2many_field_id')
def _check_model_sequence(self):
field_obj = self.env['ir.model.fields']
for config in self:
if len(field_obj.search([
('model', '=', config.one2many_field_id.relation),
('name', '=', 'sequence')], context=context)) != 1:
return False
return True
def _check_model_field(self, cr, uid, ids, context=None):
for config in self.browse(cr, uid, ids, context=context):
if config.model_id.id != config.one2many_field_id.model_id.id:
return False
return True
def _check_line_ids(self, cr, uid, ids, context=None):
for config in self.browse(cr, uid, ids, context=context):
if not config.allow_custom_setting and len(config.line_ids) == 0:
return False
return True
_constraints = [
(_check_model_sequence, "The selected Field to Sort doesn't not have"
" 'sequence' field defined.", ['one2many_field_id']),
(_check_model_field, "The selected Field to Sort doesn't belong to the"
" selected model.", ['model_id', 'one2many_field_id']),
(_check_line_ids, "You have to define field(s) in 'Sorting Criterias'"
" if you uncheck 'Allow Custom Setting'.",
['line_ids', 'allow_custom_setting']),
]
# View Section
def on_change_one2many_field_id(
self, cr, uid, ids, one2many_field_id, context=None):
field_obj = self.pool['ir.model.fields']
if not one2many_field_id:
return {'value': {'one2many_model': False}}
field = field_obj.browse(cr, uid, one2many_field_id, context=context)
return {'value': {'one2many_model': field.relation}}
('name', '=', 'sequence')])) != 1:
raise ValidationError(
_("The selected Field to Sort doesn't not have"
" 'sequence' field defined."))
@api.constrains('model_id', 'one2many_field_id')
def _check_model_field(self):
for config in self:
if config.model_id != config.one2many_field_id.model_id:
raise ValidationError(
_("The selected Field to Sort '%s' doesn't belong to the"
" selected model '%s'.") % (
config.one2many_field_id.model_id.name,
config.model_id.name))
@api.constrains('allow_custom_setting', 'line_ids')
def _check_line_ids(self):
for config in self:
if not config.allow_custom_setting and not len(config.line_ids):
raise ValidationError(_(
"You have to define field(s) in 'Sorting Criterias' if"
" you uncheck 'Allow Custom Setting'."))
# Overload Section
def unlink(self, cr, uid, ids, context=None):
self.unlink_action(cr, uid, ids, context=context)
return super(MassSortConfig, self).unlink(
cr, uid, ids, context=context)
def copy(self, cr, uid, id, value=None, context=None):
value = value or {}
config = self.browse(cr, uid, id, context=context)
value.update({
'name': _('%s (copy)') % config.name,
'ref_ir_act_window': False,
'ref_ir_value': False})
return super(MassSortConfig, self).copy(
cr, uid, id, value, context=context)
def unlink(self):
self.unlink_action()
return super(MassSortConfig, self).unlink()
def copy(self, default=None):
default = default or {}
default.update({
'name': _('%s (copy)') % self.name})
return super(MassSortConfig, self).copy(default=default)
# Custom Section
def create_action(self, cr, uid, ids, context=None):
vals = {}
action_obj = self.pool['ir.actions.act_window']
values_obj = self.pool['ir.values']
for config in self.browse(cr, uid, ids, context=context):
src_obj = config.model_id.model
@api.multi
def create_action(self):
action_obj = self.env['ir.actions.act_window']
values_obj = self.env['ir.values']
for config in self:
button_name = _('Mass Sort (%s)') % config.name
vals['ref_ir_act_window'] = action_obj.create(cr, uid, {
config.ref_ir_act_window = action_obj.create({
'name': button_name,
'type': 'ir.actions.act_window',
'res_model': 'mass.sort.wizard',
'src_model': src_obj,
'src_model': config.model_id.model,
'view_type': 'form',
'context': "{'mass_sort_config_id' : %d}" % (config.id),
'view_mode': 'form,tree',
'target': 'new',
'auto_refresh': 1,
}, context)
vals['ref_ir_value'] = values_obj.create(cr, uid, {
})
config.ref_ir_value = values_obj.create({
'name': button_name,
'model': src_obj,
'model': config.model_id.model,
'key2': 'client_action_multi',
'value': (
"ir.actions.act_window,%s" % vals['ref_ir_act_window']),
'object': True,
}, context)
self.write(cr, uid, ids, {
'ref_ir_act_window': vals.get('ref_ir_act_window', False),
'ref_ir_value': vals.get('ref_ir_value', False),
}, context)
return True
def unlink_action(self, cr, uid, ids, context=None):
action_obj = self.pool['ir.actions.act_window']
values_obj = self.pool['ir.values']
for config in self.browse(cr, uid, ids, context=context):
"ir.actions.act_window,%s" % config.ref_ir_act_window.id),
})
@api.multi
def unlink_action(self):
for config in self:
if config.ref_ir_act_window:
action_obj.unlink(
cr, uid, config.ref_ir_act_window.id, context=context)
config.ref_ir_act_window.unlink()
if config.ref_ir_value:
values_obj.unlink(
cr, uid, config.ref_ir_value.id, context=context)
return True
config.ref_ir_value.unlink()

42
mass_sorting/models/mass_sort_config_line.py

@ -3,36 +3,30 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv import fields
from openerp.osv.orm import Model
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class MassSortConfigLine(Model):
class MassSortConfigLine(models.Model):
_name = 'mass.sort.config.line'
_order = 'config_id, sequence, id'
_columns = {
'sequence': fields.integer('Sequence', required=True),
'config_id': fields.many2one(
'mass.sort.config', string='Wizard'),
'field_id': fields.many2one(
'ir.model.fields', string='Field', required=True, domain="["
"('model', '=', parent.one2many_model)]"),
'desc': fields.boolean('Inverse Order'),
}
sequence = fields.Integer(string='Sequence', required=True, default=1)
_defaults = {
'sequence': 1,
}
config_id = fields.Many2one(
comodel_name='mass.sort.config', string='Wizard')
field_id = fields.Many2one(
comodel_name='ir.model.fields', string='Field', required=True,
domain="[('model', '=', parent.one2many_model)]")
desc = fields.Boolean(string='Inverse Order')
# Constraint Section
def _check_field_id(self, cr, uid, ids, context=None):
for line in self.browse(cr, uid, ids, context=context):
@api.constrains('field_id', 'config_id')
def _check_field_id(self):
for line in self:
if line.field_id.model != line.config_id.one2many_model:
return False
return True
_constraints = [
(_check_field_id, "The selected criteria must belong to the parent"
" model.", ['config_id', 'field_id']),
]
raise ValidationError(_(
"The selected criteria '%s' must belong to the model of"
" the Field to Sort.") % (line.field_id.field_description))

154
mass_sorting/models/mass_sort_wizard.py

@ -3,95 +3,83 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv import fields
from openerp.osv.orm import TransientModel
from openerp.tools.translate import _
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class MassSortWizard(TransientModel):
class MassSortWizard(models.TransientModel):
_name = 'mass.sort.wizard'
_columns = {
'description': fields.text(
string='Description', readonly=True),
'allow_custom_setting': fields.boolean(
string='Allow Custom Setting', readonly=True),
'one2many_model': fields.char(
string='Model Name of the Field to Sort', readonly=True),
'line_ids': fields.one2many(
'mass.sort.wizard.line', 'wizard_id', 'Sorting Criterias'),
}
# Constraint Section
def _check_line_ids(self, cr, uid, ids, context=None):
for wizard in self.browse(cr, uid, ids, context=context):
if not len(wizard.line_ids):
return False
return True
_constraints = [(
_check_line_ids, "Please Select at least ona Sorting Criteria.",
['line_ids']),
]
# Default Section
def _default_description(self, cr, uid, context=None):
config_obj = self.pool['mass.sort.config']
config = config_obj.browse(
cr, uid, context.get('mass_sort_config_id'), context=context)
return _(
"You will sort the field '%(field)s' for %(qty)d %(model)s(s)"
". \n\nThe sorting will be done by %(field_list)s.") % ({
'field': config.one2many_field_id.field_description,
'qty': len(context.get('active_ids', False)),
'model': config.model_id.name,
'field_list': ', '.join(
[x.field_id.field_description for x in config.line_ids])
})
def _default_allow_custom_setting(self, cr, uid, context=None):
config_obj = self.pool['mass.sort.config']
return config_obj.browse(
cr, uid, context.get('mass_sort_config_id'), context=context)\
.allow_custom_setting
def _default_one2many_model(self, cr, uid, context=None):
config_obj = self.pool['mass.sort.config']
return config_obj.browse(
cr, uid, context.get('mass_sort_config_id'), context=context)\
.one2many_model
def _default_line_ids(self, cr, uid, context=None):
config_obj = self.pool['mass.sort.config']
res = []
def _default_config_id(self):
return self._context.get('mass_sort_config_id', False)
def _default_line_ids(self):
config_obj = self.env['mass.sort.config']
line_ids = []
config = config_obj.browse(
cr, uid, context.get('mass_sort_config_id'), context=context)
for line in config.line_ids:
res.append((0, 0, {
self._context.get('mass_sort_config_id', False))
if config:
for line in config.line_ids:
line_ids.append((0, 0, {
'sequence': line.sequence,
'field_id': line.field_id.id,
'desc': line.desc}))
return res
return line_ids
# Column Section
config_id = fields.Many2one(
comodel_name='mass.sort.config', default=_default_config_id,
required=True)
description = fields.Text(
string='Description', readonly=True, compute='_compute_description')
allow_custom_setting = fields.Boolean(
string='Allow Custom Setting', readonly=True,
related='config_id.allow_custom_setting')
one2many_model = fields.Char(
string='Model Name of the Field to Sort', readonly=True,
related='config_id.one2many_model')
line_ids = fields.One2many(
comodel_name='mass.sort.wizard.line', inverse_name='wizard_id',
string='Sorting Criterias', default=_default_line_ids)
# Compute Section
@api.depends('config_id')
def _compute_description(self):
for wizard in self:
wizard.description = _(
"You will sort the field '%(field)s' for %(qty)d %(model)s(s)"
". \n\nThe sorting will be done by %(field_list)s.") % ({
'field':
wizard.config_id.one2many_field_id.field_description,
'qty': len(self._context.get('active_ids', False)),
'model': wizard.config_id.model_id.name,
'field_list': ', '.join(
[x.field_id.field_description
for x in wizard.line_ids])
})
_defaults = {
'description': _default_description,
'allow_custom_setting': _default_allow_custom_setting,
'one2many_model': _default_one2many_model,
'line_ids': _default_line_ids,
}
# Constraint Section
@api.constrains('line_ids')
def _check_line_ids(self):
for wizard in self:
if not len(wizard.line_ids):
raise ValidationError(_(
"Please Select at least one Sorting Criteria."))
# Action Section
def button_apply(self, cr, uid, ids, context=None):
config_obj = self.pool['mass.sort.config']
model_obj = self.pool[context.get('active_model')]
active_ids = context.get('active_ids')
config = config_obj.browse(
cr, uid, context.get('mass_sort_config_id'), context=context)
wizard = self.browse(cr, uid, ids[0], context=context)
def button_apply(self):
self.ensure_one()
wizard = self
active_ids = self._context.get('active_ids')
one2many_obj = self.pool[config.one2many_field_id.relation]
parent_field = config.one2many_field_id.relation_field
model_obj = self.env[wizard.config_id.model_id.model]
one2many_obj = self.env[wizard.config_id.one2many_field_id.relation]
parent_field = wizard.config_id.one2many_field_id.relation_field
order_list = []
for line in wizard.line_ids:
@ -100,15 +88,13 @@ class MassSortWizard(TransientModel):
'%s desc' % line.field_id.name or line.field_id.name)
order = ', '.join(order_list)
for item in model_obj.browse(cr, uid, active_ids, context=context):
for item in model_obj.browse(active_ids):
# DB Query sort by the correct order
line_ids = one2many_obj.search(
cr, uid, [(parent_field, '=', item.id)], order=order,
context=context)
lines = one2many_obj.search(
[(parent_field, '=', item.id)], order=order)
# Write new sequence to sort lines
sequence = 1
for id in line_ids:
one2many_obj.write(
cr, uid, [id], {'sequence': sequence}, context=context)
for line in lines:
line.sequence = sequence
sequence += 1
return {'type': 'ir.actions.act_window_close'}

26
mass_sorting/models/mass_sort_wizard_line.py

@ -3,23 +3,19 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.osv import fields
from openerp.osv.orm import TransientModel
from odoo import fields, models
class TransientModelLine(TransientModel):
class TransientModelLine(models.TransientModel):
_name = 'mass.sort.wizard.line'
_columns = {
'sequence': fields.integer('Sequence', required=True),
'wizard_id': fields.many2one(
'mass.sort.wizard', string='Wizard'),
'field_id': fields.many2one(
'ir.model.fields', string='Field', required=True, domain="["
"('model', '=', parent.one2many_model)]"),
'desc': fields.boolean('Inverse Order'),
}
sequence = fields.Integer(string='Sequence', required=True, default=1)
_defaults = {
'sequence': 1,
}
wizard_id = fields.Many2one(
comodel_name='mass.sort.wizard', string='Wizard')
field_id = fields.Many2one(
comodel_name='ir.model.fields', string='Field', required=True,
domain="[('model', '=', parent.one2many_model)]")
desc = fields.Boolean('Inverse Order')

BIN
mass_sorting/static/description/1_mass_sort_config.png

Before

Width: 770  |  Height: 283  |  Size: 25 KiB

After

Width: 798  |  Height: 386  |  Size: 43 KiB

BIN
mass_sorting/static/description/2_button.png

Before

Width: 609  |  Height: 153  |  Size: 17 KiB

After

Width: 357  |  Height: 123  |  Size: 11 KiB

BIN
mass_sorting/static/description/3_mass_sort_wizard.png

Before

Width: 443  |  Height: 189  |  Size: 19 KiB

After

Width: 276  |  Height: 177  |  Size: 9.5 KiB

BIN
mass_sorting/static/description/3_mass_sort_wizard_custom.png

Before

Width: 718  |  Height: 251  |  Size: 15 KiB

After

Width: 776  |  Height: 318  |  Size: 17 KiB

BIN
mass_sorting/static/description/4_before.png

Before

Width: 769  |  Height: 424  |  Size: 37 KiB

After

Width: 676  |  Height: 415  |  Size: 51 KiB

BIN
mass_sorting/static/description/5_after.png

Before

Width: 771  |  Height: 420  |  Size: 37 KiB

After

Width: 679  |  Height: 412  |  Size: 50 KiB

BIN
mass_sorting/static/description/icon.png

After

Width: 256  |  Height: 256  |  Size: 6.2 KiB

6
mass_sorting/views/menu.xml

@ -5,10 +5,10 @@ Copyright (C) 2016-Today GRAP (http://www.grap.coop)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<menuitem id="menu_mass_sort_config"
action="action_mass_sort_config"
parent="base.menu_config" sequence="7"/>
parent="base.menu_custom" sequence="30"/>
</data></openerp>
</odoo>

52
mass_sorting/views/mass_sort_config_view.xml → mass_sorting/views/view_mass_sort_config.xml

@ -5,12 +5,38 @@ Copyright (C) 2016-Today GRAP (http://www.grap.coop)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="view_mass_sort_config_search" model="ir.ui.view">
<field name="model">mass.sort.config</field>
<field name="arch" type="xml">
<search>
<field name="model_id"/>
</search>
</field>
</record>
<record id="view_mass_sort_config_tree" model="ir.ui.view">
<field name="model">mass.sort.config</field>
<field name="arch" type="xml">
<tree string="Mass Sorting">
<field name="name"/>
<field name="model_id"/>
</tree>
</field>
</record>
<record id="view_mass_sort_config_form" model="ir.ui.view">
<field name="model">mass.sort.config</field>
<field name="arch" type="xml">
<form string="Mass Sorting" version="7.0">
<form>
<header>
<button name="create_action" string="Add sidebar button" type="object" class="btn btn-primary"
attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
help="Display a button in the sidebar of related model to open a wizard"/>
<button name="unlink_action" string="Remove sidebar button" type="object" class="btn btn-default"
attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
</header>
<sheet>
<div class="oe_title">
<div class="oe_edit_only"><label for="name"/></div>
@ -18,17 +44,13 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</div>
<group col="4">
<field name="model_id"/>
<field name="one2many_field_id" on_change="on_change_one2many_field_id(one2many_field_id)"/>
<field name="one2many_field_id"/>
<field name="ref_ir_act_window" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
<field name="ref_ir_value" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
<button name="create_action" string="Add sidebar button" type="object" icon="gtk-execute"
colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
help="Display a button in the sidebar of related model to open a wizard"/>
<button name="unlink_action" string="Remove sidebar button" type="object" icon="gtk-delete"
attrs="{'invisible':[('ref_ir_act_window','=',False)]}" colspan="2" />
<field name="allow_custom_setting"/>
</group>
<group>
<group string="Sorting Criterias">
<field name="line_ids" colspan="4" nolabel="1">
<tree editable="bottom">
<field name="sequence" widget="handle"/>
@ -43,14 +65,4 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</field>
</record>
<record id="view_mass_sort_config_tree" model="ir.ui.view">
<field name="model">mass.sort.config</field>
<field name="arch" type="xml">
<tree string="Mass Sorting">
<field name="name"/>
<field name="model_id"/>
</tree>
</field>
</record>
</data></openerp>
</odoo>

11
mass_sorting/views/mass_sort_wizard_view.xml → mass_sorting/views/view_mass_sort_wizard.xml

@ -5,12 +5,12 @@ Copyright (C) 2016-Today GRAP (http://www.grap.coop)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<openerp><data>
<odoo>
<record id="view_mass_sort_wizard_form" model="ir.ui.view">
<field name="model">mass.sort.wizard</field>
<field name="arch" type="xml">
<form string="Mass Sorting" version="7.0">
<form>
<group attrs="{'invisible': [('allow_custom_setting', '=', True)]}">
<field name="description" nolabel="1"/>
</group>
@ -23,14 +23,15 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</tree>
</field>
</group>
<field name="config_id" invisible="1"/>
<field name="allow_custom_setting" invisible="1"/>
<field name="one2many_model" invisible="1"/>
<footer>
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button name="button_apply" type="object" string="Confirm" class="oe_highlight"/>
<button string="Confirm" name="button_apply" type="object" class="btn btn-primary"/>
<button string="Cancel" special="cancel" class="btn-default"/>
</footer>
</form>
</field>
</record>
</data></openerp>
</odoo>
Loading…
Cancel
Save