138 lines
6.2 KiB
Python
138 lines
6.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import logging
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SaleOrder(models.Model):
|
|
_inherit = 'sale.order'
|
|
|
|
amount_delivery = fields.Monetary(
|
|
compute='_compute_amount_delivery', digits=0,
|
|
string='Delivery Amount',
|
|
help="The amount without tax.", store=True, track_visibility='always')
|
|
has_delivery = fields.Boolean(
|
|
compute='_compute_has_delivery', string='Has delivery',
|
|
help="Has an order line set for delivery", store=True)
|
|
website_order_line = fields.One2many(
|
|
'sale.order.line', 'order_id',
|
|
string='Order Lines displayed on Website', readonly=True,
|
|
domain=[('is_delivery', '=', False)],
|
|
help='Order Lines to be displayed on the website. They should not be used for computation purpose.')
|
|
|
|
@api.depends('order_line.price_unit', 'order_line.tax_id', 'order_line.discount', 'order_line.product_uom_qty')
|
|
def _compute_amount_delivery(self):
|
|
for order in self:
|
|
if self.env.user.has_group('sale.group_show_price_subtotal'):
|
|
order.amount_delivery = sum(order.order_line.filtered('is_delivery').mapped('price_subtotal'))
|
|
else:
|
|
order.amount_delivery = sum(order.order_line.filtered('is_delivery').mapped('price_total'))
|
|
|
|
@api.depends('order_line.is_delivery')
|
|
def _compute_has_delivery(self):
|
|
for order in self:
|
|
order.has_delivery = any(order.order_line.filtered('is_delivery'))
|
|
|
|
def _check_carrier_quotation(self, force_carrier_id=None):
|
|
# check to add or remove carrier_id
|
|
if not self:
|
|
return False
|
|
self.ensure_one()
|
|
DeliveryCarrier = self.env['delivery.carrier']
|
|
if self.only_services:
|
|
self.write({'carrier_id': None})
|
|
self._delivery_unset()
|
|
return True
|
|
else:
|
|
carrier = force_carrier_id and DeliveryCarrier.browse(force_carrier_id) or self.carrier_id
|
|
available_carriers = self._get_delivery_methods()
|
|
if carrier:
|
|
if carrier not in available_carriers:
|
|
carrier = DeliveryCarrier
|
|
else:
|
|
# set the forced carrier at the beginning of the list to be verfied first below
|
|
available_carriers -= carrier
|
|
available_carriers = carrier + available_carriers
|
|
if force_carrier_id or not carrier or carrier not in available_carriers:
|
|
for delivery in available_carriers:
|
|
verified_carrier = delivery.verify_carrier(self.partner_shipping_id)
|
|
if verified_carrier:
|
|
carrier = delivery
|
|
break
|
|
self.write({'carrier_id': carrier.id})
|
|
if carrier:
|
|
self.delivery_set()
|
|
else:
|
|
self._delivery_unset()
|
|
|
|
return bool(carrier)
|
|
|
|
def _get_delivery_methods(self):
|
|
"""Return the available and published delivery carriers"""
|
|
self.ensure_one()
|
|
available_carriers = DeliveryCarrier = self.env['delivery.carrier']
|
|
# Following loop is done to avoid displaying delivery methods who are not available for this order
|
|
# This can surely be done in a more efficient way, but at the moment, it mimics the way it's
|
|
# done in delivery_set method of sale.py, from delivery module
|
|
carrier_ids = DeliveryCarrier.sudo().search(
|
|
[('website_published', '=', True)]).ids
|
|
for carrier_id in carrier_ids:
|
|
carrier = DeliveryCarrier.browse(carrier_id)
|
|
try:
|
|
_logger.debug("Checking availability of carrier #%s" % carrier_id)
|
|
available = carrier.with_context(order_id=self.id).read(fields=['available'])[0]['available']
|
|
if available:
|
|
available_carriers += carrier
|
|
except ValidationError as e:
|
|
# RIM TODO: hack to remove, make available field not depend on a SOAP call to external shipping provider
|
|
# The validation error is used in backend to display errors in fedex config, but should fail silently in frontend
|
|
_logger.debug("Carrier #%s removed from e-commerce carrier list. %s" % (carrier_id, e))
|
|
return available_carriers
|
|
|
|
@api.model
|
|
def _get_errors(self, order):
|
|
errors = super(SaleOrder, self)._get_errors(order)
|
|
if not order._get_delivery_methods():
|
|
errors.append(
|
|
(_('Sorry, we are unable to ship your order'),
|
|
_('No shipping method is available for your current order and shipping address. '
|
|
'Please contact us for more information.')))
|
|
return errors
|
|
|
|
@api.model
|
|
def _get_website_data(self, order):
|
|
""" Override to add delivery-related website data. """
|
|
values = super(SaleOrder, self)._get_website_data(order)
|
|
# We need a delivery only if we have stockable products
|
|
has_stockable_products = any(order.order_line.filtered(lambda line: line.product_id.type in ['consu', 'product']))
|
|
if not has_stockable_products:
|
|
return values
|
|
|
|
delivery_carriers = order._get_delivery_methods()
|
|
values['deliveries'] = delivery_carriers.sudo().with_context(order_id=order.id)
|
|
return values
|
|
|
|
@api.multi
|
|
def _cart_update(self, product_id=None, line_id=None, add_qty=0, set_qty=0, **kwargs):
|
|
""" Override to update carrier quotation if quantity changed """
|
|
|
|
self._delivery_unset()
|
|
|
|
# When you update a cart, it is not enouf to remove the "delivery cost" line
|
|
# The carrier might also be invalid, eg: if you bought things that are too heavy
|
|
# -> this may cause a bug if you go to the checkout screen, choose a carrier,
|
|
# then update your cart (the cart becomes uneditable)
|
|
self.write({'carrier_id': False})
|
|
|
|
values = super(SaleOrder, self)._cart_update(product_id, line_id, add_qty, set_qty, **kwargs)
|
|
|
|
if add_qty or set_qty is not None:
|
|
for sale_order in self:
|
|
self._check_carrier_quotation()
|
|
|
|
return values
|