From cdebdb88880a29e8391f1754d87e52998b9f26da Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Wed, 9 Feb 2022 08:56:42 -0800 Subject: [PATCH 01/17] [IMP] delivery_gso: weight conversion, per-package insurance/sig.req --- delivery_gso/__manifest__.py | 2 +- delivery_gso/models/delivery_gso.py | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/delivery_gso/__manifest__.py b/delivery_gso/__manifest__.py index e1923d56..26968b3a 100644 --- a/delivery_gso/__manifest__.py +++ b/delivery_gso/__manifest__.py @@ -1,7 +1,7 @@ { 'name': 'Golden State Overnight (gso.com) Shipping', 'summary': 'Send your shippings through gso.com and track them online.', - 'version': '15.0.1.0.0', + 'version': '15.0.1.0.1', 'author': "Hibou Corp.", 'category': 'Warehouse', 'license': 'OPL-1', diff --git a/delivery_gso/models/delivery_gso.py b/delivery_gso/models/delivery_gso.py index a242ff85..cc3a6965 100644 --- a/delivery_gso/models/delivery_gso.py +++ b/delivery_gso/models/delivery_gso.py @@ -196,14 +196,6 @@ class ProviderGSO(models.Model): request_body['Shipment'].update(self._gso_make_shipper_address(from_, company)) request_body['Shipment'].update(self._gso_make_ship_address(to)) - # Automatic insurance at $100.0 - insurance_value = sudoself.get_insurance_value(picking=picking) - if insurance_value: - request_body['Shipment']['SignatureCode'] = 'SIG_REQD' - if insurance_value > 100.0: - # Documentation says to set DeclaredValue ONLY if over $100.00 - request_body['Shipment']['DeclaredValue'] = insurance_value - cost = 0.0 labels = { 'thermal': [], @@ -218,6 +210,20 @@ class ProviderGSO(models.Model): if picking_packages: # Every package will be a transaction for package in picking_packages: + # Use Sale Order Number or fall back to Picking + shipment_ref = (picking.sale_id.name if picking.sale_id else picking.name) + '-' + package.name + insurance_value = sudoself.get_insurance_value(picking=picking, package=package) + if insurance_value > 100.0: + # Documentation says to set DeclaredValue ONLY if over $100.00 + request_body['Shipment']['DeclaredValue'] = insurance_value + elif 'DeclaredValue' in request_body['Shipment']: + del request_body['Shipment']['DeclaredValue'] + + if sudoself.get_signature_required(picking=picking, package=package): + request_body['Shipment']['SignatureCode'] = 'SIG_REQD' + else: + request_body['Shipment']['SignatureCode'] = 'SIG_NOT_REQD' + request_body['Shipment']['Weight'] = self._gso_convert_weight(package.shipping_weight) request_body['Shipment'].update(self._gso_get_package_dimensions(package)) request_body['Shipment']['ShipmentReference'] = package.name @@ -236,9 +242,10 @@ class ProviderGSO(models.Model): raise ValidationError(e) elif not package_carriers: # ship the whole picking + shipment_ref = picking.sale_id.name if picking.sale_id else picking.name request_body['Shipment']['Weight'] = self._gso_convert_weight(picking.shipping_weight) request_body['Shipment'].update(self._gso_get_package_dimensions()) - request_body['Shipment']['ShipmentReference'] = picking.name + request_body['Shipment']['ShipmentReference'] = shipment_ref request_body['Shipment']['TrackingNumber'] = self._gso_create_tracking_number(picking.name) try: response = service.post_shipment(request_body) @@ -393,7 +400,7 @@ class ProviderGSO(models.Model): elif not package: est_weight_value = self._gso_convert_weight(picking.shipping_weight) else: - est_weight_value = package.shipping_weight or package.weight + est_weight_value = self._gso_convert_weight(package.shipping_weight or package.weight) request_body = { 'AccountNumber': sudoself.gso_account_number, @@ -409,7 +416,7 @@ class ProviderGSO(models.Model): result = service.get_rates_and_transit_time(request_body) # _logger.warning('GSO result:\n%s' % result) except HTTPError as e: - _logger.error(e) + # _logger.error(e) return [{ 'success': False, 'price': 0.0, From 03c0b61d21873c1dfbd457aa58fb8f6175a3fcd0 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Wed, 9 Feb 2022 09:16:39 -0800 Subject: [PATCH 02/17] [IMP] delivery_hibou: per-package insurance and signature req. --- delivery_hibou/__manifest__.py | 2 +- delivery_hibou/models/delivery.py | 112 +++++++++++++++++++++--- delivery_hibou/models/stock.py | 23 ++++- delivery_hibou/views/delivery_views.xml | 6 ++ delivery_hibou/views/stock_views.xml | 9 +- 5 files changed, 136 insertions(+), 16 deletions(-) diff --git a/delivery_hibou/__manifest__.py b/delivery_hibou/__manifest__.py index 62d37108..96441511 100644 --- a/delivery_hibou/__manifest__.py +++ b/delivery_hibou/__manifest__.py @@ -1,7 +1,7 @@ { 'name': 'Delivery Hibou', '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.", 'category': 'Stock', 'license': 'LGPL-3', diff --git a/delivery_hibou/models/delivery.py b/delivery_hibou/models/delivery.py index 85f1f931..78e9f876 100644 --- a/delivery_hibou/models/delivery.py +++ b/delivery_hibou/models/delivery.py @@ -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.exceptions import UserError @@ -9,6 +10,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,21 +20,42 @@ 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: - 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: 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 +227,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.package_type_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_type_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 +268,70 @@ 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') + 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, + }) diff --git a/delivery_hibou/models/stock.py b/delivery_hibou/models/stock.py index 9f732275..77ae28b1 100644 --- a/delivery_hibou/models/stock.py +++ b/delivery_hibou/models/stock.py @@ -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,7 +37,14 @@ 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') + commercial_partner_id = fields.Many2one('res.partner', related='partner_id.commercial_partner_id') @api.depends('package_ids.carrier_tracking_ref') def _compute_package_carrier_tracking_ref(self): @@ -67,8 +77,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 @@ -112,6 +124,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 @@ -150,9 +164,10 @@ class StockPicking(models.Model): for carrier in carriers: carrier_packages = packages_with_carrier.filtered(lambda p: p.carrier_id == carrier) carrier.cancel_shipment(self, packages=carrier_packages) - package_refs = ','.join(carrier_packages.mapped('carrier_tracking_ref')) - msg = "Shipment %s cancelled" % package_refs - picking.message_post(body=msg) + # Above cancel should also say which are cancelled in chatter. + # package_refs = ','.join(carrier_packages.mapped('carrier_tracking_ref')) + # msg = "Shipment %s cancelled" % package_refs + # picking.message_post(body=msg) carrier_packages.write({'carrier_tracking_ref': False}) pickings_without_package_tracking = self - pickings_with_package_tracking diff --git a/delivery_hibou/views/delivery_views.xml b/delivery_hibou/views/delivery_views.xml index 681578aa..08fe2010 100644 --- a/delivery_hibou/views/delivery_views.xml +++ b/delivery_hibou/views/delivery_views.xml @@ -7,6 +7,7 @@ + @@ -20,6 +21,11 @@ [] + + + + + diff --git a/delivery_hibou/views/stock_views.xml b/delivery_hibou/views/stock_views.xml index 6bb47f34..0989f519 100644 --- a/delivery_hibou/views/stock_views.xml +++ b/delivery_hibou/views/stock_views.xml @@ -17,6 +17,9 @@