diff --git a/addons/website_membership/__manifest__.py b/addons/website_membership/__manifest__.py index 04fc58bde3b..02041b3ff61 100644 --- a/addons/website_membership/__manifest__.py +++ b/addons/website_membership/__manifest__.py @@ -12,6 +12,7 @@ Publish your members/association directory publicly. 'depends': ['website_partner', 'website_google_map', 'association', 'website_sale'], 'data': [ 'data/membership_data.xml', + 'views/product_template_views.xml', 'views/website_membership_templates.xml', 'security/ir.model.access.csv', 'security/website_membership.xml', diff --git a/addons/website_membership/views/product_template_views.xml b/addons/website_membership/views/product_template_views.xml new file mode 100644 index 00000000000..7878526464c --- /dev/null +++ b/addons/website_membership/views/product_template_views.xml @@ -0,0 +1,24 @@ + + + + product.template.view.form.inherit.website_membership + product.template + + + + + + + + + + product.template.view.tree.inherit.website_membership + product.template + + + + + + + + diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index e2e16877fc7..dd088419362 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -157,7 +157,7 @@ class WebsiteSale(http.Controller): def _get_search_order(self, post): # OrderBy will be parsed in orm and so no direct sql injection # id is added to be sure that order is a unique sort key - order = post.get('order') or 'website_sequence desc' + order = post.get('order') or 'website_sequence ASC' return 'is_published desc, %s, id desc' % order def _get_search_domain(self, search, category, attrib_values, search_in_description=True): diff --git a/addons/website_sale/data/demo.xml b/addons/website_sale/data/demo.xml index 3e26dbed843..216c6d38c33 100644 --- a/addons/website_sale/data/demo.xml +++ b/addons/website_sale/data/demo.xml @@ -58,15 +58,13 @@ 2 2 - 1000 + 9950 - 4 - - 4 + 10010 @@ -639,7 +637,7 @@ Warranty SERV_125889 20.0 - 100 + 9980 service diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index b91657f746e..5d8bb08465c 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -3,7 +3,6 @@ from odoo import api, fields, models, tools, _ from odoo.exceptions import ValidationError, UserError -from odoo.addons import decimal_precision as dp from odoo.addons.website.models import ir_http from odoo.tools.translate import html_translate from odoo.osv import expression @@ -204,7 +203,7 @@ class ProductTemplate(models.Model): '(upsell strategy).Those product show up on the product page.') accessory_product_ids = fields.Many2many('product.product', 'product_accessory_rel', 'src_id', 'dest_id', string='Accessory Products', help='Accessories show up when the customer' - 'reviews the cart before payment (cross-sell strategy).') + 'reviews the cart before payment (cross-sell strategy).') website_size_x = fields.Integer('Size X', default=1) website_size_y = fields.Integer('Size Y', default=1) website_style_ids = fields.Many2many('product.style', string='Styles') @@ -345,27 +344,41 @@ class ProductTemplate(models.Model): return website and website.company_id or res def _default_website_sequence(self): - self._cr.execute("SELECT MIN(website_sequence) FROM %s" % self._table) - min_sequence = self._cr.fetchone()[0] - return min_sequence and min_sequence - 1 or 10 + ''' We want new product to be the last (highest seq). + Every product should ideally have an unique sequence. + Default sequence (10000) should only be used for DB first product. + As we don't resequence the whole tree (as `sequence` does), this field + might have negative value. + ''' + self._cr.execute("SELECT MAX(website_sequence) FROM %s" % self._table) + max_sequence = self._cr.fetchone()[0] + if max_sequence is None: + return 10000 + return max_sequence + 5 def set_sequence_top(self): - self.website_sequence = self.sudo().search([], order='website_sequence desc', limit=1).website_sequence + 1 + min_sequence = self.sudo().search([], order='website_sequence ASC', limit=1) + self.website_sequence = min_sequence.website_sequence - 5 def set_sequence_bottom(self): - self.website_sequence = self.sudo().search([], order='website_sequence', limit=1).website_sequence - 1 + max_sequence = self.sudo().search([], order='website_sequence DESC', limit=1) + self.website_sequence = max_sequence.website_sequence + 5 def set_sequence_up(self): - previous_product_tmpl = self.sudo().search( - [('website_sequence', '>', self.website_sequence), ('website_published', '=', self.website_published)], - order='website_sequence', limit=1) + previous_product_tmpl = self.sudo().search([ + ('website_sequence', '<', self.website_sequence), + ('website_published', '=', self.website_published), + ], order='website_sequence DESC', limit=1) if previous_product_tmpl: previous_product_tmpl.website_sequence, self.website_sequence = self.website_sequence, previous_product_tmpl.website_sequence else: self.set_sequence_top() def set_sequence_down(self): - next_prodcut_tmpl = self.search([('website_sequence', '<', self.website_sequence), ('website_published', '=', self.website_published)], order='website_sequence desc', limit=1) + next_prodcut_tmpl = self.search([ + ('website_sequence', '>', self.website_sequence), + ('website_published', '=', self.website_published), + ], order='website_sequence ASC', limit=1) if next_prodcut_tmpl: next_prodcut_tmpl.website_sequence, self.website_sequence = self.website_sequence, next_prodcut_tmpl.website_sequence else: diff --git a/addons/website_sale/tests/__init__.py b/addons/website_sale/tests/__init__.py index 33bc88ece4a..40b4a8266e4 100644 --- a/addons/website_sale/tests/__init__.py +++ b/addons/website_sale/tests/__init__.py @@ -5,3 +5,4 @@ from . import test_website_sale_mail from . import test_website_sale_pricelist from . import test_website_sale_product_attribute_value_config from . import test_website_sale_image +from . import test_website_sequence diff --git a/addons/website_sale/tests/test_website_sequence.py b/addons/website_sale/tests/test_website_sequence.py new file mode 100644 index 00000000000..85cb3cc409f --- /dev/null +++ b/addons/website_sale/tests/test_website_sequence.py @@ -0,0 +1,70 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import odoo.tests + + +@odoo.tests.common.tagged('post_install', '-at_install') +class TestWebsiteSequence(odoo.tests.TransactionCase): + + def setUp(self): + super(TestWebsiteSequence, self).setUp() + + ProductTemplate = self.env['product.template'] + product_templates = ProductTemplate.search([]) + # if stock is installed we can't archive since there is orderpoints + if hasattr(self.env['product.product'], 'orderpoint_ids'): + product_templates.mapped('product_variant_ids.orderpoint_ids').write({'active': False}) + product_templates.write({'active': False}) + self.p1, self.p2, self.p3, self.p4 = ProductTemplate.create([{ + 'name': 'First Product', + 'website_sequence': 100, + }, { + 'name': 'Second Product', + 'website_sequence': 180, + }, { + 'name': 'Third Product', + 'website_sequence': 225, + }, { + 'name': 'Last Product', + 'website_sequence': 250, + }]) + + self._check_correct_order(self.p1 + self.p2 + self.p3 + self.p4) + + def _search_website_sequence_order(self, order='ASC'): + '''Helper method to limit the search only to the setUp products''' + return self.env['product.template'].search([ + ], order='website_sequence %s' % (order)) + + def _check_correct_order(self, products): + product_ids = self._search_website_sequence_order().ids + self.assertEqual(product_ids, products.ids, "Wrong sequence order") + + def test_01_website_sequence(self): + # 100:1, 180:2, 225:3, 250:4 + self.p2.set_sequence_down() + # 100:1, 180:3, 225:2, 250:4 + self._check_correct_order(self.p1 + self.p3 + self.p2 + self.p4) + self.p4.set_sequence_up() + # 100:1, 180:3, 225:4, 250:2 + self._check_correct_order(self.p1 + self.p3 + self.p4 + self.p2) + self.p2.set_sequence_top() + # 95:2, 100:1, 180:3, 225:4 + self._check_correct_order(self.p2 + self.p1 + self.p3 + self.p4) + self.p1.set_sequence_bottom() + # 95:2, 180:3, 225:4, 230:1 + self._check_correct_order(self.p2 + self.p3 + self.p4 + self.p1) + + current_sequences = self._search_website_sequence_order().mapped('website_sequence') + self.assertEqual(current_sequences, [95, 180, 225, 230], "Wrong sequence order (2)") + + self.p2.website_sequence = 1 + self.p3.set_sequence_top() + # -4:3, 1:2, 225:4, 230:1 + self.assertEqual(self.p3.website_sequence, -4, "`website_sequence` should go below 0") + + new_product = self.env['product.template'].create({ + 'name': 'Last Newly Created Product', + }) + + self.assertEqual(self._search_website_sequence_order()[-1], new_product, "new product should be last") diff --git a/addons/website_sale/views/product_views.xml b/addons/website_sale/views/product_views.xml index 4cac8d39f18..ec49eba381b 100644 --- a/addons/website_sale/views/product_views.xml +++ b/addons/website_sale/views/product_views.xml @@ -12,22 +12,6 @@ - - Products - product.template - form - kanban,tree,form,activity - - {'search_default_published': 1, 'default_website_published': True} - - - Create a new product - - A product can be either a physical product or a service that you sell to your customers. - - - - product.pricelist.website.form product.pricelist @@ -50,8 +34,9 @@ - - product.template.website.tree + + + product.template.view.tree.inherit.website_sale product.template @@ -61,6 +46,36 @@ + + + product.template.view.tree.website_sale + primary + product.template + + + + + + + + + + Products + product.template + form + kanban,tree,form,activity + + + {'search_default_published': 1, 'default_website_published': True} + + + Create a new product + + A product can be either a physical product or a service that you sell to your customers. + + + + product.template.invoice.policy product.template @@ -96,6 +111,7 @@ + diff --git a/addons/website_sale_product_configurator/data/demo.xml b/addons/website_sale_product_configurator/data/demo.xml index a091b26688f..db513297a7b 100644 --- a/addons/website_sale_product_configurator/data/demo.xml +++ b/addons/website_sale_product_configurator/data/demo.xml @@ -1,7 +1,7 @@ - 100 + 9980
- Create a new product -
- A product can be either a physical product or a service that you sell to your customers. -
+ Create a new product +
+ A product can be either a physical product or a service that you sell to your customers. +