[MERGE][CLN] delivery: cleanup pass before incoming task(s)

- remove utf-8 encoding header in python scripts
- add missing odoo license and xml headers
- alphabetical order for imports
- rename files according to model names (+ split if needed)
- remove unused variables in tests

closes odoo/odoo#111748

Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
This commit is contained in:
Odoo's Mergebot
2023-02-03 11:45:44 +01:00
committed by GitHub
29 changed files with 313 additions and 305 deletions
-1
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
-1
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+5 -4
View File
@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import delivery_carrier
from . import delivery_grid
from . import delivery_price_rule
from . import delivery_zip_prefix
from . import product_template
from . import res_partner
from . import sale_order
from . import partner
from . import sale_order_line
from . import stock_move
from . import stock_picking
from . import stock_package_type
from . import stock_picking
from . import stock_quant_package
+128 -5
View File
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import psycopg2
import re
from odoo import api, fields, models, registry, SUPERUSER_ID, _
from odoo.tools.float_utils import float_round
from odoo.exceptions import UserError
from odoo import _, api, fields, models, registry, SUPERUSER_ID
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_round
from odoo.tools.safe_eval import safe_eval
from .delivery_request_objects import DeliveryCommodity, DeliveryPackage
@@ -40,7 +40,12 @@ class DeliveryCarrier(models.Model):
active = fields.Boolean(default=True)
sequence = fields.Integer(help="Determine the display order", default=10)
# This field will be overwritten by internal shipping providers by adding their own type (ex: 'fedex')
delivery_type = fields.Selection([('fixed', 'Fixed Price')], string='Provider', default='fixed', required=True)
delivery_type = fields.Selection(
[('base_on_rule', 'Based on Rules'), ('fixed', 'Fixed Price')],
string='Provider',
default='fixed',
required=True,
)
integration_level = fields.Selection([('rate', 'Get Rate'), ('rate_and_ship', 'Get Rate and Create Shipment')], string="Integration Level", default='rate_and_ship', help="Action while validating Delivery Orders")
prod_environment = fields.Boolean("Environment", help="Set to True if your credentials are certified for production.")
debug_logging = fields.Boolean('Debug logging', help="Log requests in order to ease debugging")
@@ -78,6 +83,10 @@ class DeliveryCarrier(models.Model):
default=0
)
price_rule_ids = fields.One2many(
'delivery.price.rule', 'carrier_id', 'Pricing Rules', copy=True
)
_sql_constraints = [
('margin_not_under_100_percent', 'CHECK (margin >= -100)', 'Margin cannot be lower than -100%'),
('shipping_insurance_is_percentage', 'CHECK(shipping_insurance >= 0 AND shipping_insurance <= 100)', "The shipping insurance must be a percentage between 0 and 100."),
@@ -316,6 +325,120 @@ class DeliveryCarrier(models.Model):
def fixed_cancel_shipment(self, pickings):
raise NotImplementedError()
# ----------------------------------- #
# Based on rule delivery type methods #
# ----------------------------------- #
def base_on_rule_rate_shipment(self, order):
carrier = self._match_address(order.partner_shipping_id)
if not carrier:
return {'success': False,
'price': 0.0,
'error_message': _('Error: this delivery method is not available for this address.'),
'warning_message': False}
try:
price_unit = self._get_price_available(order)
except UserError as e:
return {'success': False,
'price': 0.0,
'error_message': e.args[0],
'warning_message': False}
price_unit = self._compute_currency(order, price_unit, 'company_to_pricelist')
return {'success': True,
'price': price_unit,
'error_message': False,
'warning_message': False}
def _get_conversion_currencies(self, order, conversion):
if conversion == 'company_to_pricelist':
from_currency, to_currency = order.company_id.currency_id, order.pricelist_id.currency_id
elif conversion == 'pricelist_to_company':
from_currency, to_currency = order.currency_id, order.company_id.currency_id
return from_currency, to_currency
def _compute_currency(self, order, price, conversion):
from_currency, to_currency = self._get_conversion_currencies(order, conversion)
if from_currency.id == to_currency.id:
return price
return from_currency._convert(price, to_currency, order.company_id, order.date_order or fields.Date.today())
def _get_price_available(self, order):
self.ensure_one()
self = self.sudo()
order = order.sudo()
total = weight = volume = quantity = 0
total_delivery = 0.0
for line in order.order_line:
if line.state == 'cancel':
continue
if line.is_delivery:
total_delivery += line.price_total
if not line.product_id or line.is_delivery:
continue
if line.product_id.type == "service":
continue
qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
weight += (line.product_id.weight or 0.0) * qty
volume += (line.product_id.volume or 0.0) * qty
quantity += qty
total = (order.amount_total or 0.0) - total_delivery
total = self._compute_currency(order, total, 'pricelist_to_company')
# weight is either,
# 1- weight chosen by user in choose.delivery.carrier wizard passed by context
# 2- saved weight to use on sale order
# 3- total order line weight as fallback
weight = self.env.context.get('order_weight') or order.shipping_weight or weight
return self._get_price_from_picking(total, weight, volume, quantity)
def _get_price_dict(self, total, weight, volume, quantity):
'''Hook allowing to retrieve dict to be used in _get_price_from_picking() function.
Hook to be overridden when we need to add some field to product and use it in variable factor from price rules. '''
return {
'price': total,
'volume': volume,
'weight': weight,
'wv': volume * weight,
'quantity': quantity
}
def _get_price_from_picking(self, total, weight, volume, quantity):
price = 0.0
criteria_found = False
price_dict = self._get_price_dict(total, weight, volume, quantity)
if self.free_over and total >= self.amount:
return 0
for line in self.price_rule_ids:
test = safe_eval(line.variable + line.operator + str(line.max_value), price_dict)
if test:
price = line.list_base_price + line.list_price * price_dict[line.variable_factor]
criteria_found = True
break
if not criteria_found:
raise UserError(_("No price rule matching this order; delivery cost cannot be computed."))
return price
def base_on_rule_send_shipping(self, pickings):
res = []
for p in pickings:
carrier = self._match_address(p.partner_id)
if not carrier:
raise ValidationError(_('There is no matching delivery rule.'))
res = res + [{'exact_price': p.carrier_id._get_price_available(p.sale_id) if p.sale_id else 0.0, # TODO cleanme
'tracking_number': False}]
return res
def base_on_rule_get_tracking_link(self, picking):
return False
def base_on_rule_cancel_shipment(self, pickings):
raise NotImplementedError()
# -------------------------------- #
# get default packages/commodities #
# -------------------------------- #
-156
View File
@@ -1,156 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api, _
from odoo.tools.safe_eval import safe_eval
from odoo.exceptions import UserError, ValidationError
class PriceRule(models.Model):
_name = "delivery.price.rule"
_description = "Delivery Price Rules"
_order = 'sequence, list_price, id'
@api.depends('variable', 'operator', 'max_value', 'list_base_price', 'list_price', 'variable_factor')
def _compute_name(self):
for rule in self:
name = 'if %s %s %.02f then' % (rule.variable, rule.operator, rule.max_value)
if rule.list_base_price and not rule.list_price:
name = '%s fixed price %.02f' % (name, rule.list_base_price)
elif rule.list_price and not rule.list_base_price:
name = '%s %.02f times %s' % (name, rule.list_price, rule.variable_factor)
else:
name = '%s fixed price %.02f plus %.02f times %s' % (name, rule.list_base_price, rule.list_price, rule.variable_factor)
rule.name = name
name = fields.Char(compute='_compute_name')
sequence = fields.Integer(required=True, default=10)
carrier_id = fields.Many2one('delivery.carrier', 'Carrier', required=True, ondelete='cascade')
variable = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], required=True, default='weight')
operator = fields.Selection([('==', '='), ('<=', '<='), ('<', '<'), ('>=', '>='), ('>', '>')], required=True, default='<=')
max_value = fields.Float('Maximum Value', required=True)
list_base_price = fields.Float(string='Sale Base Price', digits='Product Price', required=True, default=0.0)
list_price = fields.Float('Sale Price', digits='Product Price', required=True, default=0.0)
variable_factor = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], 'Variable Factor', required=True, default='weight')
class ProviderGrid(models.Model):
_inherit = 'delivery.carrier'
delivery_type = fields.Selection(selection_add=[
('base_on_rule', 'Based on Rules'),
], ondelete={'base_on_rule': lambda recs: recs.write({
'delivery_type': 'fixed', 'fixed_price': 0,
})})
price_rule_ids = fields.One2many('delivery.price.rule', 'carrier_id', 'Pricing Rules', copy=True)
def base_on_rule_rate_shipment(self, order):
carrier = self._match_address(order.partner_shipping_id)
if not carrier:
return {'success': False,
'price': 0.0,
'error_message': _('Error: this delivery method is not available for this address.'),
'warning_message': False}
try:
price_unit = self._get_price_available(order)
except UserError as e:
return {'success': False,
'price': 0.0,
'error_message': e.args[0],
'warning_message': False}
price_unit = self._compute_currency(order, price_unit, 'company_to_pricelist')
return {'success': True,
'price': price_unit,
'error_message': False,
'warning_message': False}
def _get_conversion_currencies(self, order, conversion):
if conversion == 'company_to_pricelist':
from_currency, to_currency = order.company_id.currency_id, order.pricelist_id.currency_id
elif conversion == 'pricelist_to_company':
from_currency, to_currency = order.currency_id, order.company_id.currency_id
return from_currency, to_currency
def _compute_currency(self, order, price, conversion):
from_currency, to_currency = self._get_conversion_currencies(order, conversion)
if from_currency.id == to_currency.id:
return price
return from_currency._convert(price, to_currency, order.company_id, order.date_order or fields.Date.today())
def _get_price_available(self, order):
self.ensure_one()
self = self.sudo()
order = order.sudo()
total = weight = volume = quantity = 0
total_delivery = 0.0
for line in order.order_line:
if line.state == 'cancel':
continue
if line.is_delivery:
total_delivery += line.price_total
if not line.product_id or line.is_delivery:
continue
if line.product_id.type == "service":
continue
qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
weight += (line.product_id.weight or 0.0) * qty
volume += (line.product_id.volume or 0.0) * qty
quantity += qty
total = (order.amount_total or 0.0) - total_delivery
total = self._compute_currency(order, total, 'pricelist_to_company')
# weight is either,
# 1- weight chosen by user in choose.delivery.carrier wizard passed by context
# 2- saved weight to use on sale order
# 3- total order line weight as fallback
weight = self.env.context.get('order_weight') or order.shipping_weight or weight
return self._get_price_from_picking(total, weight, volume, quantity)
def _get_price_dict(self, total, weight, volume, quantity):
'''Hook allowing to retrieve dict to be used in _get_price_from_picking() function.
Hook to be overridden when we need to add some field to product and use it in variable factor from price rules. '''
return {
'price': total,
'volume': volume,
'weight': weight,
'wv': volume * weight,
'quantity': quantity
}
def _get_price_from_picking(self, total, weight, volume, quantity):
price = 0.0
criteria_found = False
price_dict = self._get_price_dict(total, weight, volume, quantity)
if self.free_over and total >= self.amount:
return 0
for line in self.price_rule_ids:
test = safe_eval(line.variable + line.operator + str(line.max_value), price_dict)
if test:
price = line.list_base_price + line.list_price * price_dict[line.variable_factor]
criteria_found = True
break
if not criteria_found:
raise UserError(_("No price rule matching this order; delivery cost cannot be computed."))
return price
def base_on_rule_send_shipping(self, pickings):
res = []
for p in pickings:
carrier = self._match_address(p.partner_id)
if not carrier:
raise ValidationError(_('There is no matching delivery rule.'))
res = res + [{'exact_price': p.carrier_id._get_price_available(p.sale_id) if p.sale_id else 0.0, # TODO cleanme
'tracking_number': False}]
return res
def base_on_rule_get_tracking_link(self, picking):
return False
def base_on_rule_cancel_shipment(self, pickings):
raise NotImplementedError()
@@ -0,0 +1,32 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class PriceRule(models.Model):
_name = "delivery.price.rule"
_description = "Delivery Price Rules"
_order = 'sequence, list_price, id'
@api.depends('variable', 'operator', 'max_value', 'list_base_price', 'list_price', 'variable_factor')
def _compute_name(self):
for rule in self:
name = 'if %s %s %.02f then' % (rule.variable, rule.operator, rule.max_value)
if rule.list_base_price and not rule.list_price:
name = '%s fixed price %.02f' % (name, rule.list_base_price)
elif rule.list_price and not rule.list_base_price:
name = '%s %.02f times %s' % (name, rule.list_price, rule.variable_factor)
else:
name = '%s fixed price %.02f plus %.02f times %s' % (name, rule.list_base_price, rule.list_price, rule.variable_factor)
rule.name = name
name = fields.Char(compute='_compute_name')
sequence = fields.Integer(required=True, default=10)
carrier_id = fields.Many2one('delivery.carrier', 'Carrier', required=True, ondelete='cascade')
variable = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], required=True, default='weight')
operator = fields.Selection([('==', '='), ('<=', '<='), ('<', '<'), ('>=', '>='), ('>', '>')], required=True, default='<=')
max_value = fields.Float('Maximum Value', required=True)
list_base_price = fields.Float(string='Sale Base Price', digits='Product Price', required=True, default=0.0)
list_price = fields.Float('Sale Price', digits='Product Price', required=True, default=0.0)
variable_factor = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], 'Variable Factor', required=True, default='weight')
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
class DeliveryPackage:
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
@@ -18,7 +17,7 @@ class DeliveryZipPrefix(models.Model):
# we cannot easily convert a list of prefix names into upper to compare with partner zips
# later on, so let's ensure they are always upper
vals['name'] = vals['name'].upper()
return super(DeliveryZipPrefix, self).create(vals_list)
return super().create(vals_list)
def write(self, vals):
vals['name'] = vals['name'].upper()
+1 -2
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields
from odoo import fields, models
class ProductTemplate(models.Model):
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
+1 -45
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError
@@ -163,46 +162,3 @@ class SaleOrder(models.Model):
for order_line in self.order_line.filtered(lambda l: l.product_id.type in ['product', 'consu'] and not l.is_delivery and not l.display_type):
weight += order_line.product_qty * order_line.product_id.weight
return weight
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
is_delivery = fields.Boolean(string="Is a Delivery", default=False)
product_qty = fields.Float(compute='_compute_product_qty', string='Product Qty', digits='Product Unit of Measure')
recompute_delivery_price = fields.Boolean(related='order_id.recompute_delivery_price')
def _is_not_sellable_line(self):
return self.is_delivery or super(SaleOrderLine, self)._is_not_sellable_line()
@api.depends('product_id', 'product_uom', 'product_uom_qty')
def _compute_product_qty(self):
for line in self:
if not line.product_id or not line.product_uom or not line.product_uom_qty:
line.product_qty = 0.0
continue
line.product_qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
def unlink(self):
for line in self:
if line.is_delivery:
line.order_id.carrier_id = False
return super(SaleOrderLine, self).unlink()
def _is_delivery(self):
self.ensure_one()
return self.is_delivery
# override to allow deletion of delivery line in a confirmed order
def _check_line_unlink(self):
"""
Extend the allowed deletion policy of SO lines.
Lines that are delivery lines can be deleted from a confirmed order.
:rtype: recordset sale.order.line
:returns: set of lines that cannot be deleted
"""
undeletable_lines = super()._check_line_unlink()
return undeletable_lines.filtered(lambda line: not line.is_delivery)
+50
View File
@@ -0,0 +1,50 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
is_delivery = fields.Boolean(string="Is a Delivery", default=False)
product_qty = fields.Float(
string='Product Qty', compute='_compute_product_qty', digits='Product Unit of Measure'
)
recompute_delivery_price = fields.Boolean(related='order_id.recompute_delivery_price')
def _is_not_sellable_line(self):
return self.is_delivery or super()._is_not_sellable_line()
@api.depends('product_id', 'product_uom', 'product_uom_qty')
def _compute_product_qty(self):
for line in self:
if not line.product_id or not line.product_uom or not line.product_uom_qty:
line.product_qty = 0.0
continue
line.product_qty = line.product_uom._compute_quantity(
line.product_uom_qty, line.product_id.uom_id
)
def unlink(self):
for line in self:
if line.is_delivery:
line.order_id.carrier_id = False
return super().unlink()
def _is_delivery(self):
self.ensure_one()
return self.is_delivery
# override to allow deletion of delivery line in a confirmed order
def _check_line_unlink(self):
"""
Extend the allowed deletion policy of SO lines.
Lines that are delivery lines can be deleted from a confirmed order.
:rtype: recordset sale.order.line
:returns: set of lines that cannot be deleted
"""
undeletable_lines = super()._check_line_unlink()
return undeletable_lines.filtered(lambda line: not line.is_delivery)
-1
View File
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
+1 -2
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api
from odoo import api, fields, models
class PackageType(models.Model):
+2 -68
View File
@@ -1,66 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from collections import defaultdict
import json
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools.sql import column_exists, create_column
class StockQuantPackage(models.Model):
_inherit = "stock.quant.package"
@api.depends('quant_ids', 'package_type_id')
def _compute_weight(self):
if self.env.context.get('picking_id'):
package_weights = defaultdict(float)
# Ordering by qty_done prevents the default ordering by groupby fields that can inject multiple Left Joins in the resulting query.
res_groups = self.env['stock.move.line'].read_group(
[('result_package_id', 'in', self.ids), ('product_id', '!=', False), ('picking_id', '=', self.env.context['picking_id'])],
['id:count'],
['result_package_id', 'product_id', 'product_uom_id', 'qty_done'],
lazy=False, orderby='qty_done asc'
)
for res_group in res_groups:
product_id = self.env['product.product'].browse(res_group['product_id'][0])
product_uom_id = self.env['uom.uom'].browse(res_group['product_uom_id'][0])
package_weights[res_group['result_package_id'][0]] += (
res_group['__count']
* product_uom_id._compute_quantity(res_group['qty_done'], product_id.uom_id)
* product_id.weight
)
for package in self:
weight = package.package_type_id.base_weight or 0.0
if self.env.context.get('picking_id'):
package.weight = weight + package_weights[package.id]
else:
for quant in package.quant_ids:
weight += quant.quantity * quant.product_id.weight
package.weight = weight
def _get_default_weight_uom(self):
return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter()
def _compute_weight_uom_name(self):
for package in self:
package.weight_uom_name = self.env['product.template']._get_weight_uom_name_from_ir_config_parameter()
def _compute_weight_is_kg(self):
self.weight_is_kg = False
uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter()
if uom_id == self.env.ref('uom.product_uom_kgm'):
self.weight_is_kg = True
self.weight_uom_rounding = uom_id.rounding
weight = fields.Float(compute='_compute_weight', digits='Stock Weight', help="Total weight of all the products contained in the package.")
weight_uom_name = fields.Char(string='Weight unit of measure label', compute='_compute_weight_uom_name', readonly=True, default=_get_default_weight_uom)
weight_is_kg = fields.Boolean("Technical field indicating whether weight uom is kg or not (i.e. lb)", compute="_compute_weight_is_kg")
weight_uom_rounding = fields.Float("Technical field indicating weight's number of decimal places", compute="_compute_weight_is_kg")
shipping_weight = fields.Float(string='Shipping Weight', help="Total weight of the package.")
class StockPicking(models.Model):
_inherit = 'stock.picking'
@@ -319,16 +266,3 @@ class StockPicking(models.Model):
def _should_generate_commercial_invoice(self):
self.ensure_one()
return self.picking_type_id.warehouse_id.partner_id.country_id != self.partner_id.country_id
class StockReturnPicking(models.TransientModel):
_inherit = 'stock.return.picking'
def _create_returns(self):
# Prevent copy of the carrier and carrier price when generating return picking
# (we have no integration of returns for now)
new_picking, pick_type_id = super(StockReturnPicking, self)._create_returns()
picking = self.env['stock.picking'].browse(new_picking)
picking.write({'carrier_id': False,
'carrier_price': 0.0})
return new_picking, pick_type_id
@@ -0,0 +1,57 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from odoo import api, fields, models
class StockQuantPackage(models.Model):
_inherit = "stock.quant.package"
@api.depends('quant_ids', 'package_type_id')
def _compute_weight(self):
if self.env.context.get('picking_id'):
package_weights = defaultdict(float)
# Ordering by qty_done prevents the default ordering by groupby fields that can inject multiple Left Joins in the resulting query.
res_groups = self.env['stock.move.line'].read_group(
[('result_package_id', 'in', self.ids), ('product_id', '!=', False), ('picking_id', '=', self.env.context['picking_id'])],
['id:count'],
['result_package_id', 'product_id', 'product_uom_id', 'qty_done'],
lazy=False, orderby='qty_done asc'
)
for res_group in res_groups:
product_id = self.env['product.product'].browse(res_group['product_id'][0])
product_uom_id = self.env['uom.uom'].browse(res_group['product_uom_id'][0])
package_weights[res_group['result_package_id'][0]] += (
res_group['__count']
* product_uom_id._compute_quantity(res_group['qty_done'], product_id.uom_id)
* product_id.weight
)
for package in self:
weight = package.package_type_id.base_weight or 0.0
if self.env.context.get('picking_id'):
package.weight = weight + package_weights[package.id]
else:
for quant in package.quant_ids:
weight += quant.quantity * quant.product_id.weight
package.weight = weight
def _get_default_weight_uom(self):
return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter()
def _compute_weight_uom_name(self):
for package in self:
package.weight_uom_name = self.env['product.template']._get_weight_uom_name_from_ir_config_parameter()
def _compute_weight_is_kg(self):
self.weight_is_kg = False
uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter()
if uom_id == self.env.ref('uom.product_uom_kgm'):
self.weight_is_kg = True
self.weight_uom_rounding = uom_id.rounding
weight = fields.Float(compute='_compute_weight', digits='Stock Weight', help="Total weight of all the products contained in the package.")
weight_uom_name = fields.Char(string='Weight unit of measure label', compute='_compute_weight_uom_name', readonly=True, default=_get_default_weight_uom)
weight_is_kg = fields.Boolean("Technical field indicating whether weight uom is kg or not (i.e. lb)", compute="_compute_weight_is_kg")
weight_uom_rounding = fields.Float("Technical field indicating weight's number of decimal places", compute="_compute_weight_is_kg")
shipping_weight = fields.Float(string='Shipping Weight', help="Total weight of the package.")
+4 -4
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing detailsself.
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_delivery_cost, test_delivery_stock_move
from . import test_packing_delivery
from . import test_carrier_propagation
from . import test_delivery_cost
from . import test_delivery_stock_move
from . import test_packing_delivery
@@ -1,3 +1,5 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import Form
from odoo.tests.common import TransactionCase
+1 -1
View File
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.tests import common, Form
from odoo.tools import float_compare
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests import tagged, Form
from odoo.tests import Form, tagged
@tagged('post_install', '-at_install')
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.stock.tests.test_packing import TestPackingCommon
@@ -48,7 +47,7 @@ class TestPacking(TestPackingCommon):
'location_dest_id': self.customer_location.id,
'carrier_id': self.test_carrier.id
})
move_line_paw = self.env['stock.move.line'].create({
self.env['stock.move.line'].create({
'product_id': self.product_aw.id,
'product_uom_id': self.uom_kg.id,
'picking_id': picking_ship.id,
@@ -56,7 +55,7 @@ class TestPacking(TestPackingCommon):
'location_id': self.stock_location.id,
'location_dest_id': self.customer_location.id
})
move_line_pbw = self.env['stock.move.line'].create({
self.env['stock.move.line'].create({
'product_id': self.product_bw.id,
'product_uom_id': self.uom_kg.id,
'picking_id': picking_ship.id,
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="sale_order_portal_content_inherit_sale_stock_inherit_website_sale_delivery"
name="Shipping tracking on orders followup"
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_delivery_document2" inherit_id="stock.report_delivery_document">
<xpath expr="//div[@name='div_sched_date']" position="after">
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="label_package_template_view_delivery" inherit_id="stock.label_package_template_view">
<xpath expr="//t[@name='datamatrix_pack_date']" position="after">
@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_shipping2" inherit_id="stock.report_picking">
<xpath expr="//div[@name='div_sched_date']" position="after">
+2 -2
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import choose_delivery_package
from . import choose_delivery_carrier
from . import choose_delivery_package
from . import stock_return_picking
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, api, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError
@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.tools.float_utils import float_compare
from odoo.tools import float_compare
class ChooseDeliveryPackage(models.TransientModel):
@@ -0,0 +1,16 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class StockReturnPicking(models.TransientModel):
_inherit = 'stock.return.picking'
def _create_returns(self):
# Prevent copy of the carrier and carrier price when generating return picking
# (we have no integration of returns for now)
new_picking, pick_type_id = super()._create_returns()
picking = self.env['stock.picking'].browse(new_picking)
picking.write({'carrier_id': False,
'carrier_price': 0.0})
return new_picking, pick_type_id