[ADD] delivery: package editable after put in pack

* It is sometime useful to be able to set the package type and the package weight during the delivery
* These fields can be edited during the 'put in pack' operation or after, with a button in the view
* As the weight is computed, a new field 'shipping_weight' has been added
* These fields (package type and weight) will be used in the delivery carrier for the shipping
* Packaging types are now handled in a centralized way for all shippers
This commit is contained in:
Martin Geubelle
2016-02-01 16:04:02 +01:00
committed by Richard Mathot
parent e32f6bc950
commit 2ff3749064
9 changed files with 154 additions and 4 deletions
+1
View File
@@ -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'
+1
View File
@@ -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
@@ -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'),
]
+63
View File
@@ -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'
+25
View File
@@ -166,6 +166,7 @@
<field name="weight" class="oe_inline"/>
<field name="weight_uom_id" nolabel="1" class="oe_inline"/>
</div>
<field name="shipping_weight"/>
<field name="number_of_packages"/>
</group>
</group>
@@ -177,6 +178,9 @@
<xpath expr="/form/header/button[last()]" position="after">
<button name="send_to_shipper" string="Send to Shipper" type="object" attrs="{'invisible':['|','|','|',('carrier_tracking_ref','!=',False),('delivery_type','in', ['fixed', 'base_on_rule']),('delivery_type','=',False),('state','not in',('done'))]}"/>
</xpath>
<field name="result_package_id" position="before">
<button name="manage_package_type" string="Manage Package Type" type="object" icon="fa-dropbox" groups="stock.group_tracking_lot" attrs="{'invisible': [('result_package_id','=', False)]}"/>
</field>
</data>
</field>
</record>
@@ -199,10 +203,31 @@
<field name="arch" type="xml">
<field name="company_id" position="before">
<field name="weight"/>
<field name="shipping_weight"/>
</field>
</field>
</record>
<record id="view_quant_package_form_save" model="ir.ui.view">
<field name="name">stock.quant.package.form.save</field>
<field name="model">stock.quant.package</field>
<field eval="99" name="priority"/>
<field name="arch" type="xml">
<form string="Package">
<group>
<field name="packaging_id" domain="[('package_carrier_type', '=', context.get('current_package_carrier_type'))]"/>
<field name="shipping_weight"/>
</group>
<footer>
<button name="write" type="object" string="Save" class="btn btn-sm btn-primary"/>
<button string="Discard" special="cancel" class="btn btn-sm btn-default"/>
</footer>
</form>
</field>
</record>
<record id="view_move_withweight_form" model="ir.ui.view">
<field name="name">stock.move.form.weight</field>
<field name="model">stock.move</field>
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="delivery.product_packaging_delivery_form">
<field name="name">product.packaging.form.delivery</field>
<field name="model">product.packaging</field>
<field name="inherit_id" ref="product.product_packaging_form_view"/>
<field name="arch" type="xml">
<group name="qty" position="after">
<group name="delivery">
<field name="package_carrier_type"/>
<field name="height"/>
<field name="width"/>
<field name="length"/>
<field name="max_weight"/>
<field name="shipper_package_code" groups="base.group_no_one"/>
</group>
</group>
</field>
</record>
<record model="ir.ui.view" id="delivery.product_packaging_delivery_tree">
<field name="name">product.packaging.tree.delivery</field>
<field name="model">product.packaging</field>
<field name="inherit_id" ref="product.product_packaging_tree_view"/>
<field name="arch" type="xml">
<field name="qty" position="after">
<field name="height"/>
<field name="width"/>
<field name="length"/>
<field name="max_weight"/>
<field name="package_carrier_type"/>
<field name="shipper_package_code" groups="base.group_no_one"/>
</field>
</field>
</record>
</odoo>
+2 -2
View File
@@ -400,7 +400,7 @@
<p class="oe_view_nocontent_create">
Click to define a new product.
</p><p>
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.
</p><p>
The product form contains information to simplify the sale process: price, notes in the quotation, accounting data, procurement methods, etc.
</p>
@@ -754,7 +754,7 @@
<field name="name"/>
</h1>
<group>
<group>
<group name="qty">
<field name="qty"/>
</group>
</group>
+1 -1
View File
@@ -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),
+2 -1
View File
@@ -15,6 +15,7 @@
sequence="100" groups="group_stock_manager,base.group_configuration"/>
<menuitem id="menu_warehouse_config" name="Warehouse Management" parent="menu_stock_config_settings" groups="base.group_configuration" sequence="1"/>
<menuitem id="menu_routes_config" name="Routes" parent="menu_stock_config_settings" sequence="2" groups="stock.group_adv_location"/>
<menuitem id="menu_packages_config" name="Packages" parent="menu_stock_config_settings" sequence="3" groups="product.group_stock_packaging"/>
<menuitem
id="menu_product_in_config_stock" name="Products"
parent="stock.menu_stock_config_settings" sequence="4"/>
@@ -2165,9 +2166,9 @@
</field>
</record>
<menuitem id="menu_package" name="Packages" parent="menu_stock_inventory_control" action="action_package_view" groups="stock.group_tracking_lot" sequence="102"/>
<menuitem id="menu_packagings" name="Packagings" parent="stock.menu_warehouse_report" action="product.action_packaging_view" groups="product.group_stock_packaging" sequence="3"/>
<menuitem id="menu_packagings" name="Package Types" parent="stock.menu_packages_config" action="product.action_packaging_view" groups="product.group_stock_packaging"/>
<!--Routes-->
<record id="stock_location_route_tree" model="ir.ui.view">