519 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			519 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| # Part of Odoo. See LICENSE file for full copyright and licensing details.
 | |
| import logging
 | |
| import random
 | |
| 
 | |
| from odoo import api, models, fields, tools, _
 | |
| from odoo.http import request
 | |
| from odoo.exceptions import UserError, ValidationError
 | |
| 
 | |
| _logger = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| class SaleOrder(models.Model):
 | |
|     _inherit = "sale.order"
 | |
| 
 | |
|     website_order_line = fields.One2many(
 | |
|         'sale.order.line', 'order_id',
 | |
|         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.',
 | |
|     )
 | |
|     cart_quantity = fields.Integer(compute='_compute_cart_info', string='Cart Quantity')
 | |
|     payment_acquirer_id = fields.Many2one('payment.acquirer', string='Payment Acquirer', copy=False)
 | |
|     payment_tx_id = fields.Many2one('payment.transaction', string='Transaction', copy=False)
 | |
|     only_services = fields.Boolean(compute='_compute_cart_info', string='Only Services')
 | |
| 
 | |
|     @api.multi
 | |
|     @api.depends('website_order_line.product_uom_qty', 'website_order_line.product_id')
 | |
|     def _compute_cart_info(self):
 | |
|         for order in self:
 | |
|             order.cart_quantity = int(sum(order.mapped('website_order_line.product_uom_qty')))
 | |
|             order.only_services = all(l.product_id.type in ('service', 'digital') for l in order.website_order_line)
 | |
| 
 | |
|     @api.model
 | |
|     def _get_errors(self, order):
 | |
|         return []
 | |
| 
 | |
|     @api.model
 | |
|     def _get_website_data(self, order):
 | |
|         return {
 | |
|             'partner': order.partner_id.id,
 | |
|             'order': order
 | |
|         }
 | |
| 
 | |
|     @api.multi
 | |
|     def _cart_find_product_line(self, product_id=None, line_id=None, **kwargs):
 | |
|         self.ensure_one()
 | |
|         product = self.env['product.product'].browse(product_id)
 | |
| 
 | |
|         # split lines with the same product if it has untracked attributes
 | |
|         if product and product.mapped('attribute_line_ids').filtered(lambda r: not r.attribute_id.create_variant) and not line_id:
 | |
|             return self.env['sale.order.line']
 | |
| 
 | |
|         domain = [('order_id', '=', self.id), ('product_id', '=', product_id)]
 | |
|         if line_id:
 | |
|             domain += [('id', '=', line_id)]
 | |
|         return self.env['sale.order.line'].sudo().search(domain)
 | |
| 
 | |
|     @api.multi
 | |
|     def _website_product_id_change(self, order_id, product_id, qty=0):
 | |
|         order = self.sudo().browse(order_id)
 | |
|         product_context = dict(self.env.context)
 | |
|         product_context.setdefault('lang', order.partner_id.lang)
 | |
|         product_context.update({
 | |
|             'partner': order.partner_id.id,
 | |
|             'quantity': qty,
 | |
|             'date': order.date_order,
 | |
|             'pricelist': order.pricelist_id.id,
 | |
|         })
 | |
|         product = self.env['product.product'].with_context(product_context).browse(product_id)
 | |
|         pu = product.price
 | |
|         if order.pricelist_id and order.partner_id:
 | |
|             order_line = order._cart_find_product_line(product.id)
 | |
|             if order_line:
 | |
|                 pu = self.env['account.tax']._fix_tax_included_price_company(pu, product.taxes_id, order_line[0].tax_id, self.company_id)
 | |
| 
 | |
|         return {
 | |
|             'product_id': product_id,
 | |
|             'product_uom_qty': qty,
 | |
|             'order_id': order_id,
 | |
|             'product_uom': product.uom_id.id,
 | |
|             'price_unit': pu,
 | |
|         }
 | |
| 
 | |
|     @api.multi
 | |
|     def _get_line_description(self, order_id, product_id, attributes=None):
 | |
|         if not attributes:
 | |
|             attributes = {}
 | |
| 
 | |
|         order = self.sudo().browse(order_id)
 | |
|         product_context = dict(self.env.context)
 | |
|         product_context.setdefault('lang', order.partner_id.lang)
 | |
|         product = self.env['product.product'].with_context(product_context).browse(product_id)
 | |
| 
 | |
|         name = product.display_name
 | |
| 
 | |
|         # add untracked attributes in the name
 | |
|         untracked_attributes = []
 | |
|         for k, v in attributes.items():
 | |
|             # attribute should be like 'attribute-48-1' where 48 is the product_id, 1 is the attribute_id and v is the attribute value
 | |
|             attribute_value = self.env['product.attribute.value'].sudo().browse(int(v))
 | |
|             if attribute_value and not attribute_value.attribute_id.create_variant:
 | |
|                 untracked_attributes.append(attribute_value.name)
 | |
|         if untracked_attributes:
 | |
|             name += '\n%s' % (', '.join(untracked_attributes))
 | |
| 
 | |
|         if product.description_sale:
 | |
|             name += '\n%s' % (product.description_sale)
 | |
| 
 | |
|         return name
 | |
| 
 | |
|     @api.multi
 | |
|     def _cart_update(self, product_id=None, line_id=None, add_qty=0, set_qty=0, attributes=None, **kwargs):
 | |
|         """ Add or set product quantity, add_qty can be negative """
 | |
|         self.ensure_one()
 | |
|         SaleOrderLineSudo = self.env['sale.order.line'].sudo()
 | |
| 
 | |
|         try:
 | |
|             if add_qty:
 | |
|                 add_qty = float(add_qty)
 | |
|         except ValueError:
 | |
|             add_qty = 1
 | |
|         try:
 | |
|             if set_qty:
 | |
|                 set_qty = float(set_qty)
 | |
|         except ValueError:
 | |
|             set_qty = 0
 | |
|         quantity = 0
 | |
|         order_line = False
 | |
|         if self.state != 'draft':
 | |
|             request.session['sale_order_id'] = None
 | |
|             raise UserError(_('It is forbidden to modify a sale order which is not in draft status'))
 | |
|         if line_id is not False:
 | |
|             order_lines = self._cart_find_product_line(product_id, line_id, **kwargs)
 | |
|             order_line = order_lines and order_lines[0]
 | |
| 
 | |
|         # Create line if no line with product_id can be located
 | |
|         if not order_line:
 | |
|             values = self._website_product_id_change(self.id, product_id, qty=1)
 | |
|             values['name'] = self._get_line_description(self.id, product_id, attributes=attributes)
 | |
|             order_line = SaleOrderLineSudo.create(values)
 | |
| 
 | |
|             try:
 | |
|                 order_line._compute_tax_id()
 | |
|             except ValidationError as e:
 | |
|                 # The validation may occur in backend (eg: taxcloud) but should fail silently in frontend
 | |
|                 _logger.debug("ValidationError occurs during tax compute. %s" % (e))
 | |
|             if add_qty:
 | |
|                 add_qty -= 1
 | |
| 
 | |
|         # compute new quantity
 | |
|         if set_qty:
 | |
|             quantity = set_qty
 | |
|         elif add_qty is not None:
 | |
|             quantity = order_line.product_uom_qty + (add_qty or 0)
 | |
| 
 | |
|         # Remove zero of negative lines
 | |
|         if quantity <= 0:
 | |
|             order_line.unlink()
 | |
|         else:
 | |
|             # update line
 | |
|             values = self._website_product_id_change(self.id, product_id, qty=quantity)
 | |
|             if self.pricelist_id.discount_policy == 'with_discount' and not self.env.context.get('fixed_price'):
 | |
|                 order = self.sudo().browse(self.id)
 | |
|                 product_context = dict(self.env.context)
 | |
|                 product_context.setdefault('lang', order.partner_id.lang)
 | |
|                 product_context.update({
 | |
|                     'partner': order.partner_id.id,
 | |
|                     'quantity': quantity,
 | |
|                     'date': order.date_order,
 | |
|                     'pricelist': order.pricelist_id.id,
 | |
|                 })
 | |
|                 product = self.env['product.product'].with_context(product_context).browse(product_id)
 | |
|                 values['price_unit'] = self.env['account.tax']._fix_tax_included_price_company(
 | |
|                     order_line._get_display_price(product),
 | |
|                     order_line.product_id.taxes_id,
 | |
|                     order_line.tax_id,
 | |
|                     self.company_id
 | |
|                 )
 | |
| 
 | |
|             order_line.write(values)
 | |
| 
 | |
|         return {'line_id': order_line.id, 'quantity': quantity}
 | |
| 
 | |
|     def _cart_accessories(self):
 | |
|         """ Suggest accessories based on 'Accessory Products' of products in cart """
 | |
|         for order in self:
 | |
|             accessory_products = order.website_order_line.mapped('product_id.accessory_product_ids').filtered(lambda product: product.website_published)
 | |
|             accessory_products -= order.website_order_line.mapped('product_id')
 | |
|             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', related_sudo=False, string='Default Currency')
 | |
|     salesperson_id = fields.Many2one('res.users', string='Salesperson')
 | |
|     salesteam_id = fields.Many2one('crm.team', string='Sales Team')
 | |
|     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 and hasattr(request, 'website') and request.website or None
 | |
|         if not website:
 | |
|             if self.env.context.get('website_id'):
 | |
|                 website = self.browse(self.env.context['website_id'])
 | |
|             else:
 | |
|                 # In the weird case we are coming from the backend (https://github.com/odoo/odoo/issues/20245)
 | |
|                 website = len(self) == 1 and self or self.search([], limit=1)
 | |
|         isocountry = request and 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 and request.session.get('website_sale_current_pl') or None,
 | |
|                                                    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 and 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 partner.property_payment_term_id.id or self.env.ref(DEFAULT_PAYMENT_TERM, False).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'])
 | |
|         default_user_id = partner.parent_id.user_id.id or partner.user_id.id
 | |
|         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 or default_user_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 sale order after mofications specified by params.
 | |
|         :param bool force_create: Create sale 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 sale 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 sale 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 self.env['sale.order']
 | |
| 
 | |
|         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'
 | |
| 
 | |
|     def get_website_sale_countries(self, mode='billing'):
 | |
|         return self.sudo().search([])
 | |
| 
 | |
|     def get_website_sale_states(self, mode='billing'):
 | |
|         return self.sudo().state_ids
 | |
| 
 | |
| 
 | |
| class ResPartner(models.Model):
 | |
|     _inherit = 'res.partner'
 | |
| 
 | |
|     last_website_so_id = fields.Many2one('sale.order', string='Last Online Sale Order')
 |