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)