[REF] delivery: Packages and Commodities in base
Each delivery provider, requires some information about the packages that need to be sent as well as about the commodities (for commecial invoices). Since this is needed by each provider, and the required values are very similar, these packages and commodities can be done one step ahead: in the base delivery module. These new `_get` functions return a list of custom objects containing the most important values concerning packages and commodities, and can be called directly from the child classes. closes odoo/odoo#82891 Signed-off-by: Arnold Moyaux <arm@odoo.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
import psycopg2
|
||||
|
||||
from odoo import api, fields, models, registry, SUPERUSER_ID, _
|
||||
from odoo.tools.float_utils import float_round
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
from .delivery_request_objects import DeliveryCommodity, DeliveryPackage
|
||||
|
||||
|
||||
class DeliveryCarrier(models.Model):
|
||||
@@ -277,3 +277,84 @@ class DeliveryCarrier(models.Model):
|
||||
|
||||
def fixed_cancel_shipment(self, pickings):
|
||||
raise NotImplementedError()
|
||||
|
||||
# -------------------------------- #
|
||||
# get default packages/commodities #
|
||||
# -------------------------------- #
|
||||
|
||||
def _get_packages_from_order(self, order, default_package_type):
|
||||
packages = []
|
||||
|
||||
total_cost = 0
|
||||
for line in order.order_line.filtered(lambda line: not line.is_delivery and not line.display_type):
|
||||
total_cost += self._product_price_to_company_currency(line.product_qty, line.product_id, order.company_id)
|
||||
|
||||
total_weight = order._get_estimated_weight()
|
||||
# If max weight == 0 => division by 0. If this happens, we want to have
|
||||
# more in the max weight than in the total weight, so that it only
|
||||
# creates ONE package with everything.
|
||||
max_weight = default_package_type.max_weight or total_weight + 1
|
||||
total_full_packages = int(total_weight / max_weight)
|
||||
last_package_weight = total_weight % max_weight
|
||||
|
||||
package_weights = [max_weight] * total_full_packages + [last_package_weight] if last_package_weight else []
|
||||
partial_cost = total_cost / len(package_weights) # separate the cost uniformly
|
||||
for weight in package_weights:
|
||||
packages.append(DeliveryPackage(None, weight, default_package_type, total_cost=partial_cost, currency=order.company_id.currency_id))
|
||||
return packages
|
||||
|
||||
def _get_packages_from_picking(self, picking, default_package_type):
|
||||
packages = []
|
||||
|
||||
if picking.is_return_picking:
|
||||
commodities = self._get_commodities_from_stock_move_lines(picking.move_line_ids)
|
||||
weight = picking._get_estimated_weight()
|
||||
packages.append(DeliveryPackage(commodities, weight, default_package_type, currency=picking.company_id.currency_id))
|
||||
return packages
|
||||
|
||||
# Create all packages.
|
||||
for package in picking.package_ids:
|
||||
move_lines = picking.move_line_ids.filtered(lambda ml: ml.result_package_id == package)
|
||||
commodities = self._get_commodities_from_stock_move_lines(move_lines)
|
||||
package_total_cost = 0.0
|
||||
for quant in package.quant_ids:
|
||||
package_total_cost += self._product_price_to_company_currency(quant.quantity, quant.product_id, picking.company_id)
|
||||
packages.append(DeliveryPackage(commodities, package.shipping_weight or package.weight, package.package_type_id, name=package.name, total_cost=package_total_cost, currency=picking.company_id.currency_id))
|
||||
|
||||
# Create one package: either everything is in pack or nothing is.
|
||||
if picking.weight_bulk:
|
||||
commodities = self._get_commodities_from_stock_move_lines(picking.move_line_ids)
|
||||
package_total_cost = 0.0
|
||||
for move_line in picking.move_line_ids:
|
||||
package_total_cost += self._product_price_to_company_currency(move_line.qty_done, move_line.product_id, picking.company_id)
|
||||
packages.append(DeliveryPackage(commodities, picking.weight_bulk, default_package_type, name='Bulk Content', total_cost=package_total_cost, currency=picking.company_id.currency_id))
|
||||
|
||||
return packages
|
||||
|
||||
def _get_commodities_from_order(self, order):
|
||||
commodities = []
|
||||
|
||||
for line in order.order_line.filtered(lambda line: not line.is_delivery and not line.display_type):
|
||||
unit_quantity = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
|
||||
rounded_qty = max(1, float_round(unit_quantity, precision_digits=0))
|
||||
country_of_origin = line.product_id.country_of_origin or order.warehouse_id.partner_id.country_id.code
|
||||
commodities.append(DeliveryCommodity(line.product_id, amount=rounded_qty, monetary_value=line.price_reduce_taxinc, country_of_origin=country_of_origin))
|
||||
|
||||
return commodities
|
||||
|
||||
def _get_commodities_from_stock_move_lines(self, move_lines):
|
||||
commodities = []
|
||||
|
||||
for line in move_lines.filtered(lambda line: line.product_id.type in ['product', 'consu']):
|
||||
if line.state == 'done':
|
||||
unit_quantity = line.product_uom_id._compute_quantity(line.qty_done, line.product_id.uom_id)
|
||||
else:
|
||||
unit_quantity = line.product_uom_id._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
|
||||
rounded_qty = max(1, float_round(unit_quantity, precision_digits=0))
|
||||
country_of_origin = line.product_id.country_of_origin or line.picking_id.picking_type_id.warehouse_id.partner_id.country_id.code
|
||||
commodities.append(DeliveryCommodity(line.product_id, amount=rounded_qty, monetary_value=line.sale_price, country_of_origin=country_of_origin))
|
||||
|
||||
return commodities
|
||||
|
||||
def _product_price_to_company_currency(self, quantity, product, company):
|
||||
return company.currency_id._convert(quantity * product.standard_price, product.currency_id, company, fields.Date.today())
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
class DeliveryPackage:
|
||||
""" Each provider need similar information about its packages. """
|
||||
def __init__(self, commodities, weight, package_type, name=None, total_cost=0, currency=None):
|
||||
""" The UOMs are based on the config parameters, which is very convenient:
|
||||
we do not need to keep those stored."""
|
||||
self.commodities = commodities or [] # list of DeliveryCommodity objects
|
||||
self.weight = weight
|
||||
self.dimension = {
|
||||
'length': package_type.packaging_length,
|
||||
'width': package_type.width,
|
||||
'height': package_type.height
|
||||
}
|
||||
self.packaging_type = package_type.shipper_package_code or False
|
||||
self.name = name
|
||||
self.total_cost = total_cost
|
||||
self.currency_id = currency
|
||||
|
||||
|
||||
class DeliveryCommodity:
|
||||
""" Commodities information are needed for Commercial invoices with each provider. """
|
||||
def __init__(self, product, amount, monetary_value, country_of_origin):
|
||||
self.product_id = product
|
||||
self.qty = amount
|
||||
self.monetary_value = monetary_value # based on company currency
|
||||
self.country_of_origin = country_of_origin
|
||||
Reference in New Issue
Block a user