diff --git a/.travis.yml b/.travis.yml
index 4d9962c..3fa2e72 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,38 +1,41 @@
-language: python
sudo: false
cache: pip
-python:
- - "2.7"
-
addons:
postgresql: "9.2" # minimal postgresql version for the daterange method
apt:
- packages:
+ packages:
- expect-dev # provides unbuffer utility
- python-lxml # because pip installation is slow
+
+language: python
+
+python:
+ - "3.5"
+
env:
global:
- - VERSION="10.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0"
+ - VERSION="11.0" TESTS="0" LINT_CHECK="0" TRANSIFEX="0"
- TRANSIFEX_USER='transbot@odoo-community.org'
- - secure: Z06mZCN+Hm3myqHSOZpOOk1pd4oq1epAWZv6m9OX2bTNHbhyOVOGK6JWWsnDm/3DUCN1ZeLtSGOl9bvQfMa8ahQHA80MkLL16YlTvQV59Lh+L2gAYmxX+ogJCJgeQSVAXlGLscgkADCu/HzDlmatrDeROMtULn5i23j2qcyUNyM=
-
+
matrix:
- LINT_CHECK="1"
- TRANSIFEX="1"
- - TESTS="1" ODOO_REPO="odoo/odoo"
- TESTS="1" ODOO_REPO="OCA/OCB"
+ - TESTS="1" ODOO_REPO="odoo/odoo"
+
-virtualenv:
- system_site_packages: true
+before_install:
+ - "export DISPLAY=:911.0"
+ - "sh -e /etc/init.d/xvfb start"
install:
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
+ - export WKHTMLTOPDF_VERSION=0.12.4
- travis_install_nightly
- - printf '[options]\n\nrunning_env = dev\n' > ${HOME}/.openerp_serverrc
- - ln -s ${TRAVIS_BUILD_DIR}/server_environment_files_sample ${TRAVIS_BUILD_DIR}/server_environment_files
+
script:
- travis_run_tests
diff --git a/README.md b/README.md
index 448c537..7bcc4b4 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://travis-ci.org/JayVora-SerpentCS/MassEditing)
+[](https://travis-ci.org/JayVora-SerpentCS/MassEditing)
============
Mass Editing
diff --git a/mass_editing/__init__.py b/mass_editing/__init__.py
index f232425..cae1047 100644
--- a/mass_editing/__init__.py
+++ b/mass_editing/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
diff --git a/mass_editing/__manifest__.py b/mass_editing/__manifest__.py
index 17f8daf..4dc7e47 100644
--- a/mass_editing/__manifest__.py
+++ b/mass_editing/__manifest__.py
@@ -1,9 +1,8 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Mass Editing',
- 'version': '10.0.1.0.0',
+ 'version': '11.0.1.0.0',
'author': 'Serpent Consulting Services Pvt. Ltd., '
'Odoo Community Association (OCA)',
'contributors': [
@@ -18,10 +17,12 @@
'uninstall_hook': 'uninstall_hook',
'depends': [
'base',
+ 'web',
],
'data': [
'security/ir.model.access.csv',
'views/mass_editing_view.xml',
+ 'views/template.xml'
],
'installable': True,
'application': False,
diff --git a/mass_editing/hooks.py b/mass_editing/hooks.py
index 708c4e4..2517fe6 100644
--- a/mass_editing/hooks.py
+++ b/mass_editing/hooks.py
@@ -1,12 +1,7 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
def uninstall_hook(cr, registry):
- cr.execute("""SELECT id FROM ir_act_window
- WHERE res_model = 'mass.editing.wizard'""")
- for res in cr.dictfetchall():
- value = 'ir.actions.act_window,%s' % res.get('id')
- cr.execute("DELETE FROM ir_values WHERE value = '%s'" % value)
- return True
+ cr.execute("""DELETE FROM ir_act_window WHERE
+ res_model = 'mass.editing.wizard'""")
diff --git a/mass_editing/models/__init__.py b/mass_editing/models/__init__.py
index 28f986c..d867b13 100644
--- a/mass_editing/models/__init__.py
+++ b/mass_editing/models/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
diff --git a/mass_editing/models/ir_model_fields.py b/mass_editing/models/ir_model_fields.py
index d22867e..93eb734 100644
--- a/mass_editing/models/ir_model_fields.py
+++ b/mass_editing/models/ir_model_fields.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -11,14 +10,19 @@ class IrModelFields(models.Model):
@api.model
def search(self, args, offset=0, limit=0, order=None, count=False):
model_domain = []
- for domain in args:
- if (len(domain) > 2 and domain[0] == 'model_id' and
- isinstance(domain[2], basestring) and
- list(domain[2][1:-1])):
- model_domain += [('model_id', 'in',
- map(int, domain[2][1:-1].split(',')))]
- else:
- model_domain.append(domain)
- return super(IrModelFields, self).search(model_domain, offset=offset,
- limit=limit, order=order,
+ if not self.env.context.get('mass_edit', False):
+ model_domain = args
+ else:
+ for domain in args:
+ if (len(domain) > 2 and domain[0] == 'model_id' and
+ isinstance(domain[2], str) and
+ list(domain[2][1:-1])):
+ model_ids = list(map(int, domain[2][1:-1].split(',')))
+ model_domain += [('model_id', 'in', model_ids)]
+ else:
+ model_domain.append(domain)
+ return super(IrModelFields, self).search(args=model_domain,
+ offset=offset,
+ limit=limit,
+ order=order,
count=count)
diff --git a/mass_editing/models/mass_object.py b/mass_editing/models/mass_object.py
index 656cfe1..52d3fd2 100644
--- a/mass_editing/models/mass_object.py
+++ b/mass_editing/models/mass_object.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -10,7 +9,7 @@ class MassObject(models.Model):
_name = "mass.object"
_description = "Mass Editing Object"
- name = fields.Char('Name', required=True, select=1)
+ name = fields.Char('Name', required=True, index=True)
model_id = fields.Many2one('ir.model', 'Model', required=True,
help="Model is used for Selecting Fields. "
"This is editable until Sidebar menu "
@@ -18,16 +17,12 @@ class MassObject(models.Model):
field_ids = fields.Many2many('ir.model.fields', 'mass_field_rel',
'mass_id', 'field_id', 'Fields')
ref_ir_act_window_id = fields.Many2one('ir.actions.act_window',
- 'Sidebar action',
+ 'Sidebar Action',
readonly=True,
help="Sidebar action to make this "
"template available on "
"records of the related "
"document model.")
- ref_ir_value_id = fields.Many2one('ir.values', 'Sidebar button',
- readonly=True,
- help="Sidebar button to open "
- "the sidebar action.")
model_list = fields.Char('Model List')
_sql_constraints = [
@@ -43,8 +38,10 @@ def _onchange_model_id(self):
model_list = [self.model_id.id]
active_model_obj = self.env[self.model_id.model]
if active_model_obj._inherits:
- keys = active_model_obj._inherits.keys()
- inherits_model_list = model_obj.search([('model', 'in', keys)])
+ model_names = active_model_obj._inherits.keys()
+ inherits_model_list = model_obj.search([('model',
+ 'in',
+ list(model_names))])
model_list.extend((inherits_model_list and
inherits_model_list.ids or []))
self.model_list = model_list
@@ -63,16 +60,9 @@ def create_action(self):
'src_model': src_obj,
'view_type': 'form',
'context': "{'mass_editing_object' : %d}" % (self.id),
- 'view_mode': 'form, tree',
+ 'view_mode': 'form',
'target': 'new',
- 'auto_refresh': 1,
- }).id
- vals['ref_ir_value_id'] = self.env['ir.values'].create({
- 'name': button_name,
- 'model': src_obj,
- 'key2': 'client_action_multi',
- 'value': "ir.actions.act_window," +
- str(vals['ref_ir_act_window_id']),
+ 'binding_model_id': self.model_id.id,
}).id
self.write(vals)
return True
@@ -83,8 +73,6 @@ def unlink_action(self):
try:
if mass.ref_ir_act_window_id:
mass.ref_ir_act_window_id.unlink()
- if mass.ref_ir_value_id:
- mass.ref_ir_value_id.unlink()
except:
raise UserError(_("Deletion of the action record failed."))
return True
diff --git a/mass_editing/static/description/after_edit_note.png b/mass_editing/static/description/after_edit_note.png
deleted file mode 100644
index f3757bb..0000000
Binary files a/mass_editing/static/description/after_edit_note.png and /dev/null differ
diff --git a/mass_editing/static/description/after_mass_edit.png b/mass_editing/static/description/after_mass_edit.png
deleted file mode 100644
index a8a1f70..0000000
Binary files a/mass_editing/static/description/after_mass_edit.png and /dev/null differ
diff --git a/mass_editing/static/description/index.html b/mass_editing/static/description/index.html
index f2e0dcf..eeee1f0 100644
--- a/mass_editing/static/description/index.html
+++ b/mass_editing/static/description/index.html
@@ -21,14 +21,14 @@
The user can remove the action by clicking on the "Remove Sidebar Button".
-

+
-

+
Go to the model/object in which mass editing is configured (ex. Partner).
@@ -39,26 +39,27 @@
-

+
-
The user can set or remove the value of the fields which were configured in mass editing configuration.
+
The user can set or remove the value of the fields which were configured in mass editing configuration.
+ you can also copy the value of the fields from another field.
-
+
You can see the mass editing changes in customer tree view..
-

+
-
+
-

+
You can see the mass editing changes in selected customer
diff --git a/mass_editing/static/description/mass_edit_copy.png b/mass_editing/static/description/mass_edit_copy.png
new file mode 100644
index 0000000..a079aad
Binary files /dev/null and b/mass_editing/static/description/mass_edit_copy.png differ
diff --git a/mass_editing/static/description/mass_edit_menu.png b/mass_editing/static/description/mass_edit_menu.png
new file mode 100644
index 0000000..1b645b7
Binary files /dev/null and b/mass_editing/static/description/mass_edit_menu.png differ
diff --git a/mass_editing/static/description/mass_edit_result.png b/mass_editing/static/description/mass_edit_result.png
new file mode 100644
index 0000000..e531490
Binary files /dev/null and b/mass_editing/static/description/mass_edit_result.png differ
diff --git a/mass_editing/static/description/mass_edit_tree.png b/mass_editing/static/description/mass_edit_tree.png
new file mode 100644
index 0000000..fa55b9f
Binary files /dev/null and b/mass_editing/static/description/mass_edit_tree.png differ
diff --git a/mass_editing/static/description/mass_edit_wizard.png b/mass_editing/static/description/mass_edit_wizard.png
deleted file mode 100644
index 0e78b78..0000000
Binary files a/mass_editing/static/description/mass_edit_wizard.png and /dev/null differ
diff --git a/mass_editing/static/description/mass_editing-2.png b/mass_editing/static/description/mass_editing-2.png
index 830b5b7..a948982 100644
Binary files a/mass_editing/static/description/mass_editing-2.png and b/mass_editing/static/description/mass_editing-2.png differ
diff --git a/mass_editing/static/description/mass_editing_menu.png b/mass_editing/static/description/mass_editing_menu.png
deleted file mode 100644
index 3f2dcff..0000000
Binary files a/mass_editing/static/description/mass_editing_menu.png and /dev/null differ
diff --git a/mass_editing/static/description/remove_button.png b/mass_editing/static/description/remove_button.png
deleted file mode 100644
index 403bb25..0000000
Binary files a/mass_editing/static/description/remove_button.png and /dev/null differ
diff --git a/mass_editing/static/description/remove_button2.png b/mass_editing/static/description/remove_button2.png
new file mode 100644
index 0000000..0fdb954
Binary files /dev/null and b/mass_editing/static/description/remove_button2.png differ
diff --git a/mass_editing/static/src/js/mass_editing.js b/mass_editing/static/src/js/mass_editing.js
new file mode 100644
index 0000000..d4f187c
--- /dev/null
+++ b/mass_editing/static/src/js/mass_editing.js
@@ -0,0 +1,48 @@
+odoo.define('mass_editing.mass_editing', function (require) {
+"use strict";
+
+ var BasicModel = require("web.BasicModel");
+
+ BasicModel.include({
+ /**
+ * parse the server values to javascript framwork
+ * @param {String} fieldNames
+ * @param {Object} element the dataPoint used as parent for the created
+ * dataPoints
+ * @param {Object} data the server data to parse
+ */
+ _parseServerData: function (fieldNames, element, data) {
+ var self = this;
+ _.each(fieldNames, function (fieldName) {
+ var field = element.fields[fieldName];
+ var val = data[fieldName];
+ if (field.type === 'many2one') {
+ // process many2one: split [id, nameget] and create corresponding record
+ // For val = Null
+ if (val && val !== false) {
+ // the many2one value is of the form [id, display_name]
+ var r = self._makeDataPoint({
+ modelName: field.relation,
+ fields: {
+ display_name: {type: 'char'},
+ id: {type: 'integer'},
+ },
+ data: {
+ display_name: val[1],
+ id: val[0],
+ },
+ parentID: element.id,
+ });
+ data[fieldName] = r.id;
+ } else {
+ // no value for the many2one
+ data[fieldName] = false;
+ }
+ } else {
+ data[fieldName] = self._parseServerValue(field, val);
+ }
+ });
+ },
+ });
+
+});
diff --git a/mass_editing/tests/__init__.py b/mass_editing/tests/__init__.py
index 15099e1..c1f46a4 100644
--- a/mass_editing/tests/__init__.py
+++ b/mass_editing/tests/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
diff --git a/mass_editing/tests/test_mass_editing.py b/mass_editing/tests/test_mass_editing.py
index 7ec719a..460a660 100644
--- a/mass_editing/tests/test_mass_editing.py
+++ b/mass_editing/tests/test_mass_editing.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -6,7 +5,7 @@
from odoo.tests import common
from odoo.modules import registry
-from odoo.addons.mass_editing.hooks import uninstall_hook
+from ..hooks import uninstall_hook
class TestMassEditing(common.TransactionCase):
@@ -21,11 +20,21 @@ def setUp(self):
self.partner_model = model_obj.\
search([('model', '=', 'res.partner')])
self.user_model = model_obj.search([('model', '=', 'res.users')])
+ # Calling the Search method without context for
+ # the Search from the List view of the Fields.
self.fields_model = self.env['ir.model.fields'].\
search([('model_id', '=', self.partner_model.id),
('name', 'in', ['email', 'phone', 'category_id', 'comment',
'country_id', 'customer', 'child_ids',
'title'])])
+ # Calling the Search method with context for the Search
+ # model_id field related fields in the fields_ids.
+ self.fields_model = self.env['ir.model.fields'].\
+ with_context({'mass_edit': True}).\
+ search([('model_id', '=', self.partner_model.id),
+ ('name', 'in', ['email', 'phone', 'category_id', 'comment',
+ 'country_id', 'customer', 'child_ids',
+ 'title'])])
self.mass = self._create_mass_editing(self.partner_model,
self.fields_model)
self.copy_mass = self.mass.copy()
@@ -142,21 +151,19 @@ def test_mass_edit_copy(self):
def test_sidebar_action(self):
"""Test if Sidebar Action is added / removed to / from give object."""
- action = self.mass.ref_ir_act_window_id and self.mass.ref_ir_value_id
+ action = self.mass.ref_ir_act_window_id
self.assertTrue(action, 'Sidebar action must be exists.')
# Remove the sidebar actions
self.mass.unlink_action()
- action = self.mass.ref_ir_act_window_id and self.mass.ref_ir_value_id
+ action = self.mass.ref_ir_act_window_id
self.assertFalse(action, 'Sidebar action must be removed.')
def test_unlink_mass(self):
"""Test if related actions are removed when mass editing
record is unlinked."""
- mass_action_id = "ir.actions.act_window," + str(self.mass.id)
self.mass.unlink()
- value_cnt = self.env['ir.values'].search([('value', '=',
- mass_action_id)],
- count=True)
+ value_cnt = self.env['ir.actions.act_window'].search([
+ ('res_model', '=', 'mass.editing.wizard')], count=True)
self.assertTrue(value_cnt == 0,
"Sidebar action must be removed when mass"
" editing is unlinked.")
@@ -165,10 +172,8 @@ def test_uninstall_hook(self):
"""Test if related actions are removed when mass editing
record is uninstalled."""
uninstall_hook(self.cr, registry)
- mass_action_id = "ir.actions.act_window," + str(self.mass.id)
- value_cnt = self.env['ir.values'].search([('value', '=',
- mass_action_id)],
- count=True)
+ value_cnt = self.env['ir.actions.act_window'].search([
+ ('res_model', '=', 'mass.editing.wizard')], count=True)
self.assertTrue(value_cnt == 0,
"Sidebar action must be removed when mass"
" editing module is uninstalled.")
diff --git a/mass_editing/views/mass_editing_view.xml b/mass_editing/views/mass_editing_view.xml
index 547c519..87d08ce 100644
--- a/mass_editing/views/mass_editing_view.xml
+++ b/mass_editing/views/mass_editing_view.xml
@@ -41,13 +41,12 @@
-
+
-
diff --git a/mass_editing/views/template.xml b/mass_editing/views/template.xml
new file mode 100644
index 0000000..fadf9ad
--- /dev/null
+++ b/mass_editing/views/template.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/mass_editing/wizard/__init__.py b/mass_editing/wizard/__init__.py
index ecfaa57..47a34f3 100644
--- a/mass_editing/wizard/__init__.py
+++ b/mass_editing/wizard/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
diff --git a/mass_editing/wizard/mass_editing_wizard.py b/mass_editing/wizard/mass_editing_wizard.py
index 431cdd0..d8bcb89 100644
--- a/mass_editing/wizard/mass_editing_wizard.py
+++ b/mass_editing/wizard/mass_editing_wizard.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -15,7 +14,7 @@ class MassEditingWizard(models.TransientModel):
@api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False,
submenu=False):
- result =\
+ result = \
super(MassEditingWizard, self).fields_view_get(
view_id=view_id,
view_type=view_type,
@@ -421,6 +420,8 @@ def create(self, vals):
fields_obj = self.env['ir.model.fields']
model_obj = self.env[self._context.get('active_model')]
model_rec = model_obj.browse(self._context.get('active_ids'))
+ model_id = self.env['ir.model'].search([
+ ('model', '=', self._context.get('active_model'))])
values = {}
for key, val in vals.items():
if key.startswith('selection_'):
@@ -430,14 +431,35 @@ def create(self, vals):
values.update({split_key: vals.get(split_key, False)})
elif val == 'remove':
values.update({split_key: False})
- elif val == 'remove_m2m':
+ elif val in ['remove_m2m', 'remove_m2m_all']:
+ m2m_list = []
if vals.get(split_key):
- m2m_list = []
for m2m_id in vals.get(split_key)[0][2]:
m2m_list.append((3, m2m_id))
+ if m2m_list:
values.update({split_key: m2m_list})
- elif val in ['remove_o2m', 'remove_m2m_all']:
- values.update({split_key: [(5, 0, [])]})
+ else:
+ values.update({split_key: [(5, 0, [])]})
+ elif val == 'remove_o2m':
+ # model_fieds will return the particular model
+ # in order to get the field of the model
+ # and its relation.
+ model_fields = self.env['ir.model.fields'].search(
+ [('name', '=', split_key),
+ ('model_id', '=', model_id and model_id.id)])
+ # field_model is relation of Object Relation
+ field_model = tools.ustr(model_fields and
+ model_fields.relation)
+ # field relation is relation field of O2m
+ field_relation = tools.ustr(
+ model_fields and
+ model_fields.relation_field)
+ # remove_ids is return O2m field particular ids
+ remove_ids = self.env[field_model].search(
+ [(field_relation, 'in',
+ self._context.get('active_ids'))])
+ o2m_list = [(2, rmv_id.id) for rmv_id in remove_ids]
+ values.update({split_key: o2m_list})
elif val == 'add':
if vals.get(split_key, False):
m2m_list = []
@@ -464,33 +486,33 @@ def create(self, vals):
if set_val == 'set_fix':
tot_val = split_key_data + split_val
elif set_val == 'set_per':
- tot_val = split_key_data +\
+ tot_val = split_key_data + \
(split_key_data * split_val) / 100.0
# Subtraction
elif val == 'val_sub':
if set_val == 'set_fix':
tot_val = split_key_data - split_val
elif set_val == 'set_per':
- tot_val = split_key_data -\
+ tot_val = split_key_data - \
(split_key_data * split_val) / 100.0
# Multiplication
elif val == 'val_mul':
if set_val == 'set_fix':
tot_val = split_key_data * split_val
elif set_val == 'set_per':
- tot_val = split_key_data *\
+ tot_val = split_key_data * \
(split_key_data * split_val) / 100
# Division
elif val == 'val_div':
if set_val == 'set_fix':
tot_val = split_key_data / split_val
elif set_val == 'set_per':
- tot_val = split_key_data /\
+ tot_val = split_key_data / \
(split_key_data * split_val) / 100
data.write({split_key: tot_val})
if values:
model_rec.write(values)
- return super(MassEditingWizard, self).create({})
+ return super(MassEditingWizard, self).create(vals)
@api.multi
def action_apply(self):