diff --git a/addons/delivery/models/stock_move.py b/addons/delivery/models/stock_move.py
index 49ace8ec7ef..3b51fe7763e 100644
--- a/addons/delivery/models/stock_move.py
+++ b/addons/delivery/models/stock_move.py
@@ -41,3 +41,17 @@ class StockMoveLine(models.Model):
unit_price = move_line.product_id.list_price
qty = move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id)
move_line.sale_price = unit_price * qty
+
+ def _get_aggregated_product_quantities(self, **kwargs):
+ """Returns dictionary of products and corresponding values of interest + hs_code
+
+ Unfortunately because we are working with aggregated data, we have to loop through the
+ aggregation to add more values to each datum. This extension adds on the hs_code value.
+
+ returns: dictionary {same_key_as_super: {same_values_as_super, hs_code}, ...}
+ """
+ aggregated_move_lines = super()._get_aggregated_product_quantities(**kwargs)
+ for aggregated_move_line in aggregated_move_lines:
+ hs_code = aggregated_move_lines[aggregated_move_line]['product'].product_tmpl_id.hs_code
+ aggregated_move_lines[aggregated_move_line]['hs_code'] = hs_code
+ return aggregated_move_lines
diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py
index d4c90d77d55..20ad15160f2 100644
--- a/addons/delivery/models/stock_picking.py
+++ b/addons/delivery/models/stock_picking.py
@@ -66,7 +66,8 @@ class StockPicking(models.Model):
@api.depends('move_line_ids.result_package_id', 'move_line_ids.result_package_id.shipping_weight', 'weight_bulk')
def _compute_shipping_weight(self):
for picking in self:
- picking.shipping_weight = picking.weight_bulk + sum([pack.shipping_weight for pack in picking.package_ids])
+ # if shipping weight is not assigned => default to calculated product weight
+ picking.shipping_weight = picking.weight_bulk + sum([pack.shipping_weight or pack.weight for pack in picking.package_ids])
def _get_default_weight_uom(self):
return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter()
@@ -83,8 +84,9 @@ class StockPicking(models.Model):
carrier_tracking_url = fields.Char(string='Tracking URL', compute='_compute_carrier_tracking_url')
weight_uom_name = fields.Char(string='Weight unit of measure label', compute='_compute_weight_uom_name', readonly=True, default=_get_default_weight_uom)
package_ids = fields.Many2many('stock.quant.package', compute='_compute_packages', string='Packages')
- weight_bulk = fields.Float('Bulk Weight', compute='_compute_bulk_weight')
- shipping_weight = fields.Float("Weight for Shipping", compute='_compute_shipping_weight', help="Total weight of the packages and products which are not in a package. That's the weight used to compute the cost of the shipping.")
+ weight_bulk = fields.Float('Bulk Weight', compute='_compute_bulk_weight', help="Total weight of products which are not in a package.")
+ shipping_weight = fields.Float("Weight for Shipping", compute='_compute_shipping_weight',
+ help="Total weight of packages and products not in a package. Packages with no shipping weight specified will default to their products' total weight. This is the weight used to compute the cost of the shipping.")
is_return_picking = fields.Boolean(compute='_compute_return_picking')
return_label_ids = fields.One2many('ir.attachment', compute='_compute_return_label')
diff --git a/addons/delivery/views/report_deliveryslip.xml b/addons/delivery/views/report_deliveryslip.xml
index 43031e5803e..4bf0057dd3b 100644
--- a/addons/delivery/views/report_deliveryslip.xml
+++ b/addons/delivery/views/report_deliveryslip.xml
@@ -6,7 +6,7 @@
- Weight:
+ Total Weight:
@@ -22,16 +22,51 @@
HS Code
-
-
-
-
HS Code
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Weight:
+
+
+
+
+
+ - Weight (estimated):
+
+
+
+
+
+
+
+
+
+
+ - Weight:
+
+
+
+
diff --git a/addons/mrp/__manifest__.py b/addons/mrp/__manifest__.py
index ce6d450810d..a5fdb6e3ebc 100644
--- a/addons/mrp/__manifest__.py
+++ b/addons/mrp/__manifest__.py
@@ -36,6 +36,7 @@
'views/res_config_settings_views.xml',
'views/mrp_templates.xml',
'views/stock_scrap_views.xml',
+ 'report/report_deliveryslip.xml',
'report/mrp_report_views_main.xml',
'report/mrp_report_bom_structure.xml',
'report/mrp_production_templates.xml',
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index 3ad3ba69067..f006fdb22d9 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -60,6 +60,24 @@ class StockMoveLine(models.Model):
move_line._log_message(production, move_line, 'mrp.track_production_move_template', vals)
return super(StockMoveLine, self).write(vals)
+ def _get_aggregated_product_quantities(self, **kwargs):
+ """Returns dictionary of products and corresponding values of interest grouped by optional kit_name
+
+ Removes descriptions where description == kit_name. kit_name is expected to be passed as a
+ kwargs value because this is not directly stored in move_line_ids. Unfortunately because we
+ are working with aggregated data, we have to loop through the aggregation to do this removal.
+
+ arguments: kit_name (optional): string value of a kit name passed as a kwarg
+ returns: dictionary {same_key_as_super: {same_values_as_super, ...}
+ """
+ aggregated_move_lines = super()._get_aggregated_product_quantities(**kwargs)
+ kit_name = kwargs.get('kit_name')
+ if kit_name:
+ for aggregated_move_line in aggregated_move_lines:
+ if aggregated_move_lines[aggregated_move_line]['description'] == kit_name:
+ aggregated_move_lines[aggregated_move_line]['description'] = ""
+ return aggregated_move_lines
+
class StockMove(models.Model):
_inherit = 'stock.move'
diff --git a/addons/mrp/report/report_deliveryslip.xml b/addons/mrp/report/report_deliveryslip.xml
new file mode 100644
index 00000000000..88370ca6e78
--- /dev/null
+++ b/addons/mrp/report/report_deliveryslip.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Products not associated with a kit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/product_expiry/__manifest__.py b/addons/product_expiry/__manifest__.py
index 2021381a583..0a620081fa8 100644
--- a/addons/product_expiry/__manifest__.py
+++ b/addons/product_expiry/__manifest__.py
@@ -18,11 +18,14 @@ Following dates can be tracked:
Also implements the removal strategy First Expiry First Out (FEFO) widely used, for example, in food industries.
""",
'data': ['security/ir.model.access.csv',
+ 'security/stock_security.xml',
'views/production_lot_views.xml',
'views/product_template_views.xml',
+ 'views/res_config_settings_views.xml',
'views/stock_move_views.xml',
'views/stock_quant_views.xml',
'wizard/confirm_expiry_view.xml',
+ 'report/report_deliveryslip.xml',
'report/report_lot_barcode.xml',
'data/product_expiry_data.xml'],
}
diff --git a/addons/product_expiry/models/__init__.py b/addons/product_expiry/models/__init__.py
index ce07f86f046..55fcdd6ea27 100644
--- a/addons/product_expiry/models/__init__.py
+++ b/addons/product_expiry/models/__init__.py
@@ -3,6 +3,7 @@
from . import production_lot
from . import product_product
+from . import res_config_settings
from . import stock_move_line
from . import stock_move
from . import stock_picking
diff --git a/addons/product_expiry/models/res_config_settings.py b/addons/product_expiry/models/res_config_settings.py
new file mode 100644
index 00000000000..bb565c56346
--- /dev/null
+++ b/addons/product_expiry/models/res_config_settings.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import api, fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ group_expiry_date_on_delivery_slip = fields.Boolean("Display Expiration Dates on Delivery Slips",
+ implied_group='product_expiry.group_expiry_date_on_delivery_slip')
+
+ @api.onchange('group_lot_on_delivery_slip')
+ def _onchange_group_lot_on_delivery_slip(self):
+ if not self.group_lot_on_delivery_slip:
+ self.group_expiry_date_on_delivery_slip = False
+
+ @api.onchange('module_product_expiry')
+ def _onchange_module_product_expiry(self):
+ if not self.module_product_expiry:
+ self.group_expiry_date_on_delivery_slip = False
diff --git a/addons/product_expiry/report/report_deliveryslip.xml b/addons/product_expiry/report/report_deliveryslip.xml
new file mode 100644
index 00000000000..1d390ee181c
--- /dev/null
+++ b/addons/product_expiry/report/report_deliveryslip.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py
index 079aad39305..6204341b12e 100644
--- a/addons/stock/models/stock_move_line.py
+++ b/addons/stock/models/stock_move_line.py
@@ -605,3 +605,32 @@ class StockMoveLine(models.Model):
def _should_bypass_reservation(self, location):
self.ensure_one()
return location.should_bypass_reservation() or self.product_id.type != 'product'
+
+ def _get_aggregated_product_quantities(self, **kwargs):
+ """ Returns a dictionary of products (key = id+name+description+uom) and corresponding values of interest.
+
+ Allows aggregation of data across separate move lines for the same product. This is expected to be useful
+ in things such as delivery reports. Dict key is made as a combination of values we expect to want to group
+ the products by (i.e. so data is not lost). This function purposely ignores lots/SNs because these are
+ expected to already be properly grouped by line.
+
+ returns: dictionary {product_id+name+description+uom: {product, name, description, qty_done, product_uom}, ...}
+ """
+ aggregated_move_lines = {}
+ for move_line in self:
+ name = move_line.product_id.display_name
+ description = move_line.move_id.description_picking
+ if description == name or description == move_line.product_id.name:
+ description = False
+ uom = move_line.product_uom_id
+ line_key = str(move_line.product_id.id) + "_" + name + (description or "") + "uom " + str(uom.id)
+
+ if line_key not in aggregated_move_lines:
+ aggregated_move_lines[line_key] = {'name': name,
+ 'description': description,
+ 'qty_done': move_line.qty_done,
+ 'product_uom': uom.name,
+ 'product': move_line.product_id}
+ else:
+ aggregated_move_lines[line_key]['qty_done'] += move_line.qty_done
+ return aggregated_move_lines
diff --git a/addons/stock/report/report_deliveryslip.xml b/addons/stock/report/report_deliveryslip.xml
index f6f56b10e86..24bd5e2366b 100644
--- a/addons/stock/report/report_deliveryslip.xml
+++ b/addons/stock/report/report_deliveryslip.xml
@@ -1,6 +1,5 @@
-
@@ -56,12 +55,13 @@