diff --git a/addons/delivery/__openerp__.py b/addons/delivery/__openerp__.py
index 590a913b82b..48ab56e0a05 100644
--- a/addons/delivery/__openerp__.py
+++ b/addons/delivery/__openerp__.py
@@ -19,6 +19,7 @@ invoices from picking, the system is able to add and compute the shipping line.
'views/delivery_view.xml',
'views/partner_view.xml',
'views/product_template_view.xml',
+ 'views/product_packaging_view.xml',
'data/delivery_data.xml',
'views/report_shipping.xml',
'views/report_deliveryslip.xml'
diff --git a/addons/delivery/models/__init__.py b/addons/delivery/models/__init__.py
index d593c2c3957..33fb6434d71 100644
--- a/addons/delivery/models/__init__.py
+++ b/addons/delivery/models/__init__.py
@@ -4,6 +4,7 @@
import delivery_carrier
import delivery_price_rule
import product_template
+import product_packaging
import sale_order
import partner
import stock_picking
diff --git a/addons/delivery/models/product_packaging.py b/addons/delivery/models/product_packaging.py
new file mode 100644
index 00000000000..1b5f9b7f262
--- /dev/null
+++ b/addons/delivery/models/product_packaging.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from openerp import models, fields
+
+
+class ProductPackaging(models.Model):
+ _inherit = 'product.packaging'
+
+ height = fields.Integer('Height')
+ width = fields.Integer('Width')
+ length = fields.Integer('Length')
+ max_weight = fields.Float('Max Weight', help='Maximum weight shippable in this packaging')
+ shipper_package_code = fields.Char('Package Code')
+ package_carrier_type = fields.Selection([('none', 'No carrier integration')], string='Carrier', default='none')
+
+ _sql_constraints = [
+ ('positive_height', 'CHECK(height>=0)', 'Height must be positive'),
+ ('positive_width', 'CHECK(width>=0)', 'Width must be positive'),
+ ('positive_length', 'CHECK(length>=0)', 'Length must be positive'),
+ ('positive_max_weight', 'CHECK(max_weight>=0.0)', 'Max Weight must be positive'),
+ ]
diff --git a/addons/delivery/models/stock_picking.py b/addons/delivery/models/stock_picking.py
index 9c1b93440c2..ef1c6503383 100644
--- a/addons/delivery/models/stock_picking.py
+++ b/addons/delivery/models/stock_picking.py
@@ -6,6 +6,7 @@ from openerp.exceptions import UserError
import openerp.addons.decimal_precision as dp
+
class StockQuantPackage(models.Model):
_inherit = "stock.quant.package"
@@ -21,6 +22,27 @@ class StockQuantPackage(models.Model):
self.weight = weight
weight = fields.Float(compute='_compute_weight')
+ shipping_weight = fields.Float(string='Shipping Weight', help="Can be changed during the 'put in pack' to adjust the weight of the shipping.")
+
+
+class StockPackOperation(models.Model):
+ _inherit = 'stock.pack.operation'
+
+ @api.multi
+ def manage_package_type(self):
+ self.ensure_one()
+ return {
+ 'name': _('Package Details'),
+ 'type': 'ir.actions.act_window',
+ 'view_mode': 'form',
+ 'res_model': 'stock.quant.package',
+ 'view_id': self.env.ref('delivery.view_quant_package_form_save').id,
+ 'target': 'new',
+ 'res_id': self.result_package_id.id,
+ 'context': {
+ 'current_package_carrier_type': self.picking_id.carrier_id.delivery_type if self.picking_id.carrier_id.delivery_type not in ['base_on_rule', 'fixed'] else 'none',
+ },
+ }
class StockPicking(models.Model):
@@ -52,6 +74,11 @@ class StockPicking(models.Model):
weight += uom_obj._compute_qty_obj(packop.product_uom_id , packop.product_qty, packop.product_id.uom_id) * packop.product_id.weight
self.weight_bulk = weight
+ @api.one
+ @api.depends('package_ids', 'weight_bulk')
+ def _compute_shipping_weight(self):
+ self.shipping_weight = self.weight_bulk + sum([pack.shipping_weight for pack in self.package_ids])
+
carrier_price = fields.Float(string="Shipping Cost", readonly=True)
delivery_type = fields.Selection(related='carrier_id.delivery_type', readonly=True)
carrier_id = fields.Many2one("delivery.carrier", string="Carrier")
@@ -62,6 +89,7 @@ class StockPicking(models.Model):
weight_uom_id = fields.Many2one('product.uom', string='Unit of Measure', required=True, readonly="1", help="Unit of measurement for Weight", default=_default_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')
@api.depends('product_id', 'move_lines')
def _cal_weight(self):
@@ -81,6 +109,30 @@ class StockPicking(models.Model):
return res
+ @api.multi
+ def put_in_pack(self):
+ self.ensure_one()
+ package_id = super(StockPicking, self).put_in_pack()
+ package = self.env['stock.quant.package'].browse(package_id)
+
+ # By default, sum the weights of all package operations contained in this package
+ pack_operation_ids = self.env['stock.pack.operation'].search([('result_package_id', '=', package_id)])
+ package_weight = sum([x.qty_done * x.product_id.weight for x in pack_operation_ids])
+ package.shipping_weight = package_weight
+
+ return {
+ 'name': _('Package Details'),
+ 'type': 'ir.actions.act_window',
+ 'view_mode': 'form',
+ 'res_model': 'stock.quant.package',
+ 'view_id': self.env.ref('delivery.view_quant_package_form_save').id,
+ 'target': 'new',
+ 'res_id': package_id,
+ 'context': {
+ 'current_package_carrier_type': self.carrier_id.delivery_type if self.carrier_id.delivery_type not in ['base_on_rule', 'fixed'] else 'none',
+ },
+ }
+
@api.multi
def send_to_shipper(self):
self.ensure_one()
@@ -115,6 +167,17 @@ class StockPicking(models.Model):
self.message_post(body=msg)
self.carrier_tracking_ref = False
+ @api.multi
+ def check_packages_are_identical(self):
+ '''Some shippers require identical packages in the same shipment. This utility checks it.'''
+ self.ensure_one()
+ if self.package_ids:
+ packages = [p.packaging_id for p in self.package_ids]
+ if len(set(packages)) != 1:
+ package_names = ', '.join([str(p.name) for p in packages])
+ raise UserError(_('You are shipping different packaging types in the same shipment.\nPackaging Types: %s' % package_names))
+ return True
+
class StockReturnPicking(models.TransientModel):
_inherit = 'stock.return.picking'
diff --git a/addons/delivery/views/delivery_view.xml b/addons/delivery/views/delivery_view.xml
index 6b474b0989f..5ba8dde9665 100644
--- a/addons/delivery/views/delivery_view.xml
+++ b/addons/delivery/views/delivery_view.xml
@@ -166,6 +166,7 @@
+
@@ -177,6 +178,9 @@
+
+
+
@@ -199,10 +203,31 @@
+
+
+
+ stock.quant.package.form.save
+ stock.quant.package
+
+
+
+
+
+
+
stock.move.form.weightstock.move
diff --git a/addons/delivery/views/product_packaging_view.xml b/addons/delivery/views/product_packaging_view.xml
new file mode 100644
index 00000000000..e4c0de6336d
--- /dev/null
+++ b/addons/delivery/views/product_packaging_view.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ product.packaging.form.delivery
+ product.packaging
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ product.packaging.tree.delivery
+ product.packaging
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 71fe83355ee..9848b3cfedd 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -400,7 +400,7 @@
Click to define a new product.
- You must define a product for everything you sell, whether it's a physical product, a consumable or a service you offer to customers.
+ You must define a product for everything you sell, whether it's a physical product, a consumable or a service you offer to customers.
The product form contains information to simplify the sale process: price, notes in the quotation, accounting data, procurement methods, etc.
@@ -754,7 +754,7 @@
-
+
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 819b5a53a8e..0135991c7ad 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -4188,7 +4188,7 @@ class stock_package(osv.osv):
'complete_name': fields.function(_complete_name, type='char', string="Package Name",),
'parent_left': fields.integer('Left Parent', select=1),
'parent_right': fields.integer('Right Parent', select=1),
- 'packaging_id': fields.many2one('product.packaging', 'Packaging', help="This field should be completed only if everything inside the package share the same product, otherwise it doesn't really makes sense.", select=True),
+ 'packaging_id': fields.many2one('product.packaging', 'Package Type', help="This field should be completed only if everything inside the package share the same product, otherwise it doesn't really makes sense.", select=True),
'location_id': fields.function(_get_package_info, type='many2one', relation='stock.location', string='Location', multi="package",
store={
'stock.quant': (_get_packages, ['location_id'], 10),
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index f85172c6a31..e8fe0ec03dc 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -15,6 +15,7 @@
sequence="100" groups="group_stock_manager,base.group_configuration"/>
+
@@ -2165,9 +2166,9 @@
-
+