mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[REL] delivery_fedex_hibou,delivery_gso,delivery_hibou,delivery_ups_hibou,sale_planner,stock_delivery_planner: per-package tracking from 11.0
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
'name': 'Delivery Hibou',
|
||||
'summary': 'Adds underlying pinnings for things like "RMA Return Labels"',
|
||||
'version': '13.0.1.1.0',
|
||||
'version': '13.0.1.2.0',
|
||||
'author': "Hibou Corp.",
|
||||
'category': 'Stock',
|
||||
'license': 'AGPL-3',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from odoo import fields, models
|
||||
from odoo import api, fields, models
|
||||
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
@@ -9,6 +9,9 @@ class DeliveryCarrier(models.Model):
|
||||
automatic_insurance_value = fields.Float(string='Automatic Insurance Value',
|
||||
help='Will be used during shipping to determine if the '
|
||||
'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,
|
||||
string='Procurement Priority',
|
||||
help='Priority for this carrier. Will affect pickings '
|
||||
@@ -16,7 +19,7 @@ class DeliveryCarrier(models.Model):
|
||||
|
||||
# Utility
|
||||
|
||||
def get_insurance_value(self, order=None, picking=None):
|
||||
def get_insurance_value(self, order=None, picking=None, package=None):
|
||||
value = 0.0
|
||||
if order:
|
||||
if order.order_line:
|
||||
@@ -24,13 +27,34 @@ class DeliveryCarrier(models.Model):
|
||||
else:
|
||||
return value
|
||||
if picking:
|
||||
value = picking.declared_value()
|
||||
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 = picking.declared_value(package=package)
|
||||
if package and not package.require_insurance:
|
||||
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
|
||||
|
||||
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):
|
||||
if order and order.shipping_account_id:
|
||||
return order.shipping_account_id
|
||||
@@ -202,9 +226,9 @@ class DeliveryCarrier(models.Model):
|
||||
|
||||
res = []
|
||||
for carrier in self:
|
||||
carrier_packages = packages.filtered(lambda p: not p.carrier_tracking_ref and
|
||||
(not p.carrier_id or p.carrier_id == carrier) and
|
||||
p.packaging_id.package_carrier_type in (False, '', 'none', carrier.delivery_type))
|
||||
carrier_packages = packages and packages.filtered(lambda p: not p.carrier_tracking_ref and
|
||||
(not p.carrier_id or p.carrier_id == carrier) and
|
||||
p.packaging_id.package_carrier_type in (False, '', 'none', carrier.delivery_type))
|
||||
if packages and not carrier_packages:
|
||||
continue
|
||||
if hasattr(carrier, '%s_rate_shipment_multi' % self.delivery_type):
|
||||
@@ -243,3 +267,47 @@ class DeliveryCarrier(models.Model):
|
||||
})
|
||||
|
||||
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',
|
||||
default=lambda self: self._default_package_declared_value())
|
||||
package_require_insurance = fields.Boolean(string='Require Insurance')
|
||||
package_require_signature = fields.Boolean(string='Require Signature')
|
||||
|
||||
def _default_package_declared_value(self):
|
||||
# guard for install
|
||||
if not self.env.context.get('active_id'):
|
||||
return 0.0
|
||||
if self.env.context.get('default_stock_quant_package_id'):
|
||||
stock_quant_package = self.env['stock.quant.package'].browse(self.env.context['default_stock_quant_package_id'])
|
||||
return stock_quant_package.package_declared_value
|
||||
else:
|
||||
picking_id = self.env['stock.picking'].browse(self.env.context['active_id'])
|
||||
move_line_ids = [po for po in picking_id.move_line_ids if po.qty_done > 0 and not po.result_package_id]
|
||||
total_value = sum([po.qty_done * po.product_id.standard_price for po in move_line_ids])
|
||||
return total_value
|
||||
|
||||
@api.onchange('package_declared_value')
|
||||
def _onchange_package_declared_value(self):
|
||||
picking = self.env['stock.picking'].browse(self.env.context['active_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 put_in_pack(self):
|
||||
super().put_in_pack()
|
||||
if self.stock_quant_package_id:
|
||||
self.stock_quant_package_id.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_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):
|
||||
picking_id = self._context.get('active_id')
|
||||
@@ -34,6 +37,12 @@ class StockPicking(models.Model):
|
||||
('no', 'No'),
|
||||
], string='Require Insurance', default='auto',
|
||||
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')
|
||||
|
||||
@api.depends('package_ids.carrier_tracking_ref')
|
||||
@@ -74,8 +83,10 @@ class StockPicking(models.Model):
|
||||
res = super(StockPicking, self).create(values)
|
||||
return res
|
||||
|
||||
def declared_value(self):
|
||||
def declared_value(self, package=None):
|
||||
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])
|
||||
if not cost:
|
||||
# Assume Full Value
|
||||
@@ -119,6 +130,8 @@ class StockPicking(models.Model):
|
||||
tracking_numbers.append(tracking_number)
|
||||
# Try to add tracking to the individual packages.
|
||||
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):
|
||||
for t, p in zip(potential_tracking_numbers, carrier_packages):
|
||||
p.carrier_tracking_ref = t
|
||||
|
||||
@@ -28,8 +28,10 @@ class TestDeliveryHibou(common.TransactionCase):
|
||||
|
||||
# Assign values to new Carrier
|
||||
test_insurance_value = 600
|
||||
test_sig_req_value = 300
|
||||
test_procurement_priority = '1'
|
||||
self.carrier.automatic_insurance_value = test_insurance_value
|
||||
self.carrier.automatic_sig_req_value = test_sig_req_value
|
||||
self.carrier.procurement_priority = test_procurement_priority
|
||||
|
||||
|
||||
@@ -77,7 +79,9 @@ class TestDeliveryHibou(common.TransactionCase):
|
||||
|
||||
def test_carrier_hibou_out(self):
|
||||
test_insurance_value = 4000
|
||||
test_sig_req_value = 4000
|
||||
self.carrier.automatic_insurance_value = test_insurance_value
|
||||
self.carrier.automatic_sig_req_value = test_sig_req_value
|
||||
|
||||
picking_out = self.env.ref('stock.outgoing_shipment_main_warehouse')
|
||||
picking_out.action_assign()
|
||||
@@ -94,21 +98,29 @@ class TestDeliveryHibou(common.TransactionCase):
|
||||
# The 'value' is assumed to be all of the product value from the initial demand.
|
||||
self.assertEqual(picking_out.declared_value(), 15.0 * 3300.0)
|
||||
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), picking_out.declared_value())
|
||||
self.assertTrue(picking_out.carrier_id.get_signature_required(picking=picking_out))
|
||||
|
||||
# Workflow where user explicitly opts out of insurance on the picking level.
|
||||
picking_out.require_insurance = 'no'
|
||||
picking_out.require_signature = 'no'
|
||||
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 0.0)
|
||||
self.assertFalse(picking_out.carrier_id.get_signature_required(picking=picking_out))
|
||||
picking_out.require_insurance = 'auto'
|
||||
picking_out.require_signature = 'auto'
|
||||
|
||||
# Lets choose to only delivery one piece at the moment.
|
||||
# This does not meet the minimum on the carrier to have insurance value.
|
||||
picking_out.move_line_ids.qty_done = 1.0
|
||||
self.assertEqual(picking_out.declared_value(), 3300.0)
|
||||
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 0.0)
|
||||
self.assertFalse(picking_out.carrier_id.get_signature_required(picking=picking_out))
|
||||
# Workflow where user opts in to insurance.
|
||||
picking_out.require_insurance = 'yes'
|
||||
picking_out.require_signature = 'yes'
|
||||
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 3300.0)
|
||||
self.assertTrue(picking_out.carrier_id.get_signature_required(picking=picking_out))
|
||||
picking_out.require_insurance = 'auto'
|
||||
picking_out.require_signature = 'auto'
|
||||
|
||||
# Test with picking having 3rd party account.
|
||||
self.assertEqual(picking_out.carrier_id.get_third_party_account(picking=picking_out), None)
|
||||
@@ -135,9 +147,9 @@ class TestDeliveryHibou(common.TransactionCase):
|
||||
picking_in.carrier_id = self.carrier
|
||||
# This relies heavily on the 'stock' demo data.
|
||||
# Should only have a single move_line_ids and it should not be done at all.
|
||||
self.assertEqual(picking_in.move_line_ids.mapped('qty_done'), [0.0, 0.0, 0.0])
|
||||
self.assertEqual(picking_in.move_line_ids.mapped('product_uom_qty'), [35.0, 10.0, 12.0])
|
||||
self.assertEqual(picking_in.move_line_ids.mapped('product_id.standard_price'), [55.0, 35.0, 1700.0])
|
||||
self.assertEqual(picking_in.move_line_ids.mapped('qty_done'), [0.0])
|
||||
self.assertEqual(picking_in.move_line_ids.mapped('product_uom_qty'), [35.0])
|
||||
self.assertEqual(picking_in.move_line_ids.mapped('product_id.standard_price'), [55.0])
|
||||
|
||||
self.assertEqual(picking_in.carrier_id._classify_picking(picking=picking_in), 'in')
|
||||
self.assertEqual(picking_in.carrier_id.get_shipper_company(picking=picking_in),
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='integration_level']" position="after">
|
||||
<field name="automatic_insurance_value"/>
|
||||
<field name="automatic_sig_req_value"/>
|
||||
<field name="procurement_priority"/>
|
||||
</xpath>
|
||||
</field>
|
||||
@@ -20,6 +21,11 @@
|
||||
<xpath expr="//field[@name='delivery_packaging_id']" position="attributes">
|
||||
<attribute name="domain">[('product_id', '=', False)]</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='delivery_packaging_id']" position="after">
|
||||
<field name="package_declared_value" />
|
||||
<field name="package_require_insurance" />
|
||||
<field name="package_require_signature" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
<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)]}"/>
|
||||
</div>
|
||||
<field name="declared_value" />
|
||||
<field name="require_insurance" />
|
||||
<field name="require_signature" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
@@ -29,7 +32,10 @@
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='carrier_id']" position="before">
|
||||
<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', '=', False), ('partner_id', '=', partner_id)]"/>
|
||||
<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="reset_carrier_tracking_ref" type="object" string="Reset Tracking" attrs="{'invisible': [('package_carrier_tracking_ref', '!=', False)]}" />
|
||||
|
||||
Reference in New Issue
Block a user