summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYannick Tivisse <yti@odoo.com>2017-05-24 10:25:54 +0200
committerYannick Tivisse <yti@odoo.com>2017-06-02 15:31:47 +0200
commit4fe4c1e8518f3adbd7406f2a75f98d7c25aa9a90 (patch)
tree9d172d3b97c13f1f1f259df39242813ab297a7cc
parent8d37f49cb710f75ceb2d0f2ac3a2d0668551f406 (diff)
[MOV] website_sale: Move override of website from sale_order.py to website.py
-rw-r--r--addons/website_sale/models/sale_order.py313
-rw-r--r--addons/website_sale/models/website.py315
-rw-r--r--addons/website_sale/tests/test_website_sale_pricelist.py3
3 files changed, 316 insertions, 315 deletions
diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py
index a933dd3574d..4b007b59bd2 100644
--- a/addons/website_sale/models/sale_order.py
+++ b/addons/website_sale/models/sale_order.py
@@ -3,7 +3,7 @@
import logging
import random
-from odoo import api, models, fields, tools, _
+from odoo import api, models, fields, _
from odoo.http import request
from odoo.exceptions import UserError, ValidationError
from odoo.tools import pycompat
@@ -167,317 +167,6 @@ class SaleOrder(models.Model):
return random.sample(accessory_products, len(accessory_products))
-class Website(models.Model):
- _inherit = 'website'
-
- pricelist_id = fields.Many2one('product.pricelist', compute='_compute_pricelist_id', string='Default Pricelist')
- 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')
-
- @api.one
- def _compute_pricelist_ids(self):
- self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)])
-
- @api.multi
- def _compute_pricelist_id(self):
- for website in self:
- if website._context.get('website_id') != website.id:
- website = website.with_context(website_id=website.id)
- 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):
- """ 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)
- :param int website_pl: The default pricelist used on this website
- :param int current_pl: The current pricelist used on the website
- (If not selectable but the current pricelist we had this pricelist anyway)
- :param list all_pl: List of all pricelist available for this website
- :param int partner_pl: the partner pricelist
- :param int order_pl: the current cart pricelist
- :returns: list of pricelist ids
- """
- pricelists = self.env['product.pricelist']
- 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):
- pricelists |= group_pricelists
-
- partner = self.env.user.partner_id
- is_public = self.user_id.id == self.env.user.id
- if not is_public and (not pricelists or (partner_pl or partner.property_product_pricelist.id) != website_pl):
- if partner.property_product_pricelist.website_id:
- 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))
- else:
- pricelists |= all_pl.filtered(lambda pl: not show_visible and pl.sudo().code)
-
- # This method is cached, must not return records! See also #8795
- return pricelists.ids
-
- def _get_pl(self, country_code, show_visible, website_pl, current_pl, all_pl):
- pl_ids = self._get_pl_partner_order(country_code, show_visible, website_pl, current_pl, all_pl)
- return self.env['product.pricelist'].browse(pl_ids)
-
- def get_pricelist_available(self, show_visible=False):
-
- """ Return the list of pricelists that can be used on website for the current user.
- Country restrictions will be detected with GeoIP (if installed).
- :param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo)
- :returns: pricelist recordset
- """
- website = request.website
- if not request.website:
- if self.env.context.get('website_id'):
- website = self.browse(self.env.context['website_id'])
- else:
- website = self.search([], limit=1)
- isocountry = request.session.geoip and request.session.geoip.get('country_code') or False
- partner = self.env.user.partner_id
- order_pl = partner.last_website_so_id and partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id
- partner_pl = partner.property_product_pricelist
- pricelists = website._get_pl_partner_order(isocountry, show_visible,
- website.user_id.sudo().partner_id.property_product_pricelist.id,
- request.session.get('website_sale_current_pl'),
- website.pricelist_ids,
- partner_pl=partner_pl and partner_pl.id or None,
- order_pl=order_pl and order_pl.id or None)
- return self.env['product.pricelist'].browse(pricelists)
-
- def is_pricelist_available(self, pl_id):
- """ Return a boolean to specify if a specific pricelist can be manually set on the website.
- Warning: It check only if pricelist is in the 'selectable' pricelists or the current pricelist.
- :param int pl_id: The pricelist id to check
- :returns: Boolean, True if valid / available
- """
- return pl_id in self.get_pricelist_available(show_visible=False).ids
-
- def get_current_pricelist(self):
- """
- :returns: The current pricelist record
- """
- # The list of available pricelists for this user.
- # If the user is signed in, and has a pricelist set different than the public user pricelist
- # then this pricelist will always be considered as available
- available_pricelists = self.get_pricelist_available()
- pl = None
- partner = self.env.user.partner_id
- if request.session.get('website_sale_current_pl'):
- # `website_sale_current_pl` is set only if the user specifically chose it:
- # - Either, he chose it from the pricelist selection
- # - Either, he entered a coupon code
- pl = self.env['product.pricelist'].browse(request.session['website_sale_current_pl'])
- if pl not in available_pricelists:
- pl = None
- request.session.pop('website_sale_current_pl')
- if not pl:
- # If the user has a saved cart, it take the pricelist of this cart, except if
- # the order is no longer draft (It has already been confirmed, or cancelled, ...)
- pl = partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id
- if not pl:
- # The pricelist of the user set on its partner form.
- # If the user is not signed in, it's the public user pricelist
- pl = partner.property_product_pricelist
- if available_pricelists and pl not in available_pricelists:
- # If there is at least one pricelist in the available pricelists
- # and the chosen pricelist is not within them
- # it then choose the first available pricelist.
- # This can only happen when the pricelist is the public user pricelist and this pricelist is not in the available pricelist for this localization
- # If the user is signed in, and has a special pricelist (different than the public user pricelist),
- # then this special pricelist is amongs these available pricelists, and therefore it won't fall in this case.
- pl = available_pricelists[0]
-
- if not pl:
- _logger.error('Fail to find pricelist for partner "%s" (id %s)', partner.name, partner.id)
- return pl
-
- @api.multi
- def sale_product_domain(self):
- return [("sale_ok", "=", True)]
-
- @api.model
- def sale_get_payment_term(self, partner):
- DEFAULT_PAYMENT_TERM = 'account.account_payment_term_immediate'
- return self.env.ref(DEFAULT_PAYMENT_TERM, False).id or partner.property_payment_term_id.id
-
- @api.multi
- def _prepare_sale_order_values(self, partner, pricelist):
- self.ensure_one()
- affiliate_id = request.session.get('affiliate_id')
- salesperson_id = affiliate_id if self.env['res.users'].sudo().browse(affiliate_id).exists() else request.website.salesperson_id.id
- addr = partner.address_get(['delivery', 'invoice'])
- values = {
- 'partner_id': partner.id,
- 'pricelist_id': pricelist.id,
- 'payment_term_id': self.sale_get_payment_term(partner),
- 'team_id': self.salesteam_id.id,
- 'partner_invoice_id': addr['invoice'],
- 'partner_shipping_id': addr['delivery'],
- 'user_id': salesperson_id or self.salesperson_id.id,
- }
- company = self.company_id or pricelist.company_id
- if company:
- values['company_id'] = company.id
-
- return values
-
- @api.multi
- def sale_get_order(self, force_create=False, code=None, update_pricelist=False, force_pricelist=False):
- """ Return the current sales order after mofications specified by params.
- :param bool force_create: Create sales order if not already existing
- :param str code: Code to force a pricelist (promo code)
- If empty, it's a special case to reset the pricelist with the first available else the default.
- :param bool update_pricelist: Force to recompute all the lines from sales order to adapt the price with the current pricelist.
- :param int force_pricelist: pricelist_id - if set, we change the pricelist with this one
- :returns: browse record for the current sales order
- """
- self.ensure_one()
- partner = self.env.user.partner_id
- sale_order_id = request.session.get('sale_order_id')
- if not sale_order_id:
- last_order = partner.last_website_so_id
- available_pricelists = self.get_pricelist_available()
- # Do not reload the cart of this user last visit if the cart is no longer draft or uses a pricelist no longer available.
- sale_order_id = last_order.state == 'draft' and last_order.pricelist_id in available_pricelists and last_order.id
-
- pricelist_id = request.session.get('website_sale_current_pl') or self.get_current_pricelist().id
-
- if self.env['product.pricelist'].browse(force_pricelist).exists():
- pricelist_id = force_pricelist
- request.session['website_sale_current_pl'] = pricelist_id
- update_pricelist = True
-
- if not self._context.get('pricelist'):
- self = self.with_context(pricelist=pricelist_id)
-
- # Test validity of the sale_order_id
- sale_order = self.env['sale.order'].sudo().browse(sale_order_id).exists() if sale_order_id else None
-
- # create so if needed
- if not sale_order and (force_create or code):
- # TODO cache partner_id session
- pricelist = self.env['product.pricelist'].browse(pricelist_id).sudo()
- so_data = self._prepare_sale_order_values(partner, pricelist)
- sale_order = self.env['sale.order'].sudo().create(so_data)
-
- # set fiscal position
- if request.website.partner_id.id != partner.id:
- sale_order.onchange_partner_shipping_id()
- else: # For public user, fiscal position based on geolocation
- country_code = request.session['geoip'].get('country_code')
- if country_code:
- country_id = request.env['res.country'].search([('code', '=', country_code)], limit=1).id
- fp_id = request.env['account.fiscal.position'].sudo()._get_fpos_by_region(country_id)
- sale_order.fiscal_position_id = fp_id
- else:
- # if no geolocation, use the public user fp
- sale_order.onchange_partner_shipping_id()
-
- request.session['sale_order_id'] = sale_order.id
-
- if request.website.partner_id.id != partner.id:
- partner.write({'last_website_so_id': sale_order.id})
-
- if sale_order:
- # case when user emptied the cart
- if not request.session.get('sale_order_id'):
- request.session['sale_order_id'] = sale_order.id
-
- # check for change of pricelist with a coupon
- pricelist_id = pricelist_id or partner.property_product_pricelist.id
-
- # check for change of partner_id ie after signup
- if sale_order.partner_id.id != partner.id and request.website.partner_id.id != partner.id:
- flag_pricelist = False
- if pricelist_id != sale_order.pricelist_id.id:
- flag_pricelist = True
- fiscal_position = sale_order.fiscal_position_id.id
-
- # change the partner, and trigger the onchange
- sale_order.write({'partner_id': partner.id})
- sale_order.onchange_partner_id()
- sale_order.onchange_partner_shipping_id() # fiscal position
- sale_order['payment_term_id'] = self.sale_get_payment_term(partner)
-
- # check the pricelist : update it if the pricelist is not the 'forced' one
- values = {}
- if sale_order.pricelist_id:
- if sale_order.pricelist_id.id != pricelist_id:
- values['pricelist_id'] = pricelist_id
- update_pricelist = True
-
- # if fiscal position, update the order lines taxes
- if sale_order.fiscal_position_id:
- sale_order._compute_tax_id()
-
- # if values, then make the SO update
- if values:
- sale_order.write(values)
-
- # check if the fiscal position has changed with the partner_id update
- recent_fiscal_position = sale_order.fiscal_position_id.id
- if flag_pricelist or recent_fiscal_position != fiscal_position:
- update_pricelist = True
-
- if code and code != sale_order.pricelist_id.code:
- code_pricelist = self.env['product.pricelist'].sudo().search([('code', '=', code)], limit=1)
- if code_pricelist:
- pricelist_id = code_pricelist.id
- update_pricelist = True
- elif code is not None and sale_order.pricelist_id.code:
- # code is not None when user removes code and click on "Apply"
- pricelist_id = partner.property_product_pricelist.id
- update_pricelist = True
-
- # update the pricelist
- if update_pricelist:
- request.session['website_sale_current_pl'] = pricelist_id
- values = {'pricelist_id': pricelist_id}
- sale_order.write(values)
- for line in sale_order.order_line:
- if line.exists():
- sale_order._cart_update(product_id=line.product_id.id, line_id=line.id, add_qty=0)
-
- else:
- request.session['sale_order_id'] = None
- return None
-
- return sale_order
-
- def sale_get_transaction(self):
- tx_id = request.session.get('sale_transaction_id')
- if tx_id:
- transaction = self.env['payment.transaction'].sudo().browse(tx_id)
- # Ugly hack for SIPS: SIPS does not allow to reuse a payment reference, even if the
- # payment was not not proceeded. For example:
- # - Select SIPS for payment
- # - Be redirected to SIPS website
- # - Go back to eCommerce without paying
- # - Be redirected to SIPS website again => error
- # Since there is no link module between 'website_sale' and 'payment_sips', we prevent
- # here to reuse any previous transaction for SIPS.
- if transaction.state != 'cancel' and transaction.acquirer_id.provider != 'sips':
- return transaction
- else:
- request.session['sale_transaction_id'] = False
- return False
-
- def sale_reset(self):
- request.session.update({
- 'sale_order_id': False,
- 'sale_transaction_id': False,
- 'website_sale_current_pl': False,
- })
-
-
class ResCountry(models.Model):
_inherit = 'res.country'
diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py
index 8cf1e6b78ae..2878c0bfc20 100644
--- a/addons/website_sale/models/website.py
+++ b/addons/website_sale/models/website.py
@@ -1,12 +1,325 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import api, models
+import logging
+
+from odoo import api, fields, models, tools
+
+from odoo.http import request
+
+_logger = logging.getLogger(__name__)
class Website(models.Model):
_inherit = 'website'
+ pricelist_id = fields.Many2one('product.pricelist', compute='_compute_pricelist_id', string='Default Pricelist')
+ 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')
+
+ @api.one
+ def _compute_pricelist_ids(self):
+ self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)])
+
+ @api.multi
+ def _compute_pricelist_id(self):
+ for website in self:
+ if website._context.get('website_id') != website.id:
+ website = website.with_context(website_id=website.id)
+ 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):
+ """ 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)
+ :param int website_pl: The default pricelist used on this website
+ :param int current_pl: The current pricelist used on the website
+ (If not selectable but the current pricelist we had this pricelist anyway)
+ :param list all_pl: List of all pricelist available for this website
+ :param int partner_pl: the partner pricelist
+ :param int order_pl: the current cart pricelist
+ :returns: list of pricelist ids
+ """
+ pricelists = self.env['product.pricelist']
+ 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):
+ pricelists |= group_pricelists
+
+ partner = self.env.user.partner_id
+ is_public = self.user_id.id == self.env.user.id
+ if not is_public and (not pricelists or (partner_pl or partner.property_product_pricelist.id) != website_pl):
+ if partner.property_product_pricelist.website_id:
+ 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))
+ else:
+ pricelists |= all_pl.filtered(lambda pl: not show_visible and pl.sudo().code)
+
+ # This method is cached, must not return records! See also #8795
+ return pricelists.ids
+
+ def _get_pl(self, country_code, show_visible, website_pl, current_pl, all_pl):
+ pl_ids = self._get_pl_partner_order(country_code, show_visible, website_pl, current_pl, all_pl)
+ return self.env['product.pricelist'].browse(pl_ids)
+
+ def get_pricelist_available(self, show_visible=False):
+
+ """ Return the list of pricelists that can be used on website for the current user.
+ Country restrictions will be detected with GeoIP (if installed).
+ :param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo)
+ :returns: pricelist recordset
+ """
+ website = request.website
+ if not request.website:
+ if self.env.context.get('website_id'):
+ website = self.browse(self.env.context['website_id'])
+ else:
+ website = self.search([], limit=1)
+ isocountry = request.session.geoip and request.session.geoip.get('country_code') or False
+ partner = self.env.user.partner_id
+ order_pl = partner.last_website_so_id and partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id
+ partner_pl = partner.property_product_pricelist
+ pricelists = website._get_pl_partner_order(isocountry, show_visible,
+ website.user_id.sudo().partner_id.property_product_pricelist.id,
+ request.session.get('website_sale_current_pl'),
+ website.pricelist_ids,
+ partner_pl=partner_pl and partner_pl.id or None,
+ order_pl=order_pl and order_pl.id or None)
+ return self.env['product.pricelist'].browse(pricelists)
+
+ def is_pricelist_available(self, pl_id):
+ """ Return a boolean to specify if a specific pricelist can be manually set on the website.
+ Warning: It check only if pricelist is in the 'selectable' pricelists or the current pricelist.
+ :param int pl_id: The pricelist id to check
+ :returns: Boolean, True if valid / available
+ """
+ return pl_id in self.get_pricelist_available(show_visible=False).ids
+
+ def get_current_pricelist(self):
+ """
+ :returns: The current pricelist record
+ """
+ # The list of available pricelists for this user.
+ # If the user is signed in, and has a pricelist set different than the public user pricelist
+ # then this pricelist will always be considered as available
+ available_pricelists = self.get_pricelist_available()
+ pl = None
+ partner = self.env.user.partner_id
+ if request.session.get('website_sale_current_pl'):
+ # `website_sale_current_pl` is set only if the user specifically chose it:
+ # - Either, he chose it from the pricelist selection
+ # - Either, he entered a coupon code
+ pl = self.env['product.pricelist'].browse(request.session['website_sale_current_pl'])
+ if pl not in available_pricelists:
+ pl = None
+ request.session.pop('website_sale_current_pl')
+ if not pl:
+ # If the user has a saved cart, it take the pricelist of this cart, except if
+ # the order is no longer draft (It has already been confirmed, or cancelled, ...)
+ pl = partner.last_website_so_id.state == 'draft' and partner.last_website_so_id.pricelist_id
+ if not pl:
+ # The pricelist of the user set on its partner form.
+ # If the user is not signed in, it's the public user pricelist
+ pl = partner.property_product_pricelist
+ if available_pricelists and pl not in available_pricelists:
+ # If there is at least one pricelist in the available pricelists
+ # and the chosen pricelist is not within them
+ # it then choose the first available pricelist.
+ # This can only happen when the pricelist is the public user pricelist and this pricelist is not in the available pricelist for this localization
+ # If the user is signed in, and has a special pricelist (different than the public user pricelist),
+ # then this special pricelist is amongs these available pricelists, and therefore it won't fall in this case.
+ pl = available_pricelists[0]
+
+ if not pl:
+ _logger.error('Fail to find pricelist for partner "%s" (id %s)', partner.name, partner.id)
+ return pl
+
+ @api.multi
+ def sale_product_domain(self):
+ return [("sale_ok", "=", True)]
+
+ @api.model
+ def sale_get_payment_term(self, partner):
+ DEFAULT_PAYMENT_TERM = 'account.account_payment_term_immediate'
+ return self.env.ref(DEFAULT_PAYMENT_TERM, False).id or partner.property_payment_term_id.id
+
+ @api.multi
+ def _prepare_sale_order_values(self, partner, pricelist):
+ self.ensure_one()
+ affiliate_id = request.session.get('affiliate_id')
+ salesperson_id = affiliate_id if self.env['res.users'].sudo().browse(affiliate_id).exists() else request.website.salesperson_id.id
+ addr = partner.address_get(['delivery', 'invoice'])
+ values = {
+ 'partner_id': partner.id,
+ 'pricelist_id': pricelist.id,
+ 'payment_term_id': self.sale_get_payment_term(partner),
+ 'team_id': self.salesteam_id.id,
+ 'partner_invoice_id': addr['invoice'],
+ 'partner_shipping_id': addr['delivery'],
+ 'user_id': salesperson_id or self.salesperson_id.id,
+ }
+ company = self.company_id or pricelist.company_id
+ if company:
+ values['company_id'] = company.id
+
+ return values
+
+ @api.multi
+ def sale_get_order(self, force_create=False, code=None, update_pricelist=False, force_pricelist=False):
+ """ Return the current sales order after mofications specified by params.
+ :param bool force_create: Create sales order if not already existing
+ :param str code: Code to force a pricelist (promo code)
+ If empty, it's a special case to reset the pricelist with the first available else the default.
+ :param bool update_pricelist: Force to recompute all the lines from sales order to adapt the price with the current pricelist.
+ :param int force_pricelist: pricelist_id - if set, we change the pricelist with this one
+ :returns: browse record for the current sales order
+ """
+ self.ensure_one()
+ partner = self.env.user.partner_id
+ sale_order_id = request.session.get('sale_order_id')
+ if not sale_order_id:
+ last_order = partner.last_website_so_id
+ available_pricelists = self.get_pricelist_available()
+ # Do not reload the cart of this user last visit if the cart is no longer draft or uses a pricelist no longer available.
+ sale_order_id = last_order.state == 'draft' and last_order.pricelist_id in available_pricelists and last_order.id
+
+ pricelist_id = request.session.get('website_sale_current_pl') or self.get_current_pricelist().id
+
+ if self.env['product.pricelist'].browse(force_pricelist).exists():
+ pricelist_id = force_pricelist
+ request.session['website_sale_current_pl'] = pricelist_id
+ update_pricelist = True
+
+ if not self._context.get('pricelist'):
+ self = self.with_context(pricelist=pricelist_id)
+
+ # Test validity of the sale_order_id
+ sale_order = self.env['sale.order'].sudo().browse(sale_order_id).exists() if sale_order_id else None
+
+ # create so if needed
+ if not sale_order and (force_create or code):
+ # TODO cache partner_id session
+ pricelist = self.env['product.pricelist'].browse(pricelist_id).sudo()
+ so_data = self._prepare_sale_order_values(partner, pricelist)
+ sale_order = self.env['sale.order'].sudo().create(so_data)
+
+ # set fiscal position
+ if request.website.partner_id.id != partner.id:
+ sale_order.onchange_partner_shipping_id()
+ else: # For public user, fiscal position based on geolocation
+ country_code = request.session['geoip'].get('country_code')
+ if country_code:
+ country_id = request.env['res.country'].search([('code', '=', country_code)], limit=1).id
+ fp_id = request.env['account.fiscal.position'].sudo()._get_fpos_by_region(country_id)
+ sale_order.fiscal_position_id = fp_id
+ else:
+ # if no geolocation, use the public user fp
+ sale_order.onchange_partner_shipping_id()
+
+ request.session['sale_order_id'] = sale_order.id
+
+ if request.website.partner_id.id != partner.id:
+ partner.write({'last_website_so_id': sale_order.id})
+
+ if sale_order:
+ # case when user emptied the cart
+ if not request.session.get('sale_order_id'):
+ request.session['sale_order_id'] = sale_order.id
+
+ # check for change of pricelist with a coupon
+ pricelist_id = pricelist_id or partner.property_product_pricelist.id
+
+ # check for change of partner_id ie after signup
+ if sale_order.partner_id.id != partner.id and request.website.partner_id.id != partner.id:
+ flag_pricelist = False
+ if pricelist_id != sale_order.pricelist_id.id:
+ flag_pricelist = True
+ fiscal_position = sale_order.fiscal_position_id.id
+
+ # change the partner, and trigger the onchange
+ sale_order.write({'partner_id': partner.id})
+ sale_order.onchange_partner_id()
+ sale_order.onchange_partner_shipping_id() # fiscal position
+ sale_order['payment_term_id'] = self.sale_get_payment_term(partner)
+
+ # check the pricelist : update it if the pricelist is not the 'forced' one
+ values = {}
+ if sale_order.pricelist_id:
+ if sale_order.pricelist_id.id != pricelist_id:
+ values['pricelist_id'] = pricelist_id
+ update_pricelist = True
+
+ # if fiscal position, update the order lines taxes
+ if sale_order.fiscal_position_id:
+ sale_order._compute_tax_id()
+
+ # if values, then make the SO update
+ if values:
+ sale_order.write(values)
+
+ # check if the fiscal position has changed with the partner_id update
+ recent_fiscal_position = sale_order.fiscal_position_id.id
+ if flag_pricelist or recent_fiscal_position != fiscal_position:
+ update_pricelist = True
+
+ if code and code != sale_order.pricelist_id.code:
+ code_pricelist = self.env['product.pricelist'].sudo().search([('code', '=', code)], limit=1)
+ if code_pricelist:
+ pricelist_id = code_pricelist.id
+ update_pricelist = True
+ elif code is not None and sale_order.pricelist_id.code:
+ # code is not None when user removes code and click on "Apply"
+ pricelist_id = partner.property_product_pricelist.id
+ update_pricelist = True
+
+ # update the pricelist
+ if update_pricelist:
+ request.session['website_sale_current_pl'] = pricelist_id
+ values = {'pricelist_id': pricelist_id}
+ sale_order.write(values)
+ for line in sale_order.order_line:
+ if line.exists():
+ sale_order._cart_update(product_id=line.product_id.id, line_id=line.id, add_qty=0)
+
+ else:
+ request.session['sale_order_id'] = None
+ return None
+
+ return sale_order
+
+ def sale_get_transaction(self):
+ tx_id = request.session.get('sale_transaction_id')
+ if tx_id:
+ transaction = self.env['payment.transaction'].sudo().browse(tx_id)
+ # Ugly hack for SIPS: SIPS does not allow to reuse a payment reference, even if the
+ # payment was not not proceeded. For example:
+ # - Select SIPS for payment
+ # - Be redirected to SIPS website
+ # - Go back to eCommerce without paying
+ # - Be redirected to SIPS website again => error
+ # Since there is no link module between 'website_sale' and 'payment_sips', we prevent
+ # here to reuse any previous transaction for SIPS.
+ if transaction.state != 'cancel' and transaction.acquirer_id.provider != 'sips':
+ return transaction
+ else:
+ request.session['sale_transaction_id'] = False
+ return False
+
+ def sale_reset(self):
+ request.session.update({
+ 'sale_order_id': False,
+ 'sale_transaction_id': False,
+ 'website_sale_current_pl': False,
+ })
+
@api.model
def action_dashboard_redirect(self):
if self.env.user.has_group('sales_team.group_sale_salesman'):
diff --git a/addons/website_sale/tests/test_website_sale_pricelist.py b/addons/website_sale/tests/test_website_sale_pricelist.py
index 0b354a4bed6..cf97fd815cc 100644
--- a/addons/website_sale/tests/test_website_sale_pricelist.py
+++ b/addons/website_sale/tests/test_website_sale_pricelist.py
@@ -36,8 +36,7 @@ class TestWebsitePriceList(TransactionCase):
'country_group_ids': [(6, 0, [ca_group.id])],
'sequence': 10
})
- import odoo.addons.website_sale.models.sale_order
- patcher = patch('odoo.addons.website_sale.models.sale_order.Website.get_pricelist_available', wraps=self._get_pricelist_available)
+ patcher = patch('odoo.addons.website_sale.models.website.Website.get_pricelist_available', wraps=self._get_pricelist_available)
patcher.start()
self.addCleanup(patcher.stop)