diff --git a/addons/website_sale/controllers/backend.py b/addons/website_sale/controllers/backend.py index b1c1eee7..0b3ca9b0 100644 --- a/addons/website_sale/controllers/backend.py +++ b/addons/website_sale/controllers/backend.py @@ -12,8 +12,10 @@ from flectra.http import request class WebsiteSaleBackend(WebsiteBackend): @http.route() - def fetch_dashboard_data(self, date_from, date_to): - results = super(WebsiteSaleBackend, self).fetch_dashboard_data(date_from, date_to) + def fetch_dashboard_data(self, date_from, date_to, website_id=None): + if not website_id: + website_id = request.website.id + results = super(WebsiteSaleBackend, self).fetch_dashboard_data(date_from, date_to, website_id) sales_values = dict( graph=[], @@ -44,6 +46,7 @@ class WebsiteSaleBackend(WebsiteBackend): ('team_id.team_type', '=', 'website'), ('state', 'in', ['sale', 'done']), ('date', '>=', date_from), + ('website_id.id', '=', website_id), ('date', '<=', date_to)], fields=['product_id', 'product_uom_qty', 'price_subtotal'], groupby='product_id', orderby='product_uom_qty desc', limit=5) @@ -60,7 +63,8 @@ class WebsiteSaleBackend(WebsiteBackend): sale_order_domain = [ ('team_id', 'in', request.env['crm.team'].search([('team_type', '=', 'website')]).ids), ('date_order', '>=', fields.Datetime.to_string(datetime_from)), - ('date_order', '<=', fields.Datetime.to_string(datetime_to))] + ('date_order', '<=', fields.Datetime.to_string(datetime_to)), + ('website_id', '=', website_id)] so_group_data = request.env['sale.order'].read_group(sale_order_domain, fields=['state'], groupby='state') for res in so_group_data: if res.get('state') == 'sent': @@ -74,7 +78,8 @@ class WebsiteSaleBackend(WebsiteBackend): ('team_id.team_type', '=', 'website'), ('state', 'in', ['sale', 'done']), ('date', '>=', date_from), - ('date', '<=', date_to)], + ('date', '<=', date_to), + ('website_id.id', '=', website_id)], fields=['team_id', 'price_subtotal'], groupby=['team_id'], ) @@ -114,7 +119,8 @@ class WebsiteSaleBackend(WebsiteBackend): ('team_id.team_type', '=', 'website'), ('state', 'in', ['sale', 'done']), ('date', '>=', date_from), - ('date', '<=', date_to) + ('date', '<=', date_to), + ('website_id.id', '=', website_id) ] sales_values['graph'] += [{ 'values': self._compute_sale_graph(date_date_from, date_date_to, sales_domain), diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index d531fbbd..040f8c26 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -135,7 +135,7 @@ class WebsiteSale(http.Controller): def get_attribute_value_ids(self, product): """ list of selectable attributes of a product - :return: list of product variant description + :return: list of product variant description as requested website (variant id, [visible attribute ids], variant price, variant sale price) """ # product attributes with at least two choices @@ -185,6 +185,8 @@ class WebsiteSale(http.Controller): ids = [value[1]] if attrib: domain += [('attribute_line_ids.value_ids', 'in', ids)] + if not request.env.user.has_group('website.group_website_publisher'): + domain += [('website_ids', 'in', request.website.id)] return domain @@ -222,11 +224,16 @@ class WebsiteSale(http.Controller): post["search"] = search if category: category = request.env['product.public.category'].browse(int(category)) + website = [] + for web in category.website_ids: + website.append(web.id) + if request.website.id not in website: + return request.render('website.404') url = "/shop/category/%s" % slug(category) if attrib_list: post['attrib'] = attrib_list - categs = request.env['product.public.category'].search([('parent_id', '=', False)]) + categs = request.env['product.public.category'].search([('parent_id', '=', False), ('website_ids', 'in', request.website.id)]) Product = request.env['product.template'] parent_category_ids = [] @@ -315,7 +322,7 @@ class WebsiteSale(http.Controller): @http.route(['/shop/change_pricelist/'], type='http', auth="public", website=True) def pricelist_change(self, pl_id, **post): - if (pl_id.selectable or pl_id == request.env.user.partner_id.property_product_pricelist) \ + if (pl_id.website_id or pl_id == request.env.user.partner_id.property_product_pricelist) \ and request.website.is_pricelist_available(pl_id.id): request.session['website_sale_current_pl'] = pl_id.id request.website.sale_get_order(force_pricelist=pl_id.id) diff --git a/addons/website_sale/controllers/portal.py b/addons/website_sale/controllers/portal.py new file mode 100644 index 00000000..6a2fe00c --- /dev/null +++ b/addons/website_sale/controllers/portal.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- +# Part of Flectra. See LICENSE file for full copyright and licensing details. +from flectra import http +from flectra.http import request +from flectra import tools, _ +from flectra.exceptions import AccessError +from flectra.addons.sale.controllers.portal import CustomerPortal +from flectra.addons.account.controllers.portal import PortalAccount + + +class SaleCustomerPortal(CustomerPortal): + + def _prepare_portal_layout_values(self): + values = super(SaleCustomerPortal, self)._prepare_portal_layout_values() + partner = request.env.user.partner_id + + SaleOrder = request.env['sale.order'] + quotation_count = SaleOrder.search_count([ + ('message_partner_ids', 'child_of', + [partner.commercial_partner_id.id]), + ('state', 'in', ['sent', 'cancel']), + ('website_id', '=', request.website.id), + ]) + order_count = SaleOrder.search_count([ + ('message_partner_ids', 'child_of', + [partner.commercial_partner_id.id]), + ('state', 'in', ['sale', 'done']), + ('website_id', '=', request.website.id), + ]) + + values.update({ + 'quotation_count': quotation_count, + 'order_count': order_count, + }) + return values + + @http.route(['/my/quotes', '/my/quotes/page/'], type='http', + auth="user", website=True) + def portal_my_quotes(self, page=1, date_begin=None, date_end=None, + sortby=None, **kw): + values = self._prepare_portal_layout_values() + partner = request.env.user.partner_id + SaleOrder = request.env['sale.order'] + + domain = [ + ('message_partner_ids', 'child_of', + [partner.commercial_partner_id.id]), + ('state', 'in', ['sent', 'cancel']), + ('website_id', '=', request.website.id), + ] + + searchbar_sortings = { + 'date': {'label': _('Order Date'), 'order': 'date_order desc'}, + 'name': {'label': _('Reference'), 'order': 'name'}, + 'stage': {'label': _('Stage'), 'order': 'state'}, + } + + # default sortby order + if not sortby: + sortby = 'date' + sort_order = searchbar_sortings[sortby]['order'] + + archive_groups = self._get_archive_groups('sale.order', domain) + if date_begin and date_end: + domain += [('create_date', '>', date_begin), + ('create_date', '<=', date_end)] + + # count for pager + quotation_count = SaleOrder.search_count(domain) + # make pager + pager = request.website.pager( + url="/my/quotes", + url_args={'date_begin': date_begin, 'date_end': date_end, + 'sortby': sortby}, + total=quotation_count, + page=page, + step=self._items_per_page + ) + # search the count to display, according to the pager data + quotations = SaleOrder.search(domain, order=sort_order, + limit=self._items_per_page, + offset=pager['offset']) + request.session['my_quotes_history'] = quotations.ids[:100] + values.update({ + 'date': date_begin, + 'quotations': quotations.sudo(), + 'page_name': 'quote', + 'pager': pager, + 'archive_groups': archive_groups, + 'default_url': '/my/quotes', + 'searchbar_sortings': searchbar_sortings, + 'sortby': sortby, + }) + return request.render("sale.portal_my_quotations", + values) + + @http.route(['/my/orders', '/my/orders/page/'], type='http', + auth="user", website=True) + def portal_my_orders(self, page=1, date_begin=None, date_end=None, + sortby=None, **kw): + values = self._prepare_portal_layout_values() + partner = request.env.user.partner_id + SaleOrder = request.env['sale.order'] + + domain = [ + ('message_partner_ids', 'child_of', + [partner.commercial_partner_id.id]), + ('state', 'in', ['sale', 'done']), + ('website_id', '=', request.website.id), + ] + + searchbar_sortings = { + 'date': {'label': _('Order Date'), 'order': 'date_order desc'}, + 'name': {'label': _('Reference'), 'order': 'name'}, + 'stage': {'label': _('Stage'), 'order': 'state'}, + } + # default sortby order + if not sortby: + sortby = 'date' + sort_order = searchbar_sortings[sortby]['order'] + + archive_groups = self._get_archive_groups('sale.order', domain) + if date_begin and date_end: + domain += [('create_date', '>', date_begin), + ('create_date', '<=', date_end)] + + # count for pager + order_count = SaleOrder.search_count(domain) + # pager + pager = request.website.pager( + url="/my/orders", + url_args={'date_begin': date_begin, 'date_end': date_end, + 'sortby': sortby}, + total=order_count, + page=page, + step=self._items_per_page + ) + # content according to pager and archive selected + orders = SaleOrder.search(domain, order=sort_order, + limit=self._items_per_page, + offset=pager['offset']) + request.session['my_orders_history'] = orders.ids[:100] + + values.update({ + 'date': date_begin, + 'orders': orders.sudo(), + 'page_name': 'order', + 'pager': pager, + 'archive_groups': archive_groups, + 'default_url': '/my/orders', + 'searchbar_sortings': searchbar_sortings, + 'sortby': sortby, + }) + return request.render("sale.portal_my_orders", values) + + @http.route() + def portal_order_page(self, order=None, access_token=None, **kw): + order = request.env['sale.order'].browse([order]) + try: + if order.website_id != request.website: + raise AccessError('Invalid Order !!') + except AccessError: + return request.render("website.403") + + return super(SaleCustomerPortal, self).portal_order_page(order.id, + access_token, **kw) + + @http.route() + def portal_order_report(self, order_id, access_token=None, **kw): + order = request.env['sale.order'].browse([order_id]) + try: + if order.website_id != request.website: + raise AccessError('Invalid Order !!') + except AccessError: + return request.render("website.403") + + return super(SaleCustomerPortal, self).portal_order_report(order_id, + access_token, + **kw) + + +class AccountCustomerPortal(PortalAccount): + + def _prepare_portal_layout_values(self): + values = super(AccountCustomerPortal, self)._prepare_portal_layout_values() + partner = request.env.user.partner_id + + invoice_count = request.env['account.invoice'].search_count([ + ('type', 'in', ['out_invoice', 'out_refund']), + ('message_partner_ids', 'child_of', + [partner.commercial_partner_id.id]), + ('state', 'in', ['open', 'paid', 'cancel']), + ('website_id', '=', request.website.id), + ]) + + values['invoice_count'] = invoice_count + return values + + @http.route() + def portal_my_invoices(self, page=1, date_begin=None, date_end=None, + sortby=None, **kw): + values = self._prepare_portal_layout_values() + partner = request.env.user.partner_id + AccountInvoice = request.env['account.invoice'] + + domain = [ + ('type', 'in', ['out_invoice', 'out_refund']), + ('message_partner_ids', 'child_of', + [partner.commercial_partner_id.id]), + ('state', 'in', ['open', 'paid', 'cancelled']), + ('website_id', '=', request.website.id), + ] + + searchbar_sortings = { + 'date': {'label': _('Invoice Date'), 'order': 'date_invoice desc'}, + 'duedate': {'label': _('Due Date'), 'order': 'date_due desc'}, + 'name': {'label': _('Reference'), 'order': 'name desc'}, + 'state': {'label': _('Status'), 'order': 'state'}, + } + # default sort by order + if not sortby: + sortby = 'date' + order = searchbar_sortings[sortby]['order'] + + archive_groups = self._get_archive_groups('account.invoice', domain) + if date_begin and date_end: + domain += [('create_date', '>', date_begin), + ('create_date', '<=', date_end)] + + # count for pager + invoice_count = AccountInvoice.search_count(domain) + # pager + pager = request.website.pager( + url="/my/invoices", + url_args={'date_begin': date_begin, + 'date_end': date_end, + 'sortby': sortby}, + total=invoice_count, + page=page, + step=self._items_per_page + ) + # content according to pager and archive selected + invoices = AccountInvoice.search(domain, order=order, + limit=self._items_per_page, + offset=pager['offset']) + values.update({ + 'date': date_begin, + 'invoices': invoices, + 'page_name': 'invoice', + 'pager': pager, + 'archive_groups': archive_groups, + 'default_url': '/my/invoices', + 'searchbar_sortings': searchbar_sortings, + 'sortby': sortby, + }) + return request.render("account.portal_my_invoices", values) + + @http.route() + def portal_my_invoice_detail(self, invoice_id, access_token=None, **kw): + invoice = request.env['account.invoice'].browse(invoice_id) + try: + if invoice.website_id != request.website: + raise AccessError('Invalid Invoice !!') + except AccessError: + return request.render("website.403") + + return super(PortalAccount, self).portal_my_invoice_detail(invoice_id, access_token,**kw) + + @http.route() + def portal_my_invoice_report(self, invoice_id, **kw): + invoice = request.env['account.invoice'].browse(invoice_id) + try: + if invoice.website_id != request.website: + raise AccessError('Invalid Invoice !!') + except AccessError: + return request.render("website.403") + + return super(PortalAccount, self).portal_my_invoices_report(invoice_id, + **kw) diff --git a/addons/website_sale/data/data.xml b/addons/website_sale/data/data.xml index b1ded1f0..63542070 100644 --- a/addons/website_sale/data/data.xml +++ b/addons/website_sale/data/data.xml @@ -38,10 +38,6 @@ - - - - diff --git a/addons/website_sale/data/demo.xml b/addons/website_sale/data/demo.xml index 1cf1cd55..e1f9bfc6 100644 --- a/addons/website_sale/data/demo.xml +++ b/addons/website_sale/data/demo.xml @@ -713,8 +713,7 @@ Weight: 31 grams USD - - + 3 @@ -727,8 +726,7 @@ Weight: 31 grams Christmas - - + 20 @@ -741,8 +739,7 @@ Weight: 31 grams Benelux - - + 2 @@ -757,8 +754,7 @@ Weight: 31 grams EUR - - + 3 diff --git a/addons/website_sale/models/__init__.py b/addons/website_sale/models/__init__.py index 9a0cd292..5045a186 100644 --- a/addons/website_sale/models/__init__.py +++ b/addons/website_sale/models/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. +from . import account_invoice from . import crm_team from . import ir_http from . import mail_compose_message @@ -8,6 +9,7 @@ from . import product from . import res_country from . import res_partner from . import sale_order +from . import sale_report from . import ir_model_fields from . import website from . import res_config_settings diff --git a/addons/website_sale/models/account_invoice.py b/addons/website_sale/models/account_invoice.py new file mode 100644 index 00000000..08598e3b --- /dev/null +++ b/addons/website_sale/models/account_invoice.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import api, fields, models, _ + + +class AccountInvoice(models.Model): + _inherit = 'account.invoice' + + website_id = fields.Many2one('website', string="Website") + + +class SaleAdvancePaymentInv(models.TransientModel): + _inherit = "sale.advance.payment.inv" + + @api.multi + def _create_invoice(self, order, so_line, amount): + res = super(SaleAdvancePaymentInv, self)._create_invoice(order, + so_line, + amount) + + res.website_id = order.website_id + + return res diff --git a/addons/website_sale/models/product.py b/addons/website_sale/models/product.py index e3fd8259..f5941d52 100644 --- a/addons/website_sale/models/product.py +++ b/addons/website_sale/models/product.py @@ -15,15 +15,23 @@ class ProductStyle(models.Model): html_class = fields.Char(string='HTML Classes') +class WebsitePriceList(models.Model): + _name = "website.product.pricelist" + + pricelist_id = fields.Many2one('product.pricelist', + string='Website Pricelist') + website_id = fields.Many2one('website', string='Website') + selectable = fields.Boolean(string="selectable", default=True) + + class ProductPricelist(models.Model): _inherit = "product.pricelist" def _default_website(self): return self.env['website'].search([], limit=1) - website_id = fields.Many2one('website', string="website", default=_default_website) + website_id = fields.One2many('website.product.pricelist', 'pricelist_id', string='Website') code = fields.Char(string='E-commerce Promotional Code', groups="base.group_user") - selectable = fields.Boolean(help="Allow the end user to choose this price list") def clear_cache(self): # website._get_pl() is cached to avoid to recompute at each request the @@ -75,16 +83,40 @@ class ProductPublicCategory(models.Model): help="Small-sized image of the category. It is automatically " "resized as a 64x64px image, with aspect ratio preserved. " "Use this field anywhere a small image is required.") + website_ids = fields.Many2many('website', 'website_prod_public_categ_rel', + 'website_id', 'category_id', + string='Websites', copy=False, + help='List of websites in which ' + 'category is published.') @api.model def create(self, vals): tools.image_resize_images(vals) - return super(ProductPublicCategory, self).create(vals) + res = super(ProductPublicCategory, self).create(vals) + # @todo Check different test-case: child & parent category + if res.parent_id: + res.parent_id.write({ + 'website_ids': [(4, website_id.id) for website_id in res.website_ids] + }) + return res @api.multi def write(self, vals): tools.image_resize_images(vals) - return super(ProductPublicCategory, self).write(vals) + res = super(ProductPublicCategory, self).write(vals) + # @todo Check different test-case: child & parent category + if self.parent_id and self.website_ids.ids: + self.parent_id.write({ + 'website_ids': [(4, website_id.id) for website_id in self.website_ids] + }) + if self.child_id: + for child_id in self.child_id: + for website_id in child_id.website_ids: + if website_id not in self.website_ids: + child_id.write({ + 'website_ids': [(3, website_id.id)] + }) + return res @api.constrains('parent_id') def check_parent_id(self): @@ -132,6 +164,11 @@ class ProductTemplate(models.Model): website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) website_price_difference = fields.Boolean('Website price difference', compute='_website_price') + website_ids = fields.Many2many('website', 'website_prod_pub_rel', + 'website_id', 'product_id', + string='Websites', copy=False, + help='List of websites in which ' + 'Product is published.') def _website_price(self): # First filter out the ones that have no variant: @@ -180,6 +217,11 @@ class ProductTemplate(models.Model): class Product(models.Model): _inherit = "product.product" + def _get_default_website_ids(self): + default_website_id = self.env.ref('website.default_website') + return [default_website_id.id] if default_website_id else None + + website_ids = fields.Many2many('website', string="Publish Product On Website", default=_get_default_website_ids) website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) website_price_difference = fields.Boolean('Website price difference', compute='_website_price') diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 6ba7e922..fb6a491c 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -21,6 +21,8 @@ class SaleOrder(models.Model): string='Order Lines displayed on Website', readonly=True, help='Order Lines to be displayed on the website. They should not be used for computation purpose.', ) + website_id = fields.Many2one('website', string='Website', + help='Website reference for quotation/order.') cart_quantity = fields.Integer(compute='_compute_cart_info', string='Cart Quantity') only_services = fields.Boolean(compute='_compute_cart_info', string='Only Services') can_directly_mark_as_paid = fields.Boolean(compute='_compute_can_directly_mark_as_paid', @@ -256,3 +258,9 @@ class SaleOrder(models.Model): self.payment_tx_id.state = 'done' else: raise ValidationError(_("The quote should be sent and the payment acquirer type should be manual or wire transfer")) + + @api.multi + def _prepare_invoice(self): + res = super(SaleOrder, self)._prepare_invoice() + res['website_id'] = self.website_id.id + return res diff --git a/addons/website_sale/models/sale_report.py b/addons/website_sale/models/sale_report.py new file mode 100644 index 00000000..d2643a81 --- /dev/null +++ b/addons/website_sale/models/sale_report.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# Part of flectra. See LICENSE file for full copyright and licensing details. + +from flectra import api, fields, models + + +class SaleReport(models.Model): + _inherit = "sale.report" + website_id = fields.Many2one('website', 'Website', readonly=True) + + def _select(self): + select_str = """ + WITH currency_rate as (%s) + SELECT min(l.id) as id, + l.product_id as product_id, + t.uom_id as product_uom, + sum(l.product_uom_qty / u.factor * u2.factor) as product_uom_qty, + sum(l.qty_delivered / u.factor * u2.factor) as qty_delivered, + sum(l.qty_invoiced / u.factor * u2.factor) as qty_invoiced, + sum(l.qty_to_invoice / u.factor * u2.factor) as qty_to_invoice, + sum(l.price_total / COALESCE(cr.rate, 1.0)) as price_total, + sum(l.price_subtotal / COALESCE(cr.rate, 1.0)) as price_subtotal, + sum(l.amt_to_invoice / COALESCE(cr.rate, 1.0)) as amt_to_invoice, + sum(l.amt_invoiced / COALESCE(cr.rate, 1.0)) as amt_invoiced, + count(*) as nbr, + s.name as name, + s.date_order as date, + s.confirmation_date as confirmation_date, + s.state as state, + s.partner_id as partner_id, + s.user_id as user_id, + s.company_id as company_id, + extract(epoch from avg(date_trunc('day',s.date_order)-date_trunc('day',s.create_date)))/(24*60*60)::decimal(16,2) as delay, + t.categ_id as categ_id, + s.pricelist_id as pricelist_id, + s.analytic_account_id as analytic_account_id, + s.team_id as team_id, + s.website_id as website_id, + p.product_tmpl_id, + partner.country_id as country_id, + partner.commercial_partner_id as commercial_partner_id, + sum(p.weight * l.product_uom_qty / u.factor * u2.factor) as weight, + sum(p.volume * l.product_uom_qty / u.factor * u2.factor) as volume + """ % self.env['res.currency']._select_companies_rates() + return select_str + + def _group_by(self): + res = super(SaleReport, self)._group_by() + return res + ',s.website_id' diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py index 18b2163d..54c8e8e6 100644 --- a/addons/website_sale/models/website.py +++ b/addons/website_sale/models/website.py @@ -17,12 +17,14 @@ class Website(models.Model): currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', string='Default Currency') salesperson_id = fields.Many2one('res.users', string='Salesperson') salesteam_id = fields.Many2one('crm.team', string='Sales Channel') - pricelist_ids = fields.One2many('product.pricelist', compute="_compute_pricelist_ids", - string='Price list available for this Ecommerce/Website') + pricelist_ids = fields.One2many('website.product.pricelist', compute="_compute_pricelist_ids", + string='Price list available for this Ecommerce/Website') @api.one def _compute_pricelist_ids(self): - self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)]) + for website in self: + website.pricelist_ids = website.env["website.product.pricelist"].search([("website_id", "=", website.id)]) + # self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)]) @api.multi def _compute_pricelist_id(self): @@ -32,8 +34,8 @@ class Website(models.Model): website.pricelist_id = website.get_current_pricelist() # This method is cached, must not return records! See also #8795 - @tools.ormcache('self.env.uid', 'country_code', 'show_visible', 'website_pl', 'current_pl', 'all_pl', 'partner_pl', 'order_pl') - def _get_pl_partner_order(self, country_code, show_visible, website_pl, current_pl, all_pl, partner_pl=False, order_pl=False): + @tools.ormcache('self.env.uid', 'country_code', 'show_visible', 'website_pl', 'current_pl', 'all_pls', 'partner_pl', 'order_pl') + def _get_pl_partner_order(self, country_code, show_visible, website_pl, current_pl, all_pls, partner_pl=False, order_pl=False): """ Return the list of pricelists that can be used on website for the current user. :param str country_code: code iso or False, If set, we search only price list available for this country :param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo) @@ -49,7 +51,7 @@ class Website(models.Model): if country_code: for cgroup in self.env['res.country.group'].search([('country_ids.code', '=', country_code)]): for group_pricelists in cgroup.pricelist_ids: - if not show_visible or group_pricelists.selectable or group_pricelists.id in (current_pl, order_pl): + if not show_visible or group_pricelists.website_id.filtered(lambda web_pl: web_pl.website_id == self.get_current_website() and web_pl.selectable) or group_pricelists.id in (current_pl, order_pl): pricelists |= group_pricelists partner = self.env.user.partner_id @@ -59,9 +61,11 @@ class Website(models.Model): pricelists |= partner.property_product_pricelist if not pricelists: # no pricelist for this country, or no GeoIP - pricelists |= all_pl.filtered(lambda pl: not show_visible or pl.selectable or pl.id in (current_pl, order_pl)) + for all_pl in all_pls: + pricelists |= all_pl.pricelist_id.filtered(lambda pl: not show_visible or (all_pl.pricelist_id == pl and all_pl.selectable) or pl.id in (current_pl, order_pl)) else: - pricelists |= all_pl.filtered(lambda pl: not show_visible and pl.sudo().code) + for all_pl in all_pls: + pricelists |= all_pl.pricelist_id.filtered(lambda pl: not show_visible and pl.sudo().code) # This method is cached, must not return records! See also #8795 return pricelists.ids @@ -167,6 +171,7 @@ class Website(models.Model): 'partner_invoice_id': addr['invoice'], 'partner_shipping_id': addr['delivery'], 'user_id': salesperson_id or self.salesperson_id.id or default_user_id, + 'website_id': request.website.id, } company = self.company_id or pricelist.company_id if company: diff --git a/addons/website_sale/security/ir.model.access.csv b/addons/website_sale/security/ir.model.access.csv index 9ff7391f..a65100d3 100644 --- a/addons/website_sale/security/ir.model.access.csv +++ b/addons/website_sale/security/ir.model.access.csv @@ -19,3 +19,4 @@ access_account_tax_user,account.tax,account.model_account_tax,base.group_public, access_product_image_public,product.image public,model_product_image,,1,0,0,0 access_product_image_publisher,product.image wbesite publisher,model_product_image,website.group_website_publisher,1,1,1,1 access_product_image_sale,product.image sale,model_product_image,sales_team.group_sale_manager,1,1,1,1 +access_website_product_pricelist,access_website_product_pricelist,model_website_product_pricelist,,1,0,0,0 diff --git a/addons/website_sale/tests/test_website_sale_pricelist.py b/addons/website_sale/tests/test_website_sale_pricelist.py index 16a712e4..09362304 100644 --- a/addons/website_sale/tests/test_website_sale_pricelist.py +++ b/addons/website_sale/tests/test_website_sale_pricelist.py @@ -22,22 +22,30 @@ class TestWebsitePriceList(TransactionCase): self.env['product.pricelist'].search([]).write({'website_id': False}) website_pls = ('list_benelux', 'list_christmas', 'list_europe') for pl in website_pls: - self.env.ref('website_sale.' + pl).website_id = self.website.id - self.env.ref('product.list0').website_id = self.website.id - self.env.ref('website_sale.list_benelux').selectable = True + self.env['website.product.pricelist'].create({ + 'pricelist_id': self.env.ref('website_sale.' + pl).id, + 'website_id': self.website.id, + 'selectable': False if pl == 'list_christmas' else True + }) + self.env['website.product.pricelist'].create({ + 'pricelist_id': self.env.ref('product.list0').id, + 'website_id': self.website.id + }) self.website.pricelist_id = self.ref('product.list0') ca_group = self.env['res.country.group'].create({ 'name': 'Canada', 'country_ids': [(6, 0, [self.ref('base.ca')])] }) - self.env['product.pricelist'].create({ + ppl = self.env['product.pricelist'].create({ 'name': 'Canada', - 'selectable': True, - 'website_id': self.website.id, 'country_group_ids': [(6, 0, [ca_group.id])], 'sequence': 10 }) + self.env['website.product.pricelist'].create({ + 'pricelist_id': ppl.id, + 'website_id': self.website.id + }) patcher = patch('flectra.addons.website_sale.models.website.Website.get_pricelist_available', wraps=self._get_pricelist_available) patcher.start() self.addCleanup(patcher.stop) diff --git a/addons/website_sale/views/account_views.xml b/addons/website_sale/views/account_views.xml index c159c21b..20d64b63 100644 --- a/addons/website_sale/views/account_views.xml +++ b/addons/website_sale/views/account_views.xml @@ -21,4 +21,15 @@ {"default_base":'list_price'} + + + account.invoice.form.inherit + account.invoice + + + + + + + \ No newline at end of file diff --git a/addons/website_sale/views/payment_views.xml b/addons/website_sale/views/payment_views.xml index 44d7a5c7..a4214998 100644 --- a/addons/website_sale/views/payment_views.xml +++ b/addons/website_sale/views/payment_views.xml @@ -21,4 +21,24 @@ You don't have any payments to capture from the website. + + + product.template.product.form.inherit + product.template + + + + + + + + + + + + + + diff --git a/addons/website_sale/views/product_views.xml b/addons/website_sale/views/product_views.xml index 20eb827a..a0e8d45a 100644 --- a/addons/website_sale/views/product_views.xml +++ b/addons/website_sale/views/product_views.xml @@ -74,6 +74,7 @@ +