mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[IMP] delivery_hibou: per-package insurance and signature req.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
'name': 'Delivery Hibou',
|
'name': 'Delivery Hibou',
|
||||||
'summary': 'Adds underlying pinnings for things like "RMA Return Labels"',
|
'summary': 'Adds underlying pinnings for things like "RMA Return Labels"',
|
||||||
'version': '15.0.1.0.0',
|
'version': '15.0.1.1.0',
|
||||||
'author': "Hibou Corp.",
|
'author': "Hibou Corp.",
|
||||||
'category': 'Stock',
|
'category': 'Stock',
|
||||||
'license': 'LGPL-3',
|
'license': 'LGPL-3',
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from odoo import fields, models, _
|
from odoo import api, fields, models, _
|
||||||
|
from odoo.tools.float_utils import float_compare
|
||||||
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
|
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
@@ -9,6 +10,9 @@ class DeliveryCarrier(models.Model):
|
|||||||
automatic_insurance_value = fields.Float(string='Automatic Insurance Value',
|
automatic_insurance_value = fields.Float(string='Automatic Insurance Value',
|
||||||
help='Will be used during shipping to determine if the '
|
help='Will be used during shipping to determine if the '
|
||||||
'picking\'s value warrants insurance being added.')
|
'picking\'s value warrants insurance being added.')
|
||||||
|
automatic_sig_req_value = fields.Float(string='Automatic Signature Required Value',
|
||||||
|
help='Will be used during shipping to determine if the '
|
||||||
|
'picking\'s value warrants signature required being added.')
|
||||||
procurement_priority = fields.Selection(PROCUREMENT_PRIORITIES,
|
procurement_priority = fields.Selection(PROCUREMENT_PRIORITIES,
|
||||||
string='Procurement Priority',
|
string='Procurement Priority',
|
||||||
help='Priority for this carrier. Will affect pickings '
|
help='Priority for this carrier. Will affect pickings '
|
||||||
@@ -16,21 +20,42 @@ class DeliveryCarrier(models.Model):
|
|||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
|
|
||||||
def get_insurance_value(self, order=None, picking=None):
|
def get_insurance_value(self, order=None, picking=None, package=None):
|
||||||
value = 0.0
|
value = 0.0
|
||||||
if order:
|
if order:
|
||||||
if order.order_line:
|
if order.order_line:
|
||||||
value = sum(order.order_line.filtered(lambda l: l.type != 'service').mapped('price_subtotal'))
|
value = sum(order.order_line.filtered(lambda l: l.product_id.type != 'service').mapped('price_subtotal'))
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
if picking:
|
if picking:
|
||||||
value = picking.declared_value()
|
value = picking.declared_value(package=package)
|
||||||
if picking.require_insurance == 'no':
|
if package and not package.require_insurance:
|
||||||
value = 0.0
|
|
||||||
elif picking.require_insurance == 'auto' and self.automatic_insurance_value and self.automatic_insurance_value > value:
|
|
||||||
value = 0.0
|
value = 0.0
|
||||||
|
else:
|
||||||
|
if picking.require_insurance == 'no':
|
||||||
|
value = 0.0
|
||||||
|
elif picking.require_insurance == 'auto' and self.automatic_insurance_value and self.automatic_insurance_value > value:
|
||||||
|
value = 0.0
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def get_signature_required(self, order=None, picking=None, package=None):
|
||||||
|
value = 0.0
|
||||||
|
if order:
|
||||||
|
if order.order_line:
|
||||||
|
value = sum(order.order_line.filtered(lambda l: l.product_id.type != 'service').mapped('price_subtotal'))
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
if picking:
|
||||||
|
value = picking.declared_value(package=package)
|
||||||
|
if package:
|
||||||
|
return package.require_signature
|
||||||
|
else:
|
||||||
|
if picking.require_signature == 'no':
|
||||||
|
return False
|
||||||
|
elif picking.require_signature == 'yes':
|
||||||
|
return True
|
||||||
|
return self.automatic_sig_req_value and value >= self.automatic_sig_req_value
|
||||||
|
|
||||||
def get_third_party_account(self, order=None, picking=None):
|
def get_third_party_account(self, order=None, picking=None):
|
||||||
if order and order.shipping_account_id:
|
if order and order.shipping_account_id:
|
||||||
return order.shipping_account_id
|
return order.shipping_account_id
|
||||||
@@ -202,9 +227,9 @@ class DeliveryCarrier(models.Model):
|
|||||||
|
|
||||||
res = []
|
res = []
|
||||||
for carrier in self:
|
for carrier in self:
|
||||||
carrier_packages = packages.filtered(lambda p: not p.carrier_tracking_ref and
|
carrier_packages = packages and packages.filtered(lambda p: not p.carrier_tracking_ref and
|
||||||
(not p.carrier_id or p.carrier_id == carrier) and
|
(not p.carrier_id or p.carrier_id == carrier) and
|
||||||
p.package_type_id.package_carrier_type in (False, '', 'none', carrier.delivery_type))
|
p.packaging_type_id.package_carrier_type in (False, '', 'none', carrier.delivery_type))
|
||||||
if packages and not carrier_packages:
|
if packages and not carrier_packages:
|
||||||
continue
|
continue
|
||||||
if hasattr(carrier, '%s_rate_shipment_multi' % self.delivery_type):
|
if hasattr(carrier, '%s_rate_shipment_multi' % self.delivery_type):
|
||||||
@@ -243,3 +268,70 @@ class DeliveryCarrier(models.Model):
|
|||||||
})
|
})
|
||||||
|
|
||||||
return getattr(self, '%s_cancel_shipment' % self.delivery_type)(pickings)
|
return getattr(self, '%s_cancel_shipment' % self.delivery_type)(pickings)
|
||||||
|
|
||||||
|
|
||||||
|
class ChooseDeliveryPackage(models.TransientModel):
|
||||||
|
_inherit = 'choose.delivery.package'
|
||||||
|
|
||||||
|
package_declared_value = fields.Float(string='Declared Value')
|
||||||
|
package_require_insurance = fields.Boolean(string='Require Insurance')
|
||||||
|
package_require_signature = fields.Boolean(string='Require Signature')
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def default_get(self, fields_list):
|
||||||
|
defaults = super().default_get(fields_list)
|
||||||
|
if 'package_declared_value' in fields_list:
|
||||||
|
picking = self.env['stock.picking'].browse(defaults.get('picking_id'))
|
||||||
|
move_line_ids = picking.move_line_ids.filtered(lambda m:
|
||||||
|
float_compare(m.qty_done, 0.0, precision_rounding=m.product_uom_id.rounding) > 0
|
||||||
|
and not m.result_package_id
|
||||||
|
)
|
||||||
|
total_value = 0.0
|
||||||
|
for ml in move_line_ids:
|
||||||
|
qty = ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
|
||||||
|
total_value += qty * ml.product_id.standard_price
|
||||||
|
defaults['package_declared_value'] = total_value
|
||||||
|
return defaults
|
||||||
|
|
||||||
|
@api.onchange('package_declared_value')
|
||||||
|
def _onchange_package_declared_value(self):
|
||||||
|
picking = self.picking_id
|
||||||
|
value = self.package_declared_value
|
||||||
|
if picking.require_insurance == 'auto':
|
||||||
|
self.package_require_insurance = value and picking.carrier_id.automatic_insurance_value and value >= picking.carrier_id.automatic_insurance_value
|
||||||
|
else:
|
||||||
|
self.package_require_insurance = picking.require_insurance == 'yes'
|
||||||
|
if picking.require_signature == 'auto':
|
||||||
|
self.package_require_signature = value and picking.carrier_id.automatic_sig_req_value and value >= picking.carrier_id.automatic_sig_req_value
|
||||||
|
else:
|
||||||
|
self.package_require_signature = picking.require_signature == 'yes'
|
||||||
|
|
||||||
|
def action_put_in_pack(self):
|
||||||
|
# Copied because `delivery_package` is not retained by reference or returned...
|
||||||
|
picking_move_lines = self.picking_id.move_line_ids
|
||||||
|
if not self.picking_id.picking_type_id.show_reserved and not self.env.context.get('barcode_view'):
|
||||||
|
picking_move_lines = self.picking_id.move_line_nosuggest_ids
|
||||||
|
|
||||||
|
move_line_ids = picking_move_lines.filtered(lambda ml:
|
||||||
|
float_compare(ml.qty_done, 0.0,
|
||||||
|
precision_rounding=ml.product_uom_id.rounding) > 0
|
||||||
|
and not ml.result_package_id
|
||||||
|
)
|
||||||
|
if not move_line_ids:
|
||||||
|
move_line_ids = picking_move_lines.filtered(lambda ml: float_compare(ml.product_uom_qty, 0.0,
|
||||||
|
precision_rounding=ml.product_uom_id.rounding) > 0 and float_compare(
|
||||||
|
ml.qty_done, 0.0,
|
||||||
|
precision_rounding=ml.product_uom_id.rounding) == 0)
|
||||||
|
|
||||||
|
delivery_package = self.picking_id._put_in_pack(move_line_ids)
|
||||||
|
# write shipping weight and package type on 'stock_quant_package' if needed
|
||||||
|
if self.delivery_package_type_id:
|
||||||
|
delivery_package.package_type_id = self.delivery_package_type_id
|
||||||
|
if self.shipping_weight:
|
||||||
|
delivery_package.shipping_weight = self.shipping_weight
|
||||||
|
# Hibou : Fill additional fields.
|
||||||
|
delivery_package.write({
|
||||||
|
'declared_value': self.package_declared_value,
|
||||||
|
'require_insurance': self.package_require_insurance,
|
||||||
|
'require_signature': self.package_require_signature,
|
||||||
|
})
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ class StockQuantPackage(models.Model):
|
|||||||
|
|
||||||
carrier_id = fields.Many2one('delivery.carrier', string='Carrier')
|
carrier_id = fields.Many2one('delivery.carrier', string='Carrier')
|
||||||
carrier_tracking_ref = fields.Char(string='Tracking Reference')
|
carrier_tracking_ref = fields.Char(string='Tracking Reference')
|
||||||
|
require_insurance = fields.Boolean(string='Require Insurance')
|
||||||
|
require_signature = fields.Boolean(string='Require Signature')
|
||||||
|
declared_value = fields.Float(string='Declared Value')
|
||||||
|
|
||||||
def _get_active_picking(self):
|
def _get_active_picking(self):
|
||||||
picking_id = self._context.get('active_id')
|
picking_id = self._context.get('active_id')
|
||||||
@@ -34,7 +37,14 @@ class StockPicking(models.Model):
|
|||||||
('no', 'No'),
|
('no', 'No'),
|
||||||
], string='Require Insurance', default='auto',
|
], string='Require Insurance', default='auto',
|
||||||
help='If your carrier supports it, auto should be calculated off of the "Automatic Insurance Value" field.')
|
help='If your carrier supports it, auto should be calculated off of the "Automatic Insurance Value" field.')
|
||||||
|
require_signature = fields.Selection([
|
||||||
|
('auto', 'Automatic'),
|
||||||
|
('yes', 'Yes'),
|
||||||
|
('no', 'No'),
|
||||||
|
], string='Require Signature', default='auto',
|
||||||
|
help='If your carrier supports it, auto should be calculated off of the "Automatic Signature Required Value" field.')
|
||||||
package_carrier_tracking_ref = fields.Char(string='Package Tracking Numbers', compute='_compute_package_carrier_tracking_ref')
|
package_carrier_tracking_ref = fields.Char(string='Package Tracking Numbers', compute='_compute_package_carrier_tracking_ref')
|
||||||
|
commercial_partner_id = fields.Many2one('res.partner', related='partner_id.commercial_partner_id')
|
||||||
|
|
||||||
@api.depends('package_ids.carrier_tracking_ref')
|
@api.depends('package_ids.carrier_tracking_ref')
|
||||||
def _compute_package_carrier_tracking_ref(self):
|
def _compute_package_carrier_tracking_ref(self):
|
||||||
@@ -67,8 +77,10 @@ class StockPicking(models.Model):
|
|||||||
res = super(StockPicking, self).create(values)
|
res = super(StockPicking, self).create(values)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def declared_value(self):
|
def declared_value(self, package=None):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
|
if package:
|
||||||
|
return package.declared_value
|
||||||
cost = sum([(l.product_id.standard_price * l.qty_done) for l in self.move_line_ids] or [0.0])
|
cost = sum([(l.product_id.standard_price * l.qty_done) for l in self.move_line_ids] or [0.0])
|
||||||
if not cost:
|
if not cost:
|
||||||
# Assume Full Value
|
# Assume Full Value
|
||||||
@@ -112,6 +124,8 @@ class StockPicking(models.Model):
|
|||||||
tracking_numbers.append(tracking_number)
|
tracking_numbers.append(tracking_number)
|
||||||
# Try to add tracking to the individual packages.
|
# Try to add tracking to the individual packages.
|
||||||
potential_tracking_numbers = tracking_number.split(',')
|
potential_tracking_numbers = tracking_number.split(',')
|
||||||
|
if len(potential_tracking_numbers) == 1:
|
||||||
|
potential_tracking_numbers = tracking_number.split('+') # UPS for example...
|
||||||
if len(potential_tracking_numbers) >= len(carrier_packages):
|
if len(potential_tracking_numbers) >= len(carrier_packages):
|
||||||
for t, p in zip(potential_tracking_numbers, carrier_packages):
|
for t, p in zip(potential_tracking_numbers, carrier_packages):
|
||||||
p.carrier_tracking_ref = t
|
p.carrier_tracking_ref = t
|
||||||
@@ -150,9 +164,10 @@ class StockPicking(models.Model):
|
|||||||
for carrier in carriers:
|
for carrier in carriers:
|
||||||
carrier_packages = packages_with_carrier.filtered(lambda p: p.carrier_id == carrier)
|
carrier_packages = packages_with_carrier.filtered(lambda p: p.carrier_id == carrier)
|
||||||
carrier.cancel_shipment(self, packages=carrier_packages)
|
carrier.cancel_shipment(self, packages=carrier_packages)
|
||||||
package_refs = ','.join(carrier_packages.mapped('carrier_tracking_ref'))
|
# Above cancel should also say which are cancelled in chatter.
|
||||||
msg = "Shipment %s cancelled" % package_refs
|
# package_refs = ','.join(carrier_packages.mapped('carrier_tracking_ref'))
|
||||||
picking.message_post(body=msg)
|
# msg = "Shipment %s cancelled" % package_refs
|
||||||
|
# picking.message_post(body=msg)
|
||||||
carrier_packages.write({'carrier_tracking_ref': False})
|
carrier_packages.write({'carrier_tracking_ref': False})
|
||||||
|
|
||||||
pickings_without_package_tracking = self - pickings_with_package_tracking
|
pickings_without_package_tracking = self - pickings_with_package_tracking
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='integration_level']" position="after">
|
<xpath expr="//field[@name='integration_level']" position="after">
|
||||||
<field name="automatic_insurance_value"/>
|
<field name="automatic_insurance_value"/>
|
||||||
|
<field name="automatic_sig_req_value"/>
|
||||||
<field name="procurement_priority"/>
|
<field name="procurement_priority"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
@@ -20,6 +21,11 @@
|
|||||||
<xpath expr="//field[@name='delivery_package_type_id']" position="attributes">
|
<xpath expr="//field[@name='delivery_package_type_id']" position="attributes">
|
||||||
<attribute name="domain">[]</attribute>
|
<attribute name="domain">[]</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
<xpath expr="//field[@name='delivery_package_type_id']" position="after">
|
||||||
|
<field name="package_declared_value" />
|
||||||
|
<field name="package_require_insurance" />
|
||||||
|
<field name="package_require_signature" />
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
<field name="carrier_tracking_ref" class="oe_inline" />
|
<field name="carrier_tracking_ref" class="oe_inline" />
|
||||||
<button type="object" class="fa fa-arrow-right oe_link" name="cancel_shipment" string="Cancel" attrs="{'invisible':['|',('carrier_tracking_ref','=',False),('carrier_id','=', False)]}"/>
|
<button type="object" class="fa fa-arrow-right oe_link" name="cancel_shipment" string="Cancel" attrs="{'invisible':['|',('carrier_tracking_ref','=',False),('carrier_id','=', False)]}"/>
|
||||||
</div>
|
</div>
|
||||||
|
<field name="declared_value" />
|
||||||
|
<field name="require_insurance" />
|
||||||
|
<field name="require_signature" />
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -28,8 +31,12 @@
|
|||||||
<field name="priority" eval="200" />
|
<field name="priority" eval="200" />
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//field[@name='carrier_id']" position="before">
|
<xpath expr="//field[@name='carrier_id']" position="before">
|
||||||
|
<field name="commercial_partner_id" invisible="1" />
|
||||||
<field name="require_insurance" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
|
<field name="require_insurance" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
|
||||||
<field name="shipping_account_id" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
|
<field name="require_signature" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
|
||||||
|
<field name="shipping_account_id" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"
|
||||||
|
options="{'no_create': True, 'no_open': True}"
|
||||||
|
domain="[('partner_id', 'in', (False, partner_id, commercial_partner_id))]"/>
|
||||||
<field name="package_carrier_tracking_ref" attrs="{'invisible': [('package_carrier_tracking_ref', '=', False)]}" />
|
<field name="package_carrier_tracking_ref" attrs="{'invisible': [('package_carrier_tracking_ref', '=', False)]}" />
|
||||||
<button name="clear_carrier_tracking_ref" type="object" string="Clear Tracking" attrs="{'invisible': [('carrier_tracking_ref', '!=', False)]}" />
|
<button name="clear_carrier_tracking_ref" type="object" string="Clear Tracking" attrs="{'invisible': [('carrier_tracking_ref', '!=', False)]}" />
|
||||||
<button name="reset_carrier_tracking_ref" type="object" string="Reset Tracking" attrs="{'invisible': [('package_carrier_tracking_ref', '!=', False)]}" />
|
<button name="reset_carrier_tracking_ref" type="object" string="Reset Tracking" attrs="{'invisible': [('package_carrier_tracking_ref', '!=', False)]}" />
|
||||||
|
|||||||
Reference in New Issue
Block a user