Files
suite/sale_planner/models/delivery.py

103 lines
4.3 KiB
Python

from datetime import timedelta
from odoo import api, fields, models
class DeliveryCarrier(models.Model):
_inherit = 'delivery.carrier'
delivery_calendar_id = fields.Many2one(
'resource.calendar', 'Delivery Calendar',
help="This calendar represents days that the carrier will deliver the package.")
# -------------------------- #
# API for external providers #
# -------------------------- #
def get_shipping_price_for_plan(self, orders, date_planned):
''' For every sale order, compute the price of the shipment
:param orders: A recordset of sale orders
:param date_planned: Date to say that the shipment is leaving.
:return list: A list of floats, containing the estimated price for the shipping of the sale order
'''
self.ensure_one()
if hasattr(self, '%s_get_shipping_price_for_plan' % self.delivery_type):
return getattr(self, '%s_get_shipping_price_for_plan' % self.delivery_type)(orders, date_planned)
def rate_shipment_date_planned(self, order, date_planned=None):
"""
For every sale order, compute the price of the shipment and potentially when it will arrive.
:param order: `sale.order`
:param date_planned: The date the shipment is expected to leave/be picked up by carrier.
:return: rate in the same form the normal `rate_shipment` method does BUT
-- Additional keys
- transit_days: int
- date_delivered: string
"""
self.ensure_one()
if hasattr(self, '%s_rate_shipment_date_planned' % self.delivery_type):
# New API Odoo 11 - Carrier specific override.
return getattr(self, '%s_rate_shipment_date_planned' % self.delivery_type)(order, date_planned)
rate = self.with_context(date_planned=date_planned).rate_shipment(order)
if rate and date_planned:
if rate.get('date_delivered'):
date_delivered = rate['date_delivered']
transit_days = self.calculate_transit_days(date_planned, date_delivered)
if not rate.get('transit_days') or transit_days < rate.get('transit_days'):
rate['transit_days'] = transit_days
elif rate.get('transit_days'):
rate['date_delivered'] = self.calculate_date_delivered(date_planned, rate.get('transit_days'))
elif rate:
if rate.get('date_delivered'):
rate.pop('date_delivered')
return rate
def calculate_transit_days(self, date_planned, date_delivered):
self.ensure_one()
if isinstance(date_planned, str):
date_planned = fields.Datetime.from_string(date_planned)
if isinstance(date_delivered, str):
date_delivered = fields.Datetime.from_string(date_delivered)
transit_days = 0
while date_planned < date_delivered:
if transit_days > 10:
break
current_date_planned = self.delivery_calendar_id.plan_days(1, date_planned, compute_leaves=True)
if not current_date_planned:
return self._calculate_transit_days_naive(date_planned, date_delivered)
if current_date_planned == date_planned:
date_planned += timedelta(days=1)
else:
date_planned = current_date_planned
transit_days += 1
if transit_days > 1:
transit_days -= 1
return transit_days
def _calculate_transit_days_naive(self, date_planned, date_delivered):
return abs((date_delivered - date_planned).days)
def calculate_date_delivered(self, date_planned, transit_days):
self.ensure_one()
if isinstance(date_planned, str):
date_planned = fields.Datetime.from_string(date_planned)
# date calculations needs an extra day
effective_transit_days = transit_days + 1
last_day = self.delivery_calendar_id.plan_days(effective_transit_days, date_planned, compute_leaves=True)
if not last_day:
return self._calculate_date_delivered_naive(date_planned, transit_days)
return fields.Datetime.to_string(last_day)
def _calculate_date_delivered_naive(self, date_planned, transit_days):
return fields.Datetime.to_string(date_planned + timedelta(days=transit_days))