From 15e1bc1051d252f859945bf731e01d194fff2311 Mon Sep 17 00:00:00 2001 From: Mayank Patel Date: Wed, 11 Sep 2024 05:44:24 +0000 Subject: [PATCH] [REM] delivery_fedex_hibou: available in professional H14528 --- delivery_fedex_hibou/__init__.py | 3 - delivery_fedex_hibou/__manifest__.py | 19 - delivery_fedex_hibou/models/__init__.py | 4 - delivery_fedex_hibou/models/delivery_fedex.py | 742 ------------------ delivery_fedex_hibou/models/fedex_request.py | 268 ------- delivery_fedex_hibou/models/stock.py | 10 - delivery_fedex_hibou/views/stock_views.xml | 14 - 7 files changed, 1060 deletions(-) delete mode 100644 delivery_fedex_hibou/__init__.py delete mode 100644 delivery_fedex_hibou/__manifest__.py delete mode 100644 delivery_fedex_hibou/models/__init__.py delete mode 100644 delivery_fedex_hibou/models/delivery_fedex.py delete mode 100644 delivery_fedex_hibou/models/fedex_request.py delete mode 100644 delivery_fedex_hibou/models/stock.py delete mode 100644 delivery_fedex_hibou/views/stock_views.xml diff --git a/delivery_fedex_hibou/__init__.py b/delivery_fedex_hibou/__init__.py deleted file mode 100644 index 09434554..00000000 --- a/delivery_fedex_hibou/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from . import models diff --git a/delivery_fedex_hibou/__manifest__.py b/delivery_fedex_hibou/__manifest__.py deleted file mode 100644 index 67f04fdf..00000000 --- a/delivery_fedex_hibou/__manifest__.py +++ /dev/null @@ -1,19 +0,0 @@ -{ - 'name': 'Hibou Fedex Shipping', - 'version': '15.0.1.0.0', - 'category': 'Stock', - 'author': "Hibou Corp.", - 'license': 'OPL-1', - 'website': 'https://hibou.io/', - 'depends': [ - 'delivery_fedex', - 'delivery_hibou', - ], - 'data': [ - 'views/stock_views.xml', - ], - 'demo': [ - ], - 'installable': True, - 'application': False, - } diff --git a/delivery_fedex_hibou/models/__init__.py b/delivery_fedex_hibou/models/__init__.py deleted file mode 100644 index bad254c1..00000000 --- a/delivery_fedex_hibou/models/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from . import delivery_fedex -from . import stock diff --git a/delivery_fedex_hibou/models/delivery_fedex.py b/delivery_fedex_hibou/models/delivery_fedex.py deleted file mode 100644 index 3b9ebe09..00000000 --- a/delivery_fedex_hibou/models/delivery_fedex.py +++ /dev/null @@ -1,742 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -import logging -import pytz -from odoo import fields, models, tools, _ -from odoo.exceptions import UserError, ValidationError -from odoo.addons.delivery_fedex.models.delivery_fedex import _convert_curr_iso_fdx -from .fedex_request import FedexRequest - -pdf = tools.pdf -_logger = logging.getLogger(__name__) - - -class DeliveryFedex(models.Model): - _inherit = 'delivery.carrier' - - fedex_service_type = fields.Selection(selection_add=[ - ('GROUND_HOME_DELIVERY', 'GROUND_HOME_DELIVERY'), - # ('FEDEX_EXPRESS_SAVER', 'FEDEX_EXPRESS_SAVER'), # included in 13.0, ensure it stays there... - ]) - - def _get_fedex_is_third_party(self, order=None, picking=None): - third_party_account = self.get_third_party_account(order=order, picking=picking) - if third_party_account: - if not third_party_account.delivery_type == 'fedex': - raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.') - return True - return False - - def _get_fedex_payment_account_number(self, order=None, picking=None): - """ - Common hook to customize what Fedex Account number to use. - :return: FedEx Account Number - """ - # Provided by Hibou Odoo Suite `delivery_hibou` - third_party_account = self.get_third_party_account(order=order, picking=picking) - if third_party_account: - if not third_party_account.delivery_type == 'fedex': - raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.') - return third_party_account.name - if picking and picking.picking_type_id.warehouse_id.fedex_account_number: - return picking.picking_type_id.warehouse_id.fedex_account_number - return self.fedex_account_number - - def _get_fedex_account_number(self, order=None, picking=None): - if order: - # third_party_account = self.get_third_party_account(order=order, picking=picking) - # if third_party_account: - # if not third_party_account.delivery_type == 'fedex': - # raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.') - # return third_party_account.name - if order.warehouse_id.fedex_account_number: - return order.warehouse_id.fedex_account_number - return self.fedex_account_number - if picking: - if picking.picking_type_id.warehouse_id.fedex_account_number: - return picking.picking_type_id.warehouse_id.fedex_account_number - return self.fedex_account_number - - def _get_fedex_meter_number(self, order=None, picking=None): - if order: - if order.warehouse_id.fedex_meter_number: - return order.warehouse_id.fedex_meter_number - return self.fedex_meter_number - if picking: - if picking.picking_type_id.warehouse_id.fedex_meter_number: - return picking.picking_type_id.warehouse_id.fedex_meter_number - return self.fedex_meter_number - - def _get_fedex_recipient_is_residential(self, partner): - if self.fedex_service_type.find('HOME') >= 0: - return True - return not (partner.is_company or partner.parent_id.is_company) - - """ - Overrides to use Hibou Delivery methods to get shipper etc. and to add 'transit_days' to result. - """ - def fedex_rate_shipment(self, order): - max_weight = self._fedex_convert_weight(self.fedex_default_package_type_id.max_weight, self.fedex_weight_unit) - price = 0.0 - is_india = order.partner_shipping_id.country_id.code == 'IN' and order.company_id.partner_id.country_id.code == 'IN' - - # Estimate weight of the sales order; will be definitely recomputed on the picking field "weight" - est_weight_value = sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line if not line.display_type]) or 0.0 - weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit) - - # Some users may want to ship very lightweight items; in order to give them a rating, we round the - # converted weight of the shipping to the smallest value accepted by FedEx: 0.01 kg or lb. - # (in the case where the weight is actually 0.0 because weights are not set, don't do this) - if weight_value > 0.0: - weight_value = max(weight_value, 0.01) - - order_currency = order.currency_id - superself = self.sudo() - - # Hibou Delivery methods for collecting details in an overridable way - shipper_company = superself.get_shipper_company(order=order) - shipper_warehouse = superself.get_shipper_warehouse(order=order) - recipient = superself.get_recipient(order=order) - acc_number = superself._get_fedex_account_number(order=order) - meter_number = superself._get_fedex_meter_number(order=order) - order_name = superself.get_order_name(order=order) - residential = self._get_fedex_recipient_is_residential(recipient) - date_planned = None - if self.env.context.get('date_planned'): - date_planned = self.env.context.get('date_planned') - - # Authentication stuff - srm = FedexRequest(self.log_xml, request_type="rating", prod_environment=self.prod_environment) - srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password) - srm.client_detail(acc_number, meter_number) - - # Build basic rating request and set addresses - srm.transaction_detail(order_name) - srm.shipment_request( - self.fedex_droppoff_type, - self.fedex_service_type, - self.fedex_default_package_type_id.shipper_package_code, - self.fedex_weight_unit, - self.fedex_saturday_delivery, - ) - pkg = self.fedex_default_package_type_id - - srm.set_currency(_convert_curr_iso_fdx(order_currency.name)) - srm.set_shipper(shipper_company, shipper_warehouse) - srm.set_recipient(recipient, residential=residential) - - if max_weight and weight_value > max_weight: - total_package = int(weight_value / max_weight) - last_package_weight = weight_value % max_weight - - for sequence in range(1, total_package + 1): - srm.add_package( - max_weight, - package_code=pkg.shipper_package_code, - package_height=pkg.height, - package_width=pkg.width, - package_length=pkg.packaging_length, - sequence_number=sequence, - mode='rating', - ) - if last_package_weight: - total_package = total_package + 1 - srm.add_package( - last_package_weight, - package_code=pkg.shipper_package_code, - package_height=pkg.height, - package_width=pkg.width, - package_length=pkg.packaging_length, - sequence_number=total_package, - mode='rating', - ) - srm.set_master_package(weight_value, total_package) - else: - srm.add_package( - weight_value, - package_code=pkg.shipper_package_code, - package_height=pkg.height, - package_width=pkg.width, - package_length=pkg.packaging_length, - mode='rating', - ) - srm.set_master_package(weight_value, 1) - - # Commodities for customs declaration (international shipping) - if self.fedex_service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'] or is_india: - total_commodities_amount = 0.0 - commodity_country_of_manufacture = order.warehouse_id.partner_id.country_id.code - - for line in order.order_line.filtered(lambda l: l.product_id.type in ['product', 'consu'] and not l.display_type): - commodity_amount = line.price_reduce_taxinc - total_commodities_amount += (commodity_amount * line.product_uom_qty) - commodity_description = line.product_id.name - commodity_number_of_piece = '1' - commodity_weight_units = self.fedex_weight_unit - commodity_weight_value = self._fedex_convert_weight(line.product_id.weight * line.product_uom_qty, self.fedex_weight_unit) - commodity_quantity = line.product_uom_qty - commodity_quantity_units = 'EA' - commodity_harmonized_code = line.product_id.hs_code or '' - srm.commodities(_convert_curr_iso_fdx(order_currency.name), commodity_amount, commodity_number_of_piece, commodity_weight_units, commodity_weight_value, commodity_description, commodity_country_of_manufacture, commodity_quantity, commodity_quantity_units, commodity_harmonized_code) - srm.customs_value(_convert_curr_iso_fdx(order_currency.name), total_commodities_amount, "NON_DOCUMENTS") - srm.duties_payment(order.warehouse_id.partner_id, acc_number, superself.fedex_duty_payment) - - request = srm.rate(date_planned=date_planned) - - warnings = request.get('warnings_message') - if warnings: - _logger.info(warnings) - - if not request.get('errors_message'): - if _convert_curr_iso_fdx(order_currency.name) in request['price']: - price = request['price'][_convert_curr_iso_fdx(order_currency.name)] - else: - _logger.info("Preferred currency has not been found in FedEx response") - company_currency = order.company_id.currency_id - if _convert_curr_iso_fdx(company_currency.name) in request['price']: - amount = request['price'][_convert_curr_iso_fdx(company_currency.name)] - price = company_currency._convert(amount, order_currency, order.company_id, order.date_order or fields.Date.today()) - else: - amount = request['price']['USD'] - price = company_currency._convert(amount, order_currency, order.company_id, order.date_order or fields.Date.today()) - else: - return {'success': False, - 'price': 0.0, - 'error_message': _('Error:\n%s') % request['errors_message'], - 'warning_message': False} - - date_delivered = request.get('date_delivered', False) - if date_delivered and 'delivery_calendar_id' in self and self.delivery_calendar_id.tz: - tz = pytz.timezone(self.delivery_calendar_id.tz) - date_delivered = tz.localize(date_delivered).astimezone(pytz.utc).replace(tzinfo=None) - return {'success': True, - 'price': price, - 'error_message': False, - 'transit_days': request.get('transit_days', False), - 'date_delivered': date_delivered, - 'warning_message': _('Warning:\n%s') % warnings if warnings else False} - - """ - Overrides to use Hibou Delivery methods to get shipper etc. and add insurance. - """ - def fedex_send_shipping(self, pickings): - res = [] - - for picking in pickings: - - srm = FedexRequest(self.log_xml, request_type="shipping", prod_environment=self.prod_environment) - superself = self.sudo() - - picking_packages = picking.package_ids - package_carriers = picking_packages.mapped('carrier_id') - if package_carriers: - # only ship ours - picking_packages = picking_packages.filtered(lambda p: p.carrier_id == self and not p.carrier_tracking_ref) - - if package_carriers and not picking_packages: - continue - - shipper_company = superself.get_shipper_company(picking=picking) - shipper_warehouse = superself.get_shipper_warehouse(picking=picking) - recipient = superself.get_recipient(picking=picking) - acc_number = superself._get_fedex_account_number(picking=picking) - meter_number = superself._get_fedex_meter_number(picking=picking) - payment_acc_number = superself._get_fedex_payment_account_number(picking=picking) - order_name = superself.get_order_name(picking=picking) - attn = superself.get_attn(picking=picking) - residential = self._get_fedex_recipient_is_residential(recipient) - - srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password) - srm.client_detail(acc_number, meter_number) - - srm.transaction_detail(picking.id) - - package_type = picking_packages and picking_packages[0].package_type_id.shipper_package_code or self.fedex_default_package_type_id.shipper_package_code - srm.shipment_request(self.fedex_droppoff_type, self.fedex_service_type, package_type, self.fedex_weight_unit, self.fedex_saturday_delivery) - srm.set_currency(_convert_curr_iso_fdx(picking.company_id.currency_id.name)) - srm.set_shipper(shipper_company, shipper_warehouse) - srm.set_recipient(recipient, attn=attn, residential=residential) - - srm.shipping_charges_payment(payment_acc_number, third_party=bool(self.get_third_party_account(picking=picking))) - - srm.shipment_label('COMMON2D', self.fedex_label_file_type, self.fedex_label_stock_type, 'TOP_EDGE_OF_TEXT_FIRST', 'SHIPPING_LABEL_FIRST') - - order = picking.sale_id - company = shipper_company - order_currency = picking.sale_id.currency_id or picking.company_id.currency_id - - net_weight = self._fedex_convert_weight(picking.shipping_weight, self.fedex_weight_unit) - - # Commodities for customs declaration (international shipping) - if self.fedex_service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'] or (picking.partner_id.country_id.code == 'IN' and picking.picking_type_id.warehouse_id.partner_id.country_id.code == 'IN'): - - commodity_currency = order_currency - total_commodities_amount = 0.0 - commodity_country_of_manufacture = picking.picking_type_id.warehouse_id.partner_id.country_id.code - - for operation in picking.move_line_ids: - commodity_amount = operation.move_id.sale_line_id.price_reduce_taxinc or operation.product_id.lst_price - total_commodities_amount += (commodity_amount * operation.qty_done) - commodity_description = operation.product_id.name - commodity_number_of_piece = '1' - commodity_weight_units = self.fedex_weight_unit - commodity_weight_value = self._fedex_convert_weight(operation.product_id.weight * operation.qty_done, self.fedex_weight_unit) - commodity_quantity = operation.qty_done - commodity_quantity_units = 'EA' - commodity_harmonized_code = operation.product_id.hs_code or '' - srm.commodities(_convert_curr_iso_fdx(commodity_currency.name), commodity_amount, commodity_number_of_piece, commodity_weight_units, commodity_weight_value, commodity_description, commodity_country_of_manufacture, commodity_quantity, commodity_quantity_units, commodity_harmonized_code) - srm.customs_value(_convert_curr_iso_fdx(commodity_currency.name), total_commodities_amount, "NON_DOCUMENTS") - srm.duties_payment(shipper_warehouse, acc_number, superself.fedex_duty_payment) - send_etd = superself.env['ir.config_parameter'].get_param("delivery_fedex.send_etd") - srm.commercial_invoice(self.fedex_document_stock_type, send_etd) - - package_count = len(picking_packages) or 1 - - # For india picking courier is not accepted without this details in label. - po_number = order.display_name or False - dept_number = False - if picking.partner_id.country_id.code == 'IN' and picking.picking_type_id.warehouse_id.partner_id.country_id.code == 'IN': - po_number = 'B2B' if picking.partner_id.commercial_partner_id.is_company else 'B2C' - dept_number = 'BILL D/T: SENDER' - - # TODO RIM master: factorize the following crap - - ################ - # Multipackage # - ################ - if package_count > 1: - - # Note: Fedex has a complex multi-piece shipping interface - # - Each package has to be sent in a separate request - # - First package is called "master" package and holds shipping- - # related information, including addresses, customs... - # - Last package responses contains shipping price and code - # - If a problem happens with a package, every previous package - # of the shipping has to be cancelled separately - # (Why doing it in a simple way when the complex way exists??) - - master_tracking_id = False - package_labels = [] - carrier_tracking_ref = "" - - for sequence, package in enumerate(picking_packages, start=1): - - package_weight = self._fedex_convert_weight(package.shipping_weight, self.fedex_weight_unit) - packaging = package.package_type_id - packaging_code = packaging.shipper_package_code if (packaging.package_carrier_type == 'fedex' and packaging.shipper_package_code) else self.fedex_default_package_type_id.shipper_package_code - - # Hibou Delivery - # Add more details to package. - srm._add_package( - package_weight, - package_code=packaging_code, - package_height=packaging.height, - package_width=packaging.width, - package_length=packaging.packaging_length, - sequence_number=sequence, - po_number=po_number, - dept_number=dept_number, - # reference=picking.display_name, - reference=('%s-%d' % (order_name, sequence)), # above "reference" is new in 13.0, using new name but old value - insurance=superself.get_insurance_value(picking=picking, package=package), - signature_required=superself.get_signature_required(picking=picking, package=package) - ) - srm.set_master_package(net_weight, package_count, master_tracking_id=master_tracking_id) - request = srm.process_shipment() - package_name = package.name or sequence - - warnings = request.get('warnings_message') - if warnings: - _logger.info(warnings) - - # First package - if sequence == 1: - if not request.get('errors_message'): - master_tracking_id = request['master_tracking_id'] - package_labels.append((package_name, srm.get_label())) - carrier_tracking_ref = request['tracking_number'] - else: - raise UserError(request['errors_message']) - - # Intermediary packages - elif sequence > 1 and sequence < package_count: - if not request.get('errors_message'): - package_labels.append((package_name, srm.get_label())) - carrier_tracking_ref = carrier_tracking_ref + "," + request['tracking_number'] - else: - raise UserError(request['errors_message']) - - # Last package - elif sequence == package_count: - # recuperer le label pdf - if not request.get('errors_message'): - package_labels.append((package_name, srm.get_label())) - - if _convert_curr_iso_fdx(order_currency.name) in request['price']: - carrier_price = request['price'][_convert_curr_iso_fdx(order_currency.name)] - else: - _logger.info("Preferred currency has not been found in FedEx response") - company_currency = picking.company_id.currency_id - if _convert_curr_iso_fdx(company_currency.name) in request['price']: - amount = request['price'][_convert_curr_iso_fdx(company_currency.name)] - carrier_price = company_currency._convert( - amount, order_currency, company, order.date_order or fields.Date.today()) - else: - amount = request['price']['USD'] - carrier_price = company_currency._convert( - amount, order_currency, company, order.date_order or fields.Date.today()) - - carrier_tracking_ref = carrier_tracking_ref + "," + request['tracking_number'] - - logmessage = _("Shipment created into Fedex
" - "Tracking Numbers: %s
" - "Packages: %s") % (carrier_tracking_ref, ','.join([pl[0] for pl in package_labels])) - if self.fedex_label_file_type != 'PDF': - attachments = [('LabelFedex-%s.%s' % (pl[0], self.fedex_label_file_type), pl[1]) for pl in package_labels] - if self.fedex_label_file_type == 'PDF': - attachments = [('LabelFedex.pdf', pdf.merge_pdf([pl[1] for pl in package_labels]))] - picking.message_post(body=logmessage, attachments=attachments) - shipping_data = {'exact_price': carrier_price, - 'tracking_number': carrier_tracking_ref} - res = res + [shipping_data] - else: - raise UserError(request['errors_message']) - - # TODO RIM handle if a package is not accepted (others should be deleted) - - ############### - # One package # - ############### - elif package_count == 1: - packaging = picking_packages[:1].package_type_id or self.fedex_default_package_type_id - packaging_code = packaging.shipper_package_code if packaging.package_carrier_type == 'fedex' else self.fedex_default_package_type_id.shipper_package_code - srm._add_package( - net_weight, - package_code=packaging_code, - package_height=packaging.height, - package_width=packaging.width, - package_length=packaging.packaging_length, - po_number=po_number, - dept_number=dept_number, - # reference=picking.display_name, - reference=order_name, # above "reference" is new in 13.0, using new name but old value - insurance=superself.get_insurance_value(picking=picking, package=picking_packages[:1]), - signature_required=superself.get_signature_required(picking=picking, package=picking_packages[:1]) - ) - srm.set_master_package(net_weight, 1) - - # Ask the shipping to fedex - request = srm.process_shipment() - - warnings = request.get('warnings_message') - if warnings: - _logger.info(warnings) - - if not request.get('errors_message'): - - if _convert_curr_iso_fdx(order_currency.name) in request['price']: - carrier_price = request['price'][_convert_curr_iso_fdx(order_currency.name)] - else: - _logger.info("Preferred currency has not been found in FedEx response") - company_currency = picking.company_id.currency_id - if _convert_curr_iso_fdx(company_currency.name) in request['price']: - amount = request['price'][_convert_curr_iso_fdx(company_currency.name)] - carrier_price = company_currency._convert( - amount, order_currency, company, order.date_order or fields.Date.today()) - else: - amount = request['price']['USD'] - carrier_price = company_currency._convert( - amount, order_currency, company, order.date_order or fields.Date.today()) - - carrier_tracking_ref = request['tracking_number'] - logmessage = (_("Shipment created into Fedex
Tracking Number : %s") % (carrier_tracking_ref)) - - fedex_labels = [('LabelFedex-%s-%s.%s' % (carrier_tracking_ref, index, self.fedex_label_file_type), label) - for index, label in enumerate(srm._get_labels(self.fedex_label_file_type))] - picking.message_post(body=logmessage, attachments=fedex_labels) - shipping_data = {'exact_price': carrier_price, - 'tracking_number': carrier_tracking_ref} - res = res + [shipping_data] - else: - raise UserError(request['errors_message']) - - ############## - # No package # - ############## - else: - raise UserError(_('No packages for this picking')) - if self.return_label_on_delivery: - self.get_return_label(picking, tracking_number=request['tracking_number'], origin_date=request['date']) - commercial_invoice = srm.get_document() - if commercial_invoice: - fedex_documents = [('DocumentFedex.pdf', commercial_invoice)] - picking.message_post(body='Fedex Documents', attachments=fedex_documents) - return res - - def fedex_rate_shipment_multi(self, order=None, picking=None, packages=None): - if not packages: - return self._fedex_rate_shipment_multi_package(order=order, picking=picking) - else: - rates = [] - for package in packages: - rates += self._fedex_rate_shipment_multi_package(order=order, picking=picking, package=package) - return rates - - def _fedex_rate_shipment_multi_package(self, order=None, picking=None, package=None): - if order: - max_weight = self._fedex_convert_weight(self.fedex_default_package_type_id.max_weight, self.fedex_weight_unit) - is_india = order.partner_shipping_id.country_id.code == 'IN' and order.company_id.partner_id.country_id.code == 'IN' - est_weight_value = sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0 - weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit) - order_currency = order.currency_id - elif not package: - is_india = picking.partner_id.country_id.code == 'IN' and picking.company_id.partner_id.country_id.code == 'IN' - est_weight_value = sum([(line.product_id.weight * (line.qty_done or line.product_uom_qty)) for line in picking.move_line_ids]) or 0.0 - weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit) - order_currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id - else: - is_india = picking.partner_id.country_id.code == 'IN' and picking.company_id.partner_id.country_id.code == 'IN' - order_currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id - est_weight_value = package.shipping_weight or package.weight - weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit) - - - price = 0.0 - - # Some users may want to ship very lightweight items; in order to give them a rating, we round the - # converted weight of the shipping to the smallest value accepted by FedEx: 0.01 kg or lb. - # (in the case where the weight is actually 0.0 because weights are not set, don't do this) - if weight_value > 0.0: - weight_value = max(weight_value, 0.01) - - superself = self.sudo() - - # Hibou Delivery methods for collecting details in an overridable way - shipper_company = superself.get_shipper_company(order=order, picking=picking) - shipper_warehouse = superself.get_shipper_warehouse(order=order, picking=picking) - recipient = superself.get_recipient(order=order, picking=picking) - acc_number = superself._get_fedex_account_number(order=order, picking=picking) - meter_number = superself._get_fedex_meter_number(order=order, picking=picking) - order_name = superself.get_order_name(order=order, picking=picking) - insurance_value = superself.get_insurance_value(order=order, picking=picking, package=package) - signature_required = superself.get_signature_required(order=order, picking=picking, package=package) - residential = self._get_fedex_recipient_is_residential(recipient) - date_planned = fields.Datetime.now() - if self.env.context.get('date_planned'): - date_planned = self.env.context.get('date_planned') - - # Authentication stuff - srm = FedexRequest(self.log_xml, request_type="rating", prod_environment=self.prod_environment) - srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password) - srm.client_detail(acc_number, meter_number) - - # Build basic rating request and set addresses - srm.transaction_detail(order_name) - - # TODO what shipment requests can we make? - # TODO package and main weights? - # TODO need package & weight count to pass in - srm.shipment_request( - self.fedex_droppoff_type, - None, # because we want all of the rates back... - self.fedex_default_package_type_id.shipper_package_code, - self.fedex_weight_unit, - self.fedex_saturday_delivery, - ship_timestamp=date_planned, - ) - pkg = self.fedex_default_package_type_id - - srm.set_currency(_convert_curr_iso_fdx(order_currency.name)) - srm.set_shipper(shipper_company, shipper_warehouse) - srm.set_recipient(recipient, residential=residential) - - if order and max_weight and weight_value > max_weight: - total_package = int(weight_value / max_weight) - last_package_weight = weight_value % max_weight - - for sequence in range(1, total_package + 1): - srm.add_package( - max_weight, - package_code=pkg.shipper_package_code, - package_height=pkg.height, - package_width=pkg.width, - package_length=pkg.packaging_length, - sequence_number=sequence, - mode='rating', - ) - if last_package_weight: - total_package = total_package + 1 - srm.add_package( - last_package_weight, - package_code=pkg.shipper_package_code, - package_height=pkg.height, - package_width=pkg.width, - package_length=pkg.packaging_length, - sequence_number=total_package, - mode='rating', - ) - srm.set_master_package(weight_value, total_package) - elif order: - srm.add_package( - weight_value, - package_code=pkg.shipper_package_code, - package_height=pkg.height, - package_width=pkg.width, - package_length=pkg.packaging_length, - mode='rating', - ) - srm.set_master_package(weight_value, 1) - else: - if package: - package_weight = self._fedex_convert_weight(package.shipping_weight or package.weight, self.fedex_weight_unit) - packaging = package.package_type_id - package_code = package.package_type_id.shipper_package_code if packaging.package_carrier_type == 'fedex' else self.fedex_default_package_type_id.shipper_package_code - - srm.add_package( - package_weight, - mode='rating', - package_code=package_code, - package_height=packaging.height, - package_width=packaging.width, - package_length=packaging.packaging_length, - sequence_number=1, - # po_number=po_number, - # dept_number=dept_number, - reference=('%s-%d' % (order_name, 1)), - insurance=insurance_value, - signature_required=signature_required - ) - srm.set_master_package(package_weight, 1) - else: - # deliver all together... - package_weight = self._fedex_convert_weight(picking.shipping_weight or picking.weight, self.fedex_weight_unit) - packaging = self.fedex_default_package_type_id - - srm.add_package( - package_weight, - mode='rating', - package_code=packaging.shipper_package_code, - package_height=packaging.height, - package_width=packaging.width, - package_length=packaging.packaging_length, - sequence_number=1, - # po_number=po_number, - # dept_number=dept_number, - reference=('%s-%d' % (order_name, 1)), - insurance=insurance_value, - signature_required=signature_required - ) - srm.set_master_package(package_weight, 1) - - - # Commodities for customs declaration (international shipping) - # TODO Intestigate rating if needed... - # if self.fedex_service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'] or is_india: - # total_commodities_amount = 0.0 - # commodity_country_of_manufacture = order.warehouse_id.partner_id.country_id.code - # - # for line in order.order_line.filtered(lambda l: l.product_id.type in ['product', 'consu']): - # commodity_amount = line.price_total / line.product_uom_qty - # total_commodities_amount += (commodity_amount * line.product_uom_qty) - # commodity_description = line.product_id.name - # commodity_number_of_piece = '1' - # commodity_weight_units = self.fedex_weight_unit - # commodity_weight_value = self._fedex_convert_weight(line.product_id.weight * line.product_uom_qty, - # self.fedex_weight_unit) - # commodity_quantity = line.product_uom_qty - # commodity_quantity_units = 'EA' - # # DO NOT FORWARD PORT AFTER 12.0 - # if getattr(line.product_id, 'hs_code', False): - # commodity_harmonized_code = line.product_id.hs_code or '' - # else: - # commodity_harmonized_code = '' - # srm._commodities(_convert_curr_iso_fdx(order_currency.name), commodity_amount, - # commodity_number_of_piece, commodity_weight_units, commodity_weight_value, - # commodity_description, commodity_country_of_manufacture, commodity_quantity, - # commodity_quantity_units, commodity_harmonized_code) - # srm.customs_value(_convert_curr_iso_fdx(order_currency.name), total_commodities_amount, "NON_DOCUMENTS") - # srm.duties_payment(order.warehouse_id.partner_id.country_id.code, superself.fedex_account_number) - - request_list = srm.rate(date_planned=date_planned, multi=True) - result = [] - for request in request_list: - price = 0.0 - warnings = request.get('warnings_message') - if warnings: - _logger.info(warnings) - - if not request.get('errors_message'): - if _convert_curr_iso_fdx(order_currency.name) in request['price']: - price = request['price'][_convert_curr_iso_fdx(order_currency.name)] - else: - _logger.info("Preferred currency has not been found in FedEx response") - company_currency = order.company_id.currency_id - if _convert_curr_iso_fdx(company_currency.name) in request['price']: - amount = request['price'][_convert_curr_iso_fdx(company_currency.name)] - price = company_currency._convert(amount, order_currency, order.company_id, - order.date_order or fields.Date.today()) - else: - amount = request['price']['USD'] - price = company_currency._convert(amount, order_currency, order.company_id, - order.date_order or fields.Date.today()) - else: - result.append({'carrier': self, - 'success': False, - 'price': 0.0, - 'error_message': _('Error:\n%s') % request['errors_message'], - 'warning_message': False, - 'service_code': request['service_code'], - }) - service_code = request['service_code'] - carrier = self.fedex_find_delivery_carrier_for_service(service_code) - if carrier: - date_delivered = request.get('date_delivered', False) - if date_delivered and self.delivery_calendar_id.tz: - tz = pytz.timezone(self.delivery_calendar_id.tz) - date_delivered = tz.localize(date_delivered).astimezone(pytz.utc).replace(tzinfo=None) - result.append({'carrier': carrier, - 'package': package or self.env['stock.quant.package'].browse(), - 'success': True, - 'price': price, - 'error_message': False, - 'transit_days': request.get('transit_days', False), - 'date_delivered': date_delivered, - 'date_planned': date_planned, - 'warning_message': _('Warning:\n%s') % warnings if warnings else False, - 'service_code': request['service_code'], - }) - return result - - def fedex_find_delivery_carrier_for_service(self, service_code): - if self.fedex_service_type == service_code: - return self - # arbitrary decision, lets find the same account number - carrier = self.search([('fedex_account_number', '=', self.fedex_account_number), - ('fedex_service_type', '=', service_code) - ], limit=1) - return carrier - - def fedex_cancel_shipment(self, picking): - # Overriddent to use the correct account numbers for cancelling - request = FedexRequest(self.log_xml, request_type="shipping", prod_environment=self.prod_environment) - superself = self.sudo() - request.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password) - acc_number = superself._get_fedex_account_number(picking=picking) - meter_number = superself._get_fedex_meter_number(picking=picking) - request.client_detail(acc_number, meter_number) - request.transaction_detail(picking.id) - - master_tracking_id = picking.carrier_tracking_ref.split(',')[0] - request.set_deletion_details(master_tracking_id) - result = request.delete_shipment() - - warnings = result.get('warnings_message') - if warnings: - _logger.info(warnings) - - if result.get('delete_success') and not result.get('errors_message'): - picking.message_post(body=_(u'Shipment #%s has been cancelled', master_tracking_id)) - picking.write({'carrier_tracking_ref': '', - 'carrier_price': 0.0}) - else: - raise UserError(result['errors_message']) diff --git a/delivery_fedex_hibou/models/fedex_request.py b/delivery_fedex_hibou/models/fedex_request.py deleted file mode 100644 index 483c26a9..00000000 --- a/delivery_fedex_hibou/models/fedex_request.py +++ /dev/null @@ -1,268 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from zeep.exceptions import Fault -from datetime import datetime -from copy import deepcopy -from odoo.addons.delivery_fedex.models import fedex_request -from odoo.tools import remove_accents - -STATECODE_REQUIRED_COUNTRIES = fedex_request.STATECODE_REQUIRED_COUNTRIES - - -def sanitize_name(name): - if isinstance(name, str): - return name.replace('[', '').replace(']', '') - return 'Unknown' - - -class FedexRequest(fedex_request.FedexRequest): - _transit_days = { - 'ONE_DAYS': 1, - 'ONE_DAY': 1, - 'TWO_DAYS': 2, - 'THREE_DAYS': 3, - 'FOUR_DAYS': 4, - 'FIVE_DAYS': 5, - 'SIX_DAYS': 6, - 'SEVEN_DAYS': 7, - 'EIGHT_DAYS': 8, - 'NINE_DAYS': 9, - 'TEN_DAYS': 10, - } - - _service_transit_days = { - 'FEDEX_2_DAY': 2, - 'FEDEX_2_DAY_AM': 2, - 'FEDEX_3_DAY_FREIGHT': 3, - 'FIRST_OVERNIGHT': 1, - 'PRIORITY_OVERNIGHT': 1, - 'STANDARD_OVERNIGHT': 1, - } - - def set_recipient(self, recipient_partner, attn=None, residential=False): - """ - Adds ATTN: and sanitizes against known 'illegal' common characters in names. - :param recipient_partner: default - :param attn: NEW add to contact name as an ' ATTN: $attn' - :param residential: NEW allow ground home delivery - :return: - """ - Contact = self.factory.Contact() - if recipient_partner.is_company: - Contact.PersonName = '' - Contact.CompanyName = sanitize_name(remove_accents(recipient_partner.name)) - else: - Contact.PersonName = sanitize_name(remove_accents(recipient_partner.name)) - Contact.CompanyName = sanitize_name(remove_accents(recipient_partner.parent_id.name)) or '' - - if attn: - Contact.PersonName = Contact.PersonName + ' ATTN: ' + str(attn) - - Contact.PhoneNumber = recipient_partner.phone or '' - - Address = self.factory.Address() - Address.StreetLines = [remove_accents(recipient_partner.street) or '', remove_accents(recipient_partner.street2) or ''] - Address.City = remove_accents(recipient_partner.city) or '' - if recipient_partner.country_id.code in STATECODE_REQUIRED_COUNTRIES: - Address.StateOrProvinceCode = recipient_partner.state_id.code or '' - else: - Address.StateOrProvinceCode = '' - Address.PostalCode = recipient_partner.zip or '' - Address.CountryCode = recipient_partner.country_id.code or '' - - if residential: - Address.Residential = True - - self.RequestedShipment.Recipient = self.factory.Party() - self.RequestedShipment.Recipient.Contact = Contact - self.RequestedShipment.Recipient.Address = Address - - def add_package(self, weight_value, package_code=False, package_height=0, package_width=0, package_length=0, sequence_number=False, mode='shipping', reference=False, insurance=False, signature_required=False): - # TODO remove in master and change the signature of a public method - return self._add_package(weight_value=weight_value, package_code=package_code, package_height=package_height, package_width=package_width, - package_length=package_length, sequence_number=sequence_number, mode=mode, po_number=False, dept_number=False, reference=reference, insurance=insurance, signature_required=signature_required) - - def _add_package(self, weight_value, package_code=False, package_height=0, package_width=0, package_length=0, sequence_number=False, mode='shipping', po_number=False, dept_number=False, reference=False, insurance=False, signature_required=False): - package = self.factory.RequestedPackageLineItem() - package_weight = self.factory.Weight() - package_weight.Value = weight_value - package_weight.Units = self.RequestedShipment.TotalWeight.Units - - if insurance: - insured = self.factory.Money() - insured.Amount = insurance - # TODO at some point someone might need currency here - insured.Currency = 'USD' - package.InsuredValue = insured - - special_service = self.factory.PackageSpecialServicesRequested() - signature_detail = self.factory.SignatureOptionDetail() - signature_detail.OptionType = 'DIRECT' if signature_required else 'NO_SIGNATURE_REQUIRED' - special_service.SignatureOptionDetail = signature_detail - package.SpecialServicesRequested = special_service - - package.PhysicalPackaging = 'BOX' - if package_code == 'YOUR_PACKAGING': - package.Dimensions = self.factory.Dimensions() - package.Dimensions.Height = package_height - package.Dimensions.Width = package_width - package.Dimensions.Length = package_length - # TODO in master, add unit in product packaging and perform unit conversion - package.Dimensions.Units = "IN" if self.RequestedShipment.TotalWeight.Units == 'LB' else 'CM' - if po_number: - po_reference = self.factory.CustomerReference() - po_reference.CustomerReferenceType = 'P_O_NUMBER' - po_reference.Value = po_number - package.CustomerReferences.append(po_reference) - if dept_number: - dept_reference = self.factory.CustomerReference() - dept_reference.CustomerReferenceType = 'DEPARTMENT_NUMBER' - dept_reference.Value = dept_number - package.CustomerReferences.append(dept_reference) - if reference: - customer_reference = self.factory.CustomerReference() - customer_reference.CustomerReferenceType = 'CUSTOMER_REFERENCE' - customer_reference.Value = reference - package.CustomerReferences.append(customer_reference) - - package.Weight = package_weight - if mode == 'rating': - package.GroupPackageCount = 1 - if sequence_number: - package.SequenceNumber = sequence_number - else: - self.hasOnePackage = True - - if mode == 'rating': - self.RequestedShipment.RequestedPackageLineItems.append(package) - else: - self.RequestedShipment.RequestedPackageLineItems = package - - def shipping_charges_payment(self, shipping_charges_payment_account, third_party=False): - """ - Allow 'shipping_charges_payment_account' to be considered 'third_party' - :param shipping_charges_payment_account: default - :param third_party: NEW add to indicate that the 'shipping_charges_payment_account' is third party. - :return: - """ - self.RequestedShipment.ShippingChargesPayment = self.factory.Payment() - self.RequestedShipment.ShippingChargesPayment.PaymentType = 'SENDER' if not third_party else 'THIRD_PARTY' - Payor = self.factory.Payor() - Payor.ResponsibleParty = self.factory.Party() - Payor.ResponsibleParty.AccountNumber = shipping_charges_payment_account - self.RequestedShipment.ShippingChargesPayment.Payor = Payor - - def shipment_request(self, dropoff_type, service_type, packaging_type, overall_weight_unit, saturday_delivery, ship_timestamp=None): - self.RequestedShipment = self.factory.RequestedShipment() - self.RequestedShipment.SpecialServicesRequested = self.factory.ShipmentSpecialServicesRequested() - self.RequestedShipment.ShipTimestamp = ship_timestamp or datetime.now() - self.RequestedShipment.DropoffType = dropoff_type - self.RequestedShipment.ServiceType = service_type - self.RequestedShipment.PackagingType = packaging_type - # Resuest estimation of duties and taxes for international shipping - if service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY']: - self.RequestedShipment.EdtRequestType = 'ALL' - else: - self.RequestedShipment.EdtRequestType = 'NONE' - self.RequestedShipment.PackageCount = 0 - self.RequestedShipment.TotalWeight = self.factory.Weight() - self.RequestedShipment.TotalWeight.Units = overall_weight_unit - self.RequestedShipment.TotalWeight.Value = 0 - self.listCommodities = [] - if saturday_delivery: - timestamp_day = self.RequestedShipment.ShipTimestamp.strftime("%A") - if (service_type == 'FEDEX_2_DAY' and timestamp_day == 'Thursday') or (service_type in ['PRIORITY_OVERNIGHT', 'FIRST_OVERNIGHT', 'INTERNATIONAL_PRIORITY'] and timestamp_day == 'Friday'): - self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append('SATURDAY_DELIVERY') - - # Rating stuff - - def rate(self, date_planned=None, multi=False): - """ - Response will contain 'transit_days' key with number of days. - :param date_planned: Planned Outgoing shipment. Used to have FedEx tell us how long it will take for the package to arrive. - :return: - """ - if multi: - multi_result = [] - if date_planned: - self.RequestedShipment.ShipTimestamp = date_planned - - formatted_response = {'price': {}} - del self.ClientDetail['Region'] - if self.hasCommodities: - self.RequestedShipment.CustomsClearanceDetail.Commodities = self.listCommodities - - try: - self.response = self.client.service.getRates(WebAuthenticationDetail=self.WebAuthenticationDetail, - ClientDetail=self.ClientDetail, - TransactionDetail=self.TransactionDetail, - Version=self.VersionId, - RequestedShipment=self.RequestedShipment, - ReturnTransitAndCommit=True) # New ReturnTransitAndCommit for CommitDetails in response - if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'): - if not getattr(self.response, "RateReplyDetails", False): - raise Exception("No rating found") - if not multi: - for rating in self.response.RateReplyDetails[0].RatedShipmentDetails: - formatted_response['price'][rating.ShipmentRateDetail.TotalNetFedExCharge.Currency] = float(rating.ShipmentRateDetail.TotalNetFedExCharge.Amount) - if len(self.response.RateReplyDetails[0].RatedShipmentDetails) == 1: - if 'CurrencyExchangeRate' in self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail and self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail['CurrencyExchangeRate']: - formatted_response['price'][self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.FromCurrency] = float(self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.TotalNetFedExCharge.Amount) / float(self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.Rate) - - # Hibou Delivery Planning - if hasattr(self.response.RateReplyDetails[0], 'DeliveryTimestamp') and self.response.RateReplyDetails[0].DeliveryTimestamp: - formatted_response['date_delivered'] = self.response.RateReplyDetails[0].DeliveryTimestamp - if hasattr(self.response.RateReplyDetails[0].CommitDetails[0], 'TransitTime'): - transit_days = self.response.RateReplyDetails[0].CommitDetails[0].TransitTime - transit_days = self._transit_days.get(transit_days, 0) - formatted_response['transit_days'] = transit_days - elif hasattr(self.response.RateReplyDetails[0], 'CommitDetails') and hasattr(self.response.RateReplyDetails[0].CommitDetails[0], 'CommitTimestamp'): - formatted_response['date_delivered'] = self.response.RateReplyDetails[0].CommitDetails[0].CommitTimestamp - formatted_response['transit_days'] = self._service_transit_days.get(self.response.RateReplyDetails[0].CommitDetails[0].ServiceType, 0) - elif hasattr(self.response.RateReplyDetails[0], 'CommitDetails') and hasattr(self.response.RateReplyDetails[0].CommitDetails[0], 'TransitTime'): - transit_days = self.response.RateReplyDetails[0].CommitDetails[0].TransitTime - transit_days = self._transit_days.get(transit_days, 0) - formatted_response['transit_days'] = transit_days - else: - for rate_reply_detail in self.response.RateReplyDetails: - res = deepcopy(formatted_response) - res['service_code'] = rate_reply_detail.ServiceType - for rating in rate_reply_detail.RatedShipmentDetails: - res['price'][rating.ShipmentRateDetail.TotalNetFedExCharge.Currency] = float(rating.ShipmentRateDetail.TotalNetFedExCharge.Amount) - if len(rate_reply_detail.RatedShipmentDetails) == 1: - if 'CurrencyExchangeRate' in rate_reply_detail.RatedShipmentDetails[0].ShipmentRateDetail and rate_reply_detail.RatedShipmentDetails[0].ShipmentRateDetail['CurrencyExchangeRate']: - res['price'][rate_reply_detail.RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.FromCurrency] = float(rate_reply_detail.RatedShipmentDetails[0].ShipmentRateDetail.TotalNetFedExCharge.Amount) / float(rate_reply_detail.RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.Rate) - # Hibou Delivery Planning - if hasattr(rate_reply_detail, 'DeliveryTimestamp') and rate_reply_detail.DeliveryTimestamp: - res['date_delivered'] = rate_reply_detail.DeliveryTimestamp - res['transit_days'] = self._service_transit_days.get(rate_reply_detail.ServiceType, 0) - if not res['transit_days'] and hasattr(rate_reply_detail.CommitDetails[0], 'TransitTime'): - transit_days = rate_reply_detail.CommitDetails[0].TransitTime - transit_days = self._transit_days.get(transit_days, 0) - res['transit_days'] = transit_days - elif hasattr(rate_reply_detail, 'CommitDetails') and hasattr(rate_reply_detail.CommitDetails[0], 'CommitTimestamp'): - res['date_delivered'] = rate_reply_detail.CommitDetails[0].CommitTimestamp - res['transit_days'] = self._service_transit_days.get(rate_reply_detail.ServiceType, 0) - elif hasattr(rate_reply_detail, 'CommitDetails') and hasattr(rate_reply_detail.CommitDetails[0], 'TransitTime'): - transit_days = rate_reply_detail.CommitDetails[0].TransitTime - transit_days = self._transit_days.get(transit_days, 0) - res['transit_days'] = transit_days - multi_result.append(res) - else: - errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')]) - formatted_response['errors_message'] = errors_message - - if any([n.Severity == 'WARNING' for n in self.response.Notifications]): - warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING']) - formatted_response['warnings_message'] = warnings_message - - except Fault as fault: - formatted_response['errors_message'] = fault - except IOError: - formatted_response['errors_message'] = "Fedex Server Not Found" - except Exception as e: - formatted_response['errors_message'] = e.args[0] - - if multi: - return multi_result - return formatted_response diff --git a/delivery_fedex_hibou/models/stock.py b/delivery_fedex_hibou/models/stock.py deleted file mode 100644 index 58726f6f..00000000 --- a/delivery_fedex_hibou/models/stock.py +++ /dev/null @@ -1,10 +0,0 @@ -# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. - -from odoo import api, fields, models - - -class StockWarehouse(models.Model): - _inherit = 'stock.warehouse' - - fedex_account_number = fields.Char(string='FedEx Account Number') - fedex_meter_number = fields.Char(string='FedEx Meter Number') diff --git a/delivery_fedex_hibou/views/stock_views.xml b/delivery_fedex_hibou/views/stock_views.xml deleted file mode 100644 index 8df21336..00000000 --- a/delivery_fedex_hibou/views/stock_views.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - stock.warehouse - stock.warehouse - - - - - - - - - \ No newline at end of file