From c92632daa8cb48ec200c77c6bd84a4917e8e15a7 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:08:10 +0100 Subject: [PATCH] feat!: remove packlink They don't have API docs available and, according to their support, don't support API integrations anymore. The API requests always return "Bad Request" without any possibility to fix them. --- README.md | 6 +- .../doctype/packlink/__init__.py | 0 .../doctype/packlink/packlink.js | 8 - .../doctype/packlink/packlink.json | 54 ---- .../doctype/packlink/packlink.py | 232 ------------------ .../doctype/packlink/test_packlink.py | 9 - erpnext_shipping/erpnext_shipping/shipping.py | 38 --- 7 files changed, 2 insertions(+), 345 deletions(-) delete mode 100644 erpnext_shipping/erpnext_shipping/doctype/packlink/__init__.py delete mode 100644 erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.js delete mode 100644 erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.json delete mode 100644 erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.py delete mode 100644 erpnext_shipping/erpnext_shipping/doctype/packlink/test_packlink.py diff --git a/README.md b/README.md index 5ca7169..88030a8 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ ## ERPNext Shipping A Shipping Integration for ERPNext with various platforms. Platforms integrated in this app are: -- [Packlink](https://www.packlink.com/en-GB/) + - [LetMeShip](https://www.letmeship.com/en/) - [SendCloud](https://www.sendcloud.com/home-new/) ## Features -- Creation of shipment to a carrier service (e.g. FedEx, UPS) via LetMeShip, Packlink, and SendCloud. +- Creation of shipment to a carrier service (e.g. FedEx, UPS) via LetMeShip and SendCloud. - Compare shipping rates. - Printing the shipping label is also made available within the Shipment doctype. - Templates for the parcel dimensions. @@ -27,8 +27,6 @@ For the compare shipping rates feature to work as expected, you need to generate ![LetMeShip 2020-08-05 09-54-28](https://user-images.githubusercontent.com/17470909/89377411-500c4f80-d724-11ea-8fe5-b11fec2a5c27.png) -![Packlink 2020-08-05 09-53-47](https://user-images.githubusercontent.com/17470909/89377423-56023080-d724-11ea-8396-fb9f60a0d581.png) - ### Fetch Shipping Rates ![core2](https://user-images.githubusercontent.com/17470909/89377460-70d4a500-d724-11ea-8550-a2813b936651.gif) diff --git a/erpnext_shipping/erpnext_shipping/doctype/packlink/__init__.py b/erpnext_shipping/erpnext_shipping/doctype/packlink/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.js b/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.js deleted file mode 100644 index 376d2fc..0000000 --- a/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2020, Frappe and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Packlink', { - // refresh: function(frm) { - - // } -}); diff --git a/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.json b/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.json deleted file mode 100644 index 85cbfea..0000000 --- a/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "actions": [], - "creation": "2020-07-22 10:45:17.672439", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "enabled", - "api_key", - "information" - ], - "fields": [ - { - "default": "0", - "fieldname": "enabled", - "fieldtype": "Check", - "label": "Enabled" - }, - { - "fieldname": "api_key", - "fieldtype": "Password", - "label": "API Key", - "read_only_depends_on": "eval:doc.enabled == 0" - }, - { - "fieldname": "information", - "fieldtype": "HTML", - "options": "
For steps to generate the API key, click here
" - } - ], - "issingle": 1, - "links": [], - "modified": "2020-12-16 15:30:27.436717", - "modified_by": "Administrator", - "module": "ERPNext Shipping", - "name": "Packlink", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.py b/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.py deleted file mode 100644 index 58fc48f..0000000 --- a/erpnext_shipping/erpnext_shipping/doctype/packlink/packlink.py +++ /dev/null @@ -1,232 +0,0 @@ -# Copyright (c) 2020, Frappe Technologies and contributors -# For license information, please see license.txt - -import json - -import frappe -import requests -from frappe import _ -from frappe.model.document import Document -from frappe.utils.password import get_decrypted_password - -from erpnext_shipping.erpnext_shipping.utils import show_error_alert - -PACKLINK_PROVIDER = "Packlink" - - -class Packlink(Document): - pass - - -class PackLinkUtils: - def __init__(self): - self.api_key = get_decrypted_password("Packlink", "Packlink", "api_key", raise_exception=False) - self.enabled = frappe.db.get_single_value("Packlink", "enabled") - - if not self.enabled: - link = frappe.utils.get_link_to_form("Packlink", "Packlink", frappe.bold("Packlink Settings")) - frappe.throw(_(f"Please enable Packlink Integration in {link}"), title=_("Mandatory")) - - def get_available_services(self, pickup_address, delivery_address, parcels, pickup_date): - # Retrieve rates at PackLink from specification stated. - parcel_list = self.get_parcel_list(parcels) - shipment_parcel_params = self.get_formatted_parcel_params(parcel_list) - url = self.get_formatted_request_url(pickup_address, delivery_address, shipment_parcel_params) - - if not self.api_key or not self.enabled: - return [] - - try: - responses = requests.get(url, headers={"Authorization": self.api_key}) - responses_dict = json.loads(responses.text) - # If an error occured on the api. Show the error message - if "messages" in responses_dict: - error_message = str(responses_dict["messages"][0]["message"]) - frappe.throw(error_message, title=_("PackLink")) - - available_services = [] - for response in responses_dict: - # display services only if available on pickup date - if self.parse_pickup_date(pickup_date) in response["available_dates"].keys(): - available_service = self.get_service_dict(response) - available_services.append(available_service) - - if responses_dict and not available_services: - # got a response but no service available for given date - frappe.throw(_("No Services available for {0}").format(pickup_date), title=_("PackLink")) - - return available_services - except Exception: - show_error_alert("fetching Packlink prices") - - return [] - - def create_shipment( - self, - pickup_address, - delivery_company_name, - delivery_address, - shipment_parcel, - description_of_content, - pickup_date, - value_of_goods, - pickup_contact, - delivery_contact, - service_info, - ): - # Create a transaction at PackLink - data = { - "additional_data": { - "postal_zone_id_from": "", - "postal_zone_name_from": pickup_address.country, - "postal_zone_id_to": "", - "postal_zone_name_to": delivery_address.country, - }, - "collection_date": self.parse_pickup_date(pickup_date), - "collection_time": "", - "content": description_of_content, - "contentvalue": value_of_goods, - "content_second_hand": False, - "from": self.get_shipment_address_contact_dict(pickup_address, pickup_contact), - "insurance": {"amount": 0, "insurance_selected": False}, - "price": {}, - "packages": self.get_parcel_list(json.loads(shipment_parcel)), - "service_id": service_info["service_id"], - "to": self.get_shipment_address_contact_dict( - delivery_address, delivery_contact, company_name=delivery_company_name - ), - } - - url = "https://api.packlink.com/v1/shipments" - headers = {"Authorization": self.api_key, "Content-Type": "application/json"} - try: - response_data = requests.post(url, json=data, headers=headers) - response_data = json.loads(response_data.text) - if "reference" in response_data: - return { - "service_provider": PACKLINK_PROVIDER, - "shipment_id": response_data["reference"], - "carrier": service_info["carrier"], - "carrier_service": service_info["service_name"], - "shipment_amount": service_info["actual_price"], - "awb_number": "", - } - except Exception: - show_error_alert("creating Packlink Shipment") - - def get_label(self, shipment_id): - # Retrieve shipment label from PackLink - headers = {"Authorization": self.api_key, "Content-Type": "application/json"} - try: - shipment_label_response = requests.get( - f"https://api.packlink.com/v1/shipments/{shipment_id}/labels", headers=headers - ) - shipment_label = json.loads(shipment_label_response.text) - if shipment_label: - return shipment_label - else: - message = _( - "Please make sure Shipment (ID: {0}), exists and is a complete Shipment on Packlink." - ).format(shipment_id) - frappe.msgprint(msg=_(message), title=_("Label Not Found")) - except Exception: - show_error_alert("printing Packlink Label") - return [] - - def get_tracking_data(self, shipment_id): - # Get Packlink Tracking Info - from erpnext_shipping.erpnext_shipping.utils import get_tracking_url - - headers = {"Authorization": self.api_key, "Content-Type": "application/json"} - try: - url = f"https://api.packlink.com/v1/shipments/{shipment_id}" - tracking_data_response = requests.get(url, headers=headers) - tracking_data = json.loads(tracking_data_response.text) - if "trackings" in tracking_data: - tracking_status = "In Progress" - if tracking_data["state"] == "DELIVERED": - tracking_status = "Delivered" - if tracking_data["state"] == "RETURNED": - tracking_status = "Returned" - if tracking_data["state"] == "LOST": - tracking_status = "Lost" - awb_number = None if not tracking_data["trackings"] else tracking_data["trackings"][0] - tracking_url = get_tracking_url(carrier=tracking_data["carrier"], tracking_number=awb_number) - return { - "awb_number": awb_number, - "tracking_status": tracking_status, - "tracking_status_info": tracking_data["state"], - "tracking_url": tracking_url, - } - except Exception: - show_error_alert("updating Packlink Shipment") - return [] - - def get_formatted_request_url(self, pickup_address, delivery_address, shipment_parcel_params): - """Returns formatted request URL for Packlink.""" - url = "https://api.packlink.com/v1/services?from[country]={from_country_code}&from[zip]={from_zip}&to[country]={to_country_code}&to[zip]={to_zip}&{shipment_parcel_params}sortBy=totalPrice&source=PRO".format( - from_country_code=pickup_address.country_code, - from_zip=pickup_address.pincode, - to_country_code=delivery_address.country_code, - to_zip=delivery_address.pincode, - shipment_parcel_params=shipment_parcel_params, - ) - return url - - def get_formatted_parcel_params(self, parcel_list): - """Returns formatted parcel params for Packlink URL.""" - shipment_parcel_params = "" - for index, parcel in enumerate(parcel_list): - shipment_parcel_params += "packages[{index}][height]={height}&packages[{index}][length]={length}&packages[{index}][weight]={weight}&packages[{index}][width]={width}&".format( - index=index, - height=parcel["height"], - length=parcel["length"], - weight=parcel["weight"], - width=parcel["width"], - ) - return shipment_parcel_params - - def get_service_dict(self, response): - """Returns a dictionary with service info.""" - available_service = frappe._dict() - available_service.service_provider = PACKLINK_PROVIDER - available_service.carrier = response["carrier_name"] - available_service.carrier_name = response["name"] - available_service.service_name = "" - available_service.is_preferred = 0 - available_service.total_price = response["price"]["base_price"] - available_service.actual_price = response["price"]["total_price"] - available_service.service_id = response["id"] - available_service.available_dates = response["available_dates"] - return available_service - - def get_shipment_address_contact_dict(self, address, contact, company_name=None): - """Returns a dict with Address and Contact Info for Packlink Payload.""" - return { - "city": address.city, - "company": company_name or address.address_title, - "country": address.country_code, - "email": contact.email_id, - "name": contact.first_name, - "phone": contact.phone, - "state": address.country, - "street1": address.address_line1, - "street2": address.address_line2, - "surname": contact.last_name, - "zip_code": address.pincode, - } - - def get_parcel_list(self, shipment_parcel): - parcel_list = [] - for parcel in shipment_parcel: - for count in range(parcel.get("count")): - formatted_parcel = {} - formatted_parcel["height"] = parcel.get("height") - formatted_parcel["width"] = parcel.get("width") - formatted_parcel["length"] = parcel.get("length") - formatted_parcel["weight"] = parcel.get("weight") - parcel_list.append(formatted_parcel) - return parcel_list - - def parse_pickup_date(self, pickup_date): - return pickup_date.replace("-", "/") diff --git a/erpnext_shipping/erpnext_shipping/doctype/packlink/test_packlink.py b/erpnext_shipping/erpnext_shipping/doctype/packlink/test_packlink.py deleted file mode 100644 index 4f599c6..0000000 --- a/erpnext_shipping/erpnext_shipping/doctype/packlink/test_packlink.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2020, Frappe and Contributors -# See license.txt - -# import frappe -import unittest - - -class TestPacklink(unittest.TestCase): - pass diff --git a/erpnext_shipping/erpnext_shipping/shipping.py b/erpnext_shipping/erpnext_shipping/shipping.py index b507ea2..b80d23a 100644 --- a/erpnext_shipping/erpnext_shipping/shipping.py +++ b/erpnext_shipping/erpnext_shipping/shipping.py @@ -4,10 +4,8 @@ import frappe from erpnext.stock.doctype.shipment.shipment import get_company_contact -from six import string_types from erpnext_shipping.erpnext_shipping.doctype.letmeship.letmeship import LETMESHIP_PROVIDER, LetMeShipUtils -from erpnext_shipping.erpnext_shipping.doctype.packlink.packlink import PACKLINK_PROVIDER, PackLinkUtils from erpnext_shipping.erpnext_shipping.doctype.sendcloud.sendcloud import SENDCLOUD_PROVIDER, SendCloudUtils from erpnext_shipping.erpnext_shipping.utils import ( get_address, @@ -32,7 +30,6 @@ def fetch_shipping_rates( # Return Shipping Rates for the various Shipping Providers shipment_prices = [] letmeship_enabled = frappe.db.get_single_value("LetMeShip", "enabled") - packlink_enabled = frappe.db.get_single_value("Packlink", "enabled") sendcloud_enabled = frappe.db.get_single_value("SendCloud", "enabled") pickup_address = get_address(pickup_address_name) delivery_address = get_address(delivery_address_name) @@ -71,20 +68,6 @@ def fetch_shipping_rates( letmeship_prices = match_parcel_service_type_carrier(letmeship_prices, ["carrier", "carrier_name"]) shipment_prices = shipment_prices + letmeship_prices - if packlink_enabled: - packlink = PackLinkUtils() - packlink_prices = ( - packlink.get_available_services( - pickup_address=pickup_address, - delivery_address=delivery_address, - parcels=parcels, - pickup_date=pickup_date, - ) - or [] - ) - packlink_prices = match_parcel_service_type_carrier(packlink_prices, ["carrier_name", "carrier"]) - shipment_prices = shipment_prices + packlink_prices - if sendcloud_enabled and pickup_from_type == "Company": sendcloud = SendCloudUtils() sendcloud_prices = ( @@ -153,21 +136,6 @@ def create_shipment( service_info=service_info, ) - if service_info["service_provider"] == PACKLINK_PROVIDER: - packlink = PackLinkUtils() - shipment_info = packlink.create_shipment( - pickup_address=pickup_address, - delivery_company_name=delivery_company_name, - delivery_address=delivery_address, - shipment_parcel=shipment_parcel, - description_of_content=description_of_content, - pickup_date=pickup_date, - value_of_goods=value_of_goods, - pickup_contact=pickup_contact, - delivery_contact=delivery_contact, - service_info=service_info, - ) - if service_info["service_provider"] == SENDCLOUD_PROVIDER: sendcloud = SendCloudUtils() shipment_info = sendcloud.create_shipment( @@ -221,9 +189,6 @@ def print_shipping_label(shipment: str): if service_provider == LETMESHIP_PROVIDER: letmeship = LetMeShipUtils() shipping_label = letmeship.get_label(shipment_id) - elif service_provider == PACKLINK_PROVIDER: - packlink = PackLinkUtils() - shipping_label = packlink.get_label(shipment_id) elif service_provider == SENDCLOUD_PROVIDER: sendcloud = SendCloudUtils() shipping_label = [] @@ -261,9 +226,6 @@ def update_tracking(shipment, service_provider, shipment_id, delivery_notes=None if service_provider == LETMESHIP_PROVIDER: letmeship = LetMeShipUtils() tracking_data = letmeship.get_tracking_data(shipment_id) - elif service_provider == PACKLINK_PROVIDER: - packlink = PackLinkUtils() - tracking_data = packlink.get_tracking_data(shipment_id) elif service_provider == SENDCLOUD_PROVIDER: sendcloud = SendCloudUtils() tracking_data = sendcloud.get_tracking_data(shipment_id)