Shipping plays a crucial role in the success of any e-commerce business. By integrating a shipping method with Odoo 16, you can streamline your shipping processes and provide a seamless experience for your customers.
In this blog, we will guide you through the basic steps to integrate a shipping method with Odoo 16, enabling you to efficiently handle order shipments and enhance customer satisfaction.
Choose a Compatible Shipping Method
Before starting the integration process, you need to decide on a shipping method that aligns with your business requirements. Odoo 16 supports various shipping carriers and methods, such as UPS, FedEx, DHL, and local postal services. Research the available options and choose a shipping method that offers reliable service in your target regions.
Obtain Shipping Method Credentials
To integrate your chosen shipping method with Odoo 16, you will need specific credentials or API keys provided by the shipping carrier. These credentials are necessary for Odoo to communicate with the shipping carrier's system and retrieve real-time shipping rates, create shipping labels, and track shipments. Contact the shipping carrier to acquire the required credentials.
Basic Steps to follow while coding:
Add a new shipping method to the 'delivery.carrier' model, we need to inherit the model and extend its functionality.
Consider the following code snippet as an example:
class DeliverCarrier(models.Model):
""" Class representing delivery carriers. """
_inherit = 'delivery.carrier'
delivery_type = fields.Selection(selection_add=[
(‘carrier_name’, ‘Carrier Name’)
], ondelete={carrier_name: lambda recs: recs.write({'delivery_type': 'fixed', 'fixed_price': 0})})
The class DeliverCarrier(models.Model) line defines a new class named 'DeliverCarrier' that extends the 'delivery.carrier' mode
The delivery_type field is a selection field that determines the type of delivery method. In this case, we add a new option named “Carrier Name” with the value “carrier_name”.
The ondelete attribute defines the behavior when the new option is deleted. In this example, we specify that when the 'Shipping' option is deleted, it should update the delivery type to 'fixed' and set the fixed price to 0. This ensures that any records associated with the deleted shipping method are appropriately handled.
Import the file to __init__.py
List the shipping method inside the view.
To list out the shipping method inside the shipping methods we need to create a data file with the service product.
<?xml version='1.0' encoding='utf-8'?>
<data>
<record id="product_product_delivery_carrier_name" model="product.product">
<field name="name">Delivery Product</field>
<field name="default_code">Code</field>
<field name="type">service</field>
<field name="categ_id" ref="delivery.product_category_deliveries"/>
<field name="sale_ok" eval="False"/>
<field name="purchase_ok" eval="False"/>
<field name="list_price">0.0</field>
<field name="invoice_policy">order</field>
</record>
<record id="delivery_carrier_carrier_name" model="delivery.carrier">
<field name="name">Carrier Name</field>
<field name="product_id" ref="module_name.product_product_delivery_carrier_name"/> //this is the id of the created delivery product
<field name="delivery_type">carrier_name</field>
</record>
</data>
<record id="product_product_delivery_carrier_name" model="product.product">: This record defines a new product with the ID "product_product_delivery_carrier_name" and the model "product.product." It represents the delivery product that will be associated with the carrier.
Add file inside __manifest__.py
<record id="delivery_carrier_carrier_name" model="delivery.carrier">: This record defines a new delivery carrier with the ID "delivery_carrier_carrier_name" and the model "delivery.carrier."
It will show the Delivery Method as follows.
Get the Rate of Shipment
For fetching the rate for the shipments we need to write a function that retrieves rates for a quotation or sales order and returns the rate information as a dictionary: the function is written inside the file ‘delivery.carrier’ file.
def carrier_name_rate_shipment(self, order):
""" Return the rates for a quotation or sales order.
:param order: The order for which to retrieve rates.
:type order: odoo.models.Model
:return: The rate information.
:rtype: dict
"""
# Your code goes here to fetch the rates for the shipment
# Example code to calculate rates based on weight
weight = order.get_weight() # Assuming a method to get the total weight of the order
rate = weight * 0.5 # Assuming a rate calculation formula based on weight
# Example code to construct the rate information dictionary
rate_info = {
'carrier_name': 'Carrier Name',
'service_name': 'Standard Shipping',
'currency': 'USD',
'total_price': rate,
}
return rate_info
Send Shipment
For sending shipment we need to write a function that sends the package to the service provider and returns a list of dictionaries containing the price and tracking number for each picking:
Eg:
def carrier_name_send_shipping(self, pickings):
"""Send the package to the service provider.
:param pickings: A recordset of pickings.
:return: A list of dictionaries (one per picking) containing:
- 'exact_price': The price of the shipment.
- 'tracking_number': The tracking number of the shipment.
:rtype: list
"""
shipping_results = []
for picking in pickings:
# Your code goes here to send the package to the service provider
# Example code to calculate the exact price and obtain a tracking number
exact_price = 15.99 # Assuming a constant exact price for simplicity
tracking_number = 'TRACK123' # Assuming a generated tracking number
# Example code to construct the dictionary for each picking
result = {
'exact_price': exact_price,
'tracking_number': tracking_number,
}
shipping_results.append(result)
return shipping_results
Get Tracking Link
For getting the tracking link we need to write a function as follows.
def carrier_name_get_tracking_link(self, picking):
"""Ask the tracking link to the service provider.
:param picking: A record of stock.picking.
:return: A URL containing the tracking link or False.
:rtype: str or False
"""
# Your code goes here to request the tracking link from the service provider
# Example code to obtain the tracking link
tracking_link = 'https://example.com/tracking/123' # Assuming a generated tracking link
if tracking_link:
return tracking_link
else:
return False
In the above example, the carrier_name_get_tracking_link function takes a picking parameter, which represents a record of stock.picking for which we want to request the tracking link.
Inside the function, you can customize the code to communicate with the service provider's API or any other relevant method to obtain the tracking link for the given picking.
In this example, we assume that the tracking link is available and set it as 'https://example.com/tracking/123' for demonstration purposes. You should replace this placeholder with the actual logic to request and retrieve the tracking link from your service provider.
If the tracking link is obtained successfully, it is returned as a string. Otherwise, if the tracking link is not available, the function returns False.
Remember to adapt the code to match your specific service provider's integration and update the logic to obtain the tracking link according to your provider's API or system.
Cancel Shipment
Following function used to cancel the shipments.
def carrier_name_cancel_shipment(self, pickings):
''' Cancel a shipment
:param pickings: A recordset of pickings
'''
'In the above example, the cancel_shipment function takes a recordset of pickings as the pickings parameter. Each picking represents a shipment that needs to be canceled.
Inside the function, you can customize the code to handle the cancellation of the shipment based on your business requirements and the structure of the pickings recordset.