chore: remove packlink, letmeship, and sendcloud files
This commit is contained in:
parent
000494f548
commit
ac3c1f1493
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('LetMeShip', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -1,55 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-07-23 10:55:19.669830",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"enabled",
|
||||
"api_id",
|
||||
"api_password"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "api_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "API ID",
|
||||
"read_only_depends_on": "eval:doc.enabled == 0"
|
||||
},
|
||||
{
|
||||
"fieldname": "api_password",
|
||||
"fieldtype": "Password",
|
||||
"label": "API Password",
|
||||
"read_only_depends_on": "eval:doc.enabled == 0"
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-21 10:28:37.607717",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "LetMeShip",
|
||||
"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
|
||||
}
|
@ -1,386 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import requests
|
||||
import frappe
|
||||
import json
|
||||
import re
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from erpnext.erpnext_integrations.utils import get_tracking_url
|
||||
|
||||
LETMESHIP_PROVIDER = 'LetMeShip'
|
||||
|
||||
class LetMeShip(Document):
|
||||
pass
|
||||
|
||||
def get_letmeship_available_services(delivery_to_type, pickup_address,
|
||||
delivery_address, shipment_parcel, description_of_content, pickup_date,
|
||||
value_of_goods, pickup_contact=None, delivery_contact=None):
|
||||
# Retrieve rates at LetMeShip from specification stated.
|
||||
api_id, api_password, enabled = frappe.db.get_value('LetMeShip', 'LetMeShip', ['enabled', 'api_password', 'api_id'])
|
||||
if not enabled or not api_id or not api_password:
|
||||
return []
|
||||
|
||||
set_letmeship_specific_fields(pickup_contact, delivery_contact)
|
||||
|
||||
# LetMeShip have limit of 30 characters for Company field
|
||||
if len(pickup_address.address_title) > 30:
|
||||
pickup_address.address_title = pickup_address.address_title[:30]
|
||||
if len(delivery_address.address_title) > 30:
|
||||
delivery_address.address_title = delivery_address.address_title[:30]
|
||||
parcel_list = get_parcel_list(json.loads(shipment_parcel), description_of_content)
|
||||
|
||||
url = 'https://api.letmeship.com/v1/available'
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Access-Control-Allow-Origin': 'string'
|
||||
}
|
||||
payload = generate_payload(
|
||||
pickup_address=pickup_address,
|
||||
pickup_contact=pickup_contact,
|
||||
delivery_address=delivery_address,
|
||||
delivery_contact=delivery_contact,
|
||||
description_of_content=description_of_content,
|
||||
value_of_goods=value_of_goods,
|
||||
parcel_list=parcel_list,
|
||||
pickup_date=pickup_date
|
||||
)
|
||||
try:
|
||||
available_services = []
|
||||
response_data = requests.post(
|
||||
url=url,
|
||||
auth=(api_id, api_password),
|
||||
headers=headers,
|
||||
data=json.dumps(payload)
|
||||
)
|
||||
response_data = json.loads(response_data.text)
|
||||
if 'serviceList' in response_data:
|
||||
for response in response_data['serviceList']:
|
||||
available_service = frappe._dict()
|
||||
basic_info = response['baseServiceDetails']
|
||||
price_info = basic_info['priceInfo']
|
||||
available_service.service_provider = LETMESHIP_PROVIDER
|
||||
available_service.id = basic_info['id']
|
||||
available_service.carrier = basic_info['carrier']
|
||||
available_service.carrier_name = basic_info['name']
|
||||
available_service.service_name = ''
|
||||
available_service.is_preferred = 0
|
||||
available_service.real_weight = price_info['realWeight']
|
||||
available_service.total_price = price_info['netPrice']
|
||||
available_service.price_info = price_info
|
||||
available_services.append(available_service)
|
||||
return available_services
|
||||
else:
|
||||
frappe.throw(
|
||||
_('Error occurred while fetching LetMeShip prices: {0}')
|
||||
.format(response_data['message'])
|
||||
)
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(
|
||||
_('Error occurred while fetching LetMeShip Prices: {0}')
|
||||
.format(str(exc)),
|
||||
indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
return []
|
||||
|
||||
|
||||
def create_letmeship_shipment(pickup_address, delivery_address, shipment_parcel, description_of_content,
|
||||
pickup_date, value_of_goods, service_info, shipment_notific_email, tracking_notific_email,
|
||||
pickup_contact=None, delivery_contact=None):
|
||||
# Create a transaction at LetMeShip
|
||||
# LetMeShip have limit of 30 characters for Company field
|
||||
api_id, api_password, enabled = frappe.db.get_value('LetMeShip', 'LetMeShip', ['enabled', 'api_password', 'api_id'])
|
||||
if not enabled or not api_id or not api_password:
|
||||
return []
|
||||
|
||||
set_letmeship_specific_fields(pickup_contact, delivery_contact)
|
||||
|
||||
if len(pickup_address.address_title) > 30:
|
||||
pickup_address.address_title = pickup_address.address_title[:30]
|
||||
if len(delivery_address.address_title) > 30:
|
||||
delivery_address.address_title = delivery_address.address_title[:30]
|
||||
|
||||
parcel_list = get_parcel_list(json.loads(shipment_parcel), description_of_content)
|
||||
url = 'https://api.letmeship.com/v1/shipments'
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Access-Control-Allow-Origin': 'string'
|
||||
}
|
||||
payload = generate_payload(
|
||||
pickup_address=pickup_address,
|
||||
pickup_contact=pickup_contact,
|
||||
delivery_address=delivery_address,
|
||||
delivery_contact=delivery_contact,
|
||||
description_of_content=description_of_content,
|
||||
value_of_goods=value_of_goods,
|
||||
parcel_list=parcel_list,
|
||||
pickup_date=pickup_date,
|
||||
service_info=service_info,
|
||||
tracking_notific_email=tracking_notific_email,
|
||||
shipment_notific_email=shipment_notific_email
|
||||
)
|
||||
try:
|
||||
response_data = requests.post(
|
||||
url=url,
|
||||
auth=(api_id, api_password),
|
||||
headers=headers,
|
||||
data=json.dumps(payload)
|
||||
)
|
||||
response_data = json.loads(response_data.text)
|
||||
if 'shipmentId' in response_data:
|
||||
shipment_amount = response_data['service']['priceInfo']['totalPrice']
|
||||
awb_number = ''
|
||||
url = 'https://api.letmeship.com/v1/shipments/{id}'.format(id=response_data['shipmentId'])
|
||||
tracking_response = requests.get(url, auth=(api_id, api_password),headers=headers)
|
||||
tracking_response_data = json.loads(tracking_response.text)
|
||||
if 'trackingData' in tracking_response_data:
|
||||
for parcel in tracking_response_data['trackingData']['parcelList']:
|
||||
if 'awbNumber' in parcel:
|
||||
awb_number = parcel['awbNumber']
|
||||
return {
|
||||
'service_provider': LETMESHIP_PROVIDER,
|
||||
'shipment_id': response_data['shipmentId'],
|
||||
'carrier': service_info['carrier'],
|
||||
'carrier_service': service_info['service_name'],
|
||||
'shipment_amount': shipment_amount,
|
||||
'awb_number': awb_number,
|
||||
}
|
||||
elif 'message' in response_data:
|
||||
frappe.throw(
|
||||
_('Error occurred while creating Shipment: {0}')
|
||||
.format(response_data['message'])
|
||||
)
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(
|
||||
_('Error occurred while creating Shipment: {0}')
|
||||
.format(str(exc)),
|
||||
indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
|
||||
def generate_payload(
|
||||
pickup_address,
|
||||
pickup_contact,
|
||||
delivery_address,
|
||||
delivery_contact,
|
||||
description_of_content,
|
||||
value_of_goods,
|
||||
parcel_list,
|
||||
pickup_date,
|
||||
service_info=None,
|
||||
tracking_notific_email=None,
|
||||
shipment_notific_email=None
|
||||
):
|
||||
payload = {
|
||||
'pickupInfo': {
|
||||
'address': {
|
||||
'countryCode': pickup_address.country_code,
|
||||
'zip': pickup_address.pincode,
|
||||
'city': pickup_address.city,
|
||||
'street': pickup_address.address_line1,
|
||||
'addressInfo1': pickup_address.address_line2,
|
||||
'houseNo': '',
|
||||
},
|
||||
'company': pickup_address.address_title,
|
||||
'person': {
|
||||
'title': pickup_contact.title,
|
||||
'firstname': pickup_contact.first_name,
|
||||
'lastname': pickup_contact.last_name
|
||||
},
|
||||
'phone': {
|
||||
'phoneNumber': pickup_contact.phone,
|
||||
'phoneNumberPrefix': pickup_contact.phone_prefix
|
||||
},
|
||||
'email': pickup_contact.email,
|
||||
},
|
||||
'deliveryInfo': {
|
||||
'address': {
|
||||
'countryCode': delivery_address.country_code,
|
||||
'zip': delivery_address.pincode,
|
||||
'city': delivery_address.city,
|
||||
'street': delivery_address.address_line1,
|
||||
'addressInfo1': delivery_address.address_line2,
|
||||
'houseNo': '',
|
||||
},
|
||||
'company': delivery_address.address_title,
|
||||
'person': {
|
||||
'title': delivery_contact.title,
|
||||
'firstname': delivery_contact.first_name,
|
||||
'lastname': delivery_contact.last_name
|
||||
},
|
||||
'phone': {
|
||||
'phoneNumber': delivery_contact.phone,
|
||||
'phoneNumberPrefix': delivery_contact.phone_prefix
|
||||
},
|
||||
'email': delivery_contact.email,
|
||||
},
|
||||
'shipmentDetails': {
|
||||
'contentDescription': description_of_content,
|
||||
'shipmentType': 'PARCEL',
|
||||
'shipmentSettings': {
|
||||
'saturdayDelivery': False,
|
||||
'ddp': False,
|
||||
'insurance': False,
|
||||
'pickupOrder': False,
|
||||
'pickupTailLift': False,
|
||||
'deliveryTailLift': False,
|
||||
'holidayDelivery': False,
|
||||
},
|
||||
'goodsValue': value_of_goods,
|
||||
'parcelList': parcel_list,
|
||||
'pickupInterval': {
|
||||
'date': pickup_date
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if service_info:
|
||||
payload['service'] = {
|
||||
'baseServiceDetails': {
|
||||
'id': service_info['id'],
|
||||
'name': service_info['service_name'],
|
||||
'carrier': service_info['carrier'],
|
||||
'priceInfo': service_info['price_info'],
|
||||
},
|
||||
'supportedExWorkType': [],
|
||||
'messages': [''],
|
||||
'description': '',
|
||||
'serviceInfo': '',
|
||||
}
|
||||
payload['shipmentNotification'] = {
|
||||
'trackingNotification': {
|
||||
'deliveryNotification': True,
|
||||
'problemNotification': True,
|
||||
'emails': [tracking_notific_email],
|
||||
'notificationText': '',
|
||||
},
|
||||
'recipientNotification': {
|
||||
'notificationText': '',
|
||||
'emails': [ shipment_notific_email ]
|
||||
}
|
||||
}
|
||||
payload['labelEmail'] = True
|
||||
return payload
|
||||
|
||||
def get_letmeship_label(shipment_id):
|
||||
try:
|
||||
# Retrieve shipment label from LetMeShip
|
||||
api_id = frappe.db.get_single_value('LetMeShip','api_id')
|
||||
api_password = frappe.db.get_single_value('LetMeShip','api_password')
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Access-Control-Allow-Origin': 'string'
|
||||
}
|
||||
url = 'https://api.letmeship.com/v1/shipments/{id}/documents?types=LABEL'\
|
||||
.format(id=shipment_id)
|
||||
shipment_label_response = requests.get(
|
||||
url,
|
||||
auth=(api_id,api_password),
|
||||
headers=headers
|
||||
)
|
||||
shipment_label_response_data = json.loads(shipment_label_response.text)
|
||||
if 'documents' in shipment_label_response_data:
|
||||
for label in shipment_label_response_data['documents']:
|
||||
if 'data' in label:
|
||||
return json.dumps(label['data'])
|
||||
else:
|
||||
frappe.throw(
|
||||
_('Error occurred while printing Shipment: {0}')
|
||||
.format(shipment_label_response_data['message'])
|
||||
)
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(
|
||||
_('Error occurred while printing Shipment: {0}')
|
||||
.format(str(exc)),
|
||||
indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
|
||||
|
||||
def get_letmeship_tracking_data(shipment_id):
|
||||
# return letmeship tracking data
|
||||
api_id = frappe.db.get_single_value('LetMeShip','api_id')
|
||||
api_password = frappe.db.get_single_value('LetMeShip','api_password')
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Access-Control-Allow-Origin': 'string'
|
||||
}
|
||||
try:
|
||||
url = 'https://api.letmeship.com/v1/tracking?shipmentid={id}'.format(id=shipment_id)
|
||||
tracking_data_response = requests.get(
|
||||
url,
|
||||
auth=(api_id, api_password),
|
||||
headers=headers
|
||||
)
|
||||
tracking_data = json.loads(tracking_data_response.text)
|
||||
if 'awbNumber' in tracking_data:
|
||||
tracking_status = 'In Progress'
|
||||
if tracking_data['lmsTrackingStatus'].startswith('DELIVERED'):
|
||||
tracking_status = 'Delivered'
|
||||
if tracking_data['lmsTrackingStatus'] == 'RETURNED':
|
||||
tracking_status = 'Returned'
|
||||
if tracking_data['lmsTrackingStatus'] == 'LOST':
|
||||
tracking_status = 'Lost'
|
||||
tracking_url = get_tracking_url(
|
||||
carrier=tracking_data['carrier'],
|
||||
tracking_number=tracking_data['awbNumber']
|
||||
)
|
||||
return {
|
||||
'awb_number': tracking_data['awbNumber'],
|
||||
'tracking_status': tracking_status,
|
||||
'tracking_status_info': tracking_data['lmsTrackingStatus'],
|
||||
'tracking_url': tracking_url,
|
||||
}
|
||||
elif 'message' in tracking_data:
|
||||
frappe.throw(
|
||||
_('Error occurred while updating Shipment: {0}')
|
||||
.format(tracking_data['message'])
|
||||
)
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(
|
||||
_('Error occurred while updating Shipment: {0}')
|
||||
.format(str(exc)),
|
||||
indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
|
||||
|
||||
def get_parcel_list(shipment_parcel, description_of_content):
|
||||
parcel_list = []
|
||||
for parcel in shipment_parcel:
|
||||
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')
|
||||
formatted_parcel['quantity'] = parcel.get('count')
|
||||
formatted_parcel['contentDescription'] = description_of_content
|
||||
parcel_list.append(formatted_parcel)
|
||||
return parcel_list
|
||||
|
||||
def set_letmeship_specific_fields(pickup_contact, delivery_contact):
|
||||
pickup_contact.phone_prefix = pickup_contact.phone[:3]
|
||||
pickup_contact.phone = re.sub('[^A-Za-z0-9]+', '', pickup_contact.phone[3:])
|
||||
|
||||
pickup_contact.title = 'MS'
|
||||
if pickup_contact.gender == 'Male':
|
||||
pickup_contact.title = 'MR'
|
||||
|
||||
delivery_contact.phone_prefix = delivery_contact.phone[:3]
|
||||
delivery_contact.phone = re.sub('[^A-Za-z0-9]+', '', delivery_contact.phone[3:])
|
||||
|
||||
delivery_contact.title = 'MS'
|
||||
if delivery_contact.gender == 'Male':
|
||||
delivery_contact.title = 'MR'
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestLetMeShip(unittest.TestCase):
|
||||
pass
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Packlink', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -1,48 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-07-22 10:45:17.672439",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"enabled",
|
||||
"api_key"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "api_key",
|
||||
"fieldtype": "Data",
|
||||
"label": "API Key",
|
||||
"read_only_depends_on": "eval:doc.enabled == 0"
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-08-05 16:33:59.720980",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"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
|
||||
}
|
@ -1,240 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
import frappe
|
||||
import requests
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from erpnext.erpnext_integrations.utils import get_tracking_url
|
||||
|
||||
PACKLINK_PROVIDER = 'Packlink'
|
||||
|
||||
class Packlink(Document):
|
||||
pass
|
||||
|
||||
def get_packlink_available_services(pickup_address, delivery_address, shipment_parcel,pickup_date):
|
||||
# Retrieve rates at PackLink from specification stated.
|
||||
from_zip = pickup_address.pincode
|
||||
from_country_code = pickup_address.country_code
|
||||
to_zip = delivery_address.pincode
|
||||
to_country_code = delivery_address.country_code
|
||||
shipment_parcel_params = ''
|
||||
parcel_list = packlink_get_parcel_list(json.loads(shipment_parcel))
|
||||
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']
|
||||
)
|
||||
url = 'https://api.packlink.com/v1/services?from[country]={}&from[zip]={}&to[country]={}&to[zip]={}&{}sortBy=totalPrice&source=PRO'.format(
|
||||
from_country_code,
|
||||
from_zip,
|
||||
to_country_code,
|
||||
to_zip,
|
||||
shipment_parcel_params
|
||||
)
|
||||
api_key = frappe.db.get_single_value('Packlink', 'api_key')
|
||||
enabled = frappe.db.get_single_value('Packlink', 'enabled')
|
||||
if not api_key or not enabled:
|
||||
return []
|
||||
try:
|
||||
responses = requests.get(url, headers={'Authorization': api_key})
|
||||
responses_dict = json.loads(responses.text)
|
||||
# If an error occured on the api. Show the error message
|
||||
if 'messages' in responses_dict:
|
||||
frappe.msgprint(
|
||||
_('Packlink: {0}'
|
||||
.format(str(responses_dict['messages'][0]['message']))
|
||||
),
|
||||
indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
available_services = []
|
||||
for response in responses_dict:
|
||||
if parse_pickup_date(pickup_date) \
|
||||
in response['available_dates'].keys():
|
||||
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']
|
||||
available_services.append(available_service)
|
||||
|
||||
return available_services
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(
|
||||
_('Error occurred on Packlink: {0}')
|
||||
.format(str(exc)), indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
return []
|
||||
|
||||
|
||||
def create_packlink_shipment(pickup_address, delivery_address, shipment_parcel,
|
||||
description_of_content, pickup_date, value_of_goods, pickup_contact,
|
||||
delivery_contact, service_info):
|
||||
# Create a transaction at PackLink
|
||||
enabled = frappe.db.get_single_value('Packlink', 'enabled')
|
||||
if not enabled:
|
||||
frappe.throw(_('Packlink integration is not enabled'))
|
||||
api_key = frappe.db.get_single_value('Packlink', 'api_key')
|
||||
from_country_code = pickup_address.country_code
|
||||
to_country_code = delivery_address.country_code
|
||||
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': parse_pickup_date(pickup_date),
|
||||
'collection_time': '',
|
||||
'content': description_of_content,
|
||||
'contentvalue': value_of_goods,
|
||||
'content_second_hand': False,
|
||||
'from': {
|
||||
'city': pickup_address.city,
|
||||
'company': pickup_address.address_title,
|
||||
'country': from_country_code,
|
||||
'email': pickup_contact.email,
|
||||
'name': pickup_contact.first_name,
|
||||
'phone': pickup_contact.phone,
|
||||
'state': pickup_address.country,
|
||||
'street1': pickup_address.address_line1,
|
||||
'street2': pickup_address.address_line2,
|
||||
'surname': pickup_contact.last_name,
|
||||
'zip_code': pickup_address.pincode,
|
||||
},
|
||||
'insurance': {'amount': 0, 'insurance_selected': False},
|
||||
'price': {},
|
||||
'packages': packlink_get_parcel_list(json.loads(shipment_parcel)),
|
||||
'service_id': service_info['service_id'],
|
||||
'to': {
|
||||
'city': delivery_address.city,
|
||||
'company': delivery_address.address_title,
|
||||
'country': to_country_code,
|
||||
'email': delivery_contact.email,
|
||||
'name': delivery_contact.first_name,
|
||||
'phone': delivery_contact.phone,
|
||||
'state': delivery_address.country,
|
||||
'street1': delivery_address.address_line1,
|
||||
'street2': delivery_address.address_line2,
|
||||
'surname': delivery_contact.last_name,
|
||||
'zip_code': delivery_address.pincode,
|
||||
},
|
||||
}
|
||||
|
||||
url = 'https://api.packlink.com/v1/shipments'
|
||||
headers = {
|
||||
'Authorization': 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 as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(
|
||||
_('Error occurred while creating Shipment: {0}')
|
||||
.format(str(exc)),
|
||||
indicator='orange',
|
||||
alert=True
|
||||
)
|
||||
|
||||
|
||||
def get_packlink_label(shipment_id):
|
||||
# Retrieve shipment label from PackLink
|
||||
enabled = frappe.db.get_single_value('Packlink', 'enabled')
|
||||
if not enabled:
|
||||
frappe.throw(_('Packlink integration is not enabled'))
|
||||
api_key = frappe.db.get_single_value('Packlink', 'api_key')
|
||||
headers = {
|
||||
'Authorization': api_key,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
shipment_label_response = requests.get(
|
||||
'https://api.packlink.com/v1/shipments/{id}/labels'.format(id=shipment_id),
|
||||
headers=headers
|
||||
)
|
||||
shipment_label = json.loads(shipment_label_response.text)
|
||||
if shipment_label:
|
||||
return shipment_label
|
||||
else:
|
||||
frappe.msgprint(_('Shipment ID not found'))
|
||||
|
||||
|
||||
def get_packlink_tracking_data(shipment_id):
|
||||
# Get Packlink Tracking Info
|
||||
enabled = frappe.db.get_single_value('Packlink', 'enabled')
|
||||
if not enabled:
|
||||
frappe.throw(_('Packlink integration is not enabled'))
|
||||
api_key = frappe.db.get_single_value('Packlink', 'api_key')
|
||||
headers = {
|
||||
'Authorization': api_key,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
try:
|
||||
url = 'https://api.packlink.com/v1/shipments/{id}'.format(id=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 as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(_('Error occurred while updating Shipment: {0}').format(
|
||||
str(exc)), indicator='orange', alert=True)
|
||||
return []
|
||||
|
||||
|
||||
def packlink_get_parcel_list(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(pickup_date):
|
||||
return pickup_date.replace('-', '/')
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestPacklink(unittest.TestCase):
|
||||
pass
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('SendCloud', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -1,56 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-08-18 09:48:50.836233",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"enabled",
|
||||
"api_key",
|
||||
"api_secret"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
},
|
||||
{
|
||||
"fieldname": "api_key",
|
||||
"fieldtype": "Data",
|
||||
"label": "API Key",
|
||||
"read_only_depends_on": "eval:doc.enabled == 0"
|
||||
},
|
||||
{
|
||||
"fieldname": "api_secret",
|
||||
"fieldtype": "Password",
|
||||
"label": "API Secret",
|
||||
"read_only_depends_on": "eval:doc.enabled == 0"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-10-21 10:28:57.710549",
|
||||
"modified_by": "Administrator",
|
||||
"module": "ERPNext Integrations",
|
||||
"name": "SendCloud",
|
||||
"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
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import requests
|
||||
import frappe
|
||||
import json
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
|
||||
SENDCLOUD_PROVIDER = 'SendCloud'
|
||||
|
||||
class SendCloud(Document):
|
||||
pass
|
||||
|
||||
def get_sendcloud_available_services(delivery_address, shipment_parcel):
|
||||
# Retrieve rates at SendCloud from specification stated.
|
||||
api_key, api_secret, enabled = frappe.db.get_value('SendCloud', 'SendCloud', ['enabled', 'api_key', 'api_secret'])
|
||||
if not enabled or not api_key or not api_secret:
|
||||
return []
|
||||
|
||||
try:
|
||||
url = 'https://panel.sendcloud.sc/api/v2/shipping_methods'
|
||||
responses = requests.get(url, auth=(api_key, api_secret))
|
||||
responses_dict = json.loads(responses.text)
|
||||
|
||||
available_services = []
|
||||
for service in responses_dict['shipping_methods']:
|
||||
for country in service['countries']:
|
||||
if country['iso_2'] == delivery_address.country_code:
|
||||
available_service = frappe._dict()
|
||||
available_service.service_provider = 'SendCloud'
|
||||
available_service.carrier = service['carrier']
|
||||
available_service.service_name = service['name']
|
||||
available_service.total_price = total_parcel_price(country['price'], json.loads(shipment_parcel))
|
||||
available_service.service_id = service['id']
|
||||
available_services.append(available_service)
|
||||
return available_services
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(_('Error occurred on SendCloud: {0}').format(
|
||||
str(exc)), indicator='orange', alert=True)
|
||||
|
||||
def create_sendcloud_shipment(
|
||||
shipment,
|
||||
delivery_address,
|
||||
delivery_contact,
|
||||
service_info,
|
||||
shipment_parcel,
|
||||
description_of_content,
|
||||
value_of_goods
|
||||
):
|
||||
# Create a transaction at SendCloud
|
||||
api_key, api_secret, enabled = frappe.db.get_value('SendCloud', 'SendCloud', ['enabled', 'api_key', 'api_secret'])
|
||||
if not enabled or not api_key or not api_secret:
|
||||
return []
|
||||
|
||||
parcels = []
|
||||
for i, parcel in enumerate(json.loads(shipment_parcel), start=1):
|
||||
parcel_data = {
|
||||
'name': "{} {}".format(delivery_contact.first_name, delivery_contact.last_name),
|
||||
'company_name': delivery_address.address_title,
|
||||
'address': delivery_address.address_line1,
|
||||
'address_2': delivery_address.address_line2 or '',
|
||||
'city': delivery_address.city,
|
||||
'postal_code': delivery_address.pincode,
|
||||
'telephone': delivery_contact.phone,
|
||||
'request_label': True,
|
||||
'email': delivery_contact.email,
|
||||
'data': [],
|
||||
'country': delivery_address.country_code,
|
||||
'shipment': {
|
||||
'id': service_info['service_id']
|
||||
},
|
||||
'order_number': "{}-{}".format(shipment, i),
|
||||
'external_reference': "{}-{}".format(shipment, i),
|
||||
'weight': parcel.get('weight'),
|
||||
'parcel_items': get_parcel_items(parcel, description_of_content, value_of_goods)
|
||||
}
|
||||
parcels.append(parcel_data)
|
||||
data = {
|
||||
'parcels': parcels
|
||||
}
|
||||
try:
|
||||
url = 'https://panel.sendcloud.sc/api/v2/parcels?errors=verbose'
|
||||
response_data = requests.post(url, json=data, auth=(api_key, api_secret))
|
||||
response_data = json.loads(response_data.text)
|
||||
if 'failed_parcels' in response_data:
|
||||
frappe.msgprint(_('Error occurred while creating Shipment: {0}'
|
||||
).format(response_data['failed_parcels'][0]['errors']), indicator='orange',
|
||||
alert=True)
|
||||
else:
|
||||
shipment_id = ', '.join([str(x['id']) for x in response_data['parcels']])
|
||||
awb_number = ', '.join([str(x['tracking_number']) for x in response_data['parcels']])
|
||||
return {
|
||||
'service_provider': 'SendCloud',
|
||||
'shipment_id': shipment_id,
|
||||
'carrier': service_info['carrier'],
|
||||
'carrier_service': service_info['service_name'],
|
||||
'shipment_amount': service_info['total_price'],
|
||||
'awb_number': awb_number
|
||||
}
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(_('Error occurred while creating Shipment: {0}').format(
|
||||
str(exc)), indicator='orange', alert=True)
|
||||
|
||||
def get_sendcloud_label(shipment_id):
|
||||
# Retrieve shipment label from SendCloud
|
||||
api_key = frappe.db.get_single_value('SendCloud', 'api_key')
|
||||
api_secret = frappe.db.get_single_value('SendCloud', 'api_secret')
|
||||
shipment_id_list = shipment_id.split(', ')
|
||||
label_urls = []
|
||||
for ship_id in shipment_id_list:
|
||||
shipment_label_response = \
|
||||
requests.get('https://panel.sendcloud.sc/api/v2/labels/{id}'.format(id=ship_id), auth=(api_key, api_secret))
|
||||
shipment_label = json.loads(shipment_label_response.text)
|
||||
label_urls.append(shipment_label['label']['label_printer'])
|
||||
if len(label_urls):
|
||||
return label_urls
|
||||
else:
|
||||
frappe.msgprint(_('Shipment ID not found'))
|
||||
|
||||
def get_sendcloud_tracking_data(shipment_id):
|
||||
# return SendCloud tracking data
|
||||
try:
|
||||
api_key = frappe.db.get_single_value('SendCloud', 'api_key')
|
||||
api_secret = frappe.db.get_single_value('SendCloud', 'api_secret')
|
||||
shipment_id_list = shipment_id.split(', ')
|
||||
awb_number = []
|
||||
tracking_status = []
|
||||
tracking_status_info = []
|
||||
tracking_urls = []
|
||||
for ship_id in shipment_id_list:
|
||||
tracking_data_response = \
|
||||
requests.get('https://panel.sendcloud.sc/api/v2/parcels/{id}'.format(id=ship_id), auth=(api_key, api_secret))
|
||||
tracking_data = json.loads(tracking_data_response.text)
|
||||
tracking_urls.append(tracking_data['parcel']['tracking_url'])
|
||||
awb_number.append(tracking_data['parcel']['tracking_number'])
|
||||
tracking_status.append(tracking_data['parcel']['status']['message'])
|
||||
tracking_status_info.append(tracking_data['parcel']['status']['message'])
|
||||
return {
|
||||
'awb_number': ', '.join(awb_number),
|
||||
'tracking_status': ', '.join(tracking_status),
|
||||
'tracking_status_info': ', '.join(tracking_status_info),
|
||||
'tracking_url': ', '.join(tracking_urls)
|
||||
}
|
||||
except Exception as exc:
|
||||
frappe.log_error(frappe.get_traceback())
|
||||
frappe.msgprint(_('Error occurred while updating Shipment: {0}').format(
|
||||
str(exc)), indicator='orange', alert=True)
|
||||
|
||||
def total_parcel_price(parcel_price, shipment_parcel):
|
||||
count = 0
|
||||
for parcel in shipment_parcel:
|
||||
count += parcel.get('count')
|
||||
return parcel_price * count
|
||||
|
||||
def get_parcel_items(parcel, description_of_content, value_of_goods):
|
||||
parcel_list = []
|
||||
formatted_parcel = {}
|
||||
formatted_parcel['description'] = description_of_content
|
||||
formatted_parcel['quantity'] = parcel.get('count')
|
||||
formatted_parcel['weight'] = parcel.get('weight')
|
||||
formatted_parcel['value'] = value_of_goods
|
||||
parcel_list.append(formatted_parcel)
|
||||
return parcel_list
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestSendCloud(unittest.TestCase):
|
||||
pass
|
@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Parcel Service', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
@ -1,56 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "field:parcel_service_name",
|
||||
"creation": "2020-07-23 10:35:38.211715",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"parcel_service_name",
|
||||
"parcel_service_code",
|
||||
"url_reference"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "parcel_service_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Parcel Service Name",
|
||||
"unique": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parcel_service_code",
|
||||
"fieldtype": "Data",
|
||||
"label": "Parcel Service Code"
|
||||
},
|
||||
{
|
||||
"fieldname": "url_reference",
|
||||
"fieldtype": "Data",
|
||||
"label": "URL Reference"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-07-23 10:35:38.211715",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Parcel Service",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ParcelService(Document):
|
||||
pass
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestParcelService(unittest.TestCase):
|
||||
pass
|
@ -1,12 +0,0 @@
|
||||
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Parcel Service Type Alias', {
|
||||
parcel_type_alias: function(frm, cdt, cdn) {
|
||||
let row = locals[cdt][cdn];
|
||||
if (row.parcel_type_alias) {
|
||||
frappe.model.set_value(cdt, cdn, 'parcel_service', frm.doc.parcel_service);
|
||||
frm.refresh_field('parcel_service_type_alias');
|
||||
}
|
||||
}
|
||||
});
|
@ -1,89 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_rename": 1,
|
||||
"autoname": "format: {parcel_service} - {parcel_service_type}",
|
||||
"creation": "2020-07-23 10:47:43.794083",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"parcel_service",
|
||||
"parcel_service_type",
|
||||
"description",
|
||||
"section_break_4",
|
||||
"parcel_service_type_alias",
|
||||
"column_break_6",
|
||||
"section_break_7",
|
||||
"show_in_preferred_services_list"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "parcel_service",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Parcel Service",
|
||||
"options": "Parcel Service",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parcel_service_type",
|
||||
"fieldtype": "Data",
|
||||
"label": "Parcel Service Type",
|
||||
"reqd": 1,
|
||||
"set_only_once": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "description",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Description"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_4",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "parcel_service_type_alias",
|
||||
"fieldtype": "Table",
|
||||
"label": "Parcel Service Type Alias",
|
||||
"options": "Parcel Service Type Alias"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_6",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "section_break_7",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "show_in_preferred_services_list",
|
||||
"fieldtype": "Check",
|
||||
"label": "Show in Preferred Services List"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-07-23 10:47:43.794083",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Parcel Service Type",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ParcelServiceType(Document):
|
||||
pass
|
||||
|
||||
def match_parcel_service_type_alias(parcel_service_type, parcel_service):
|
||||
# Match and return Parcel Service Type Alias to Parcel Service Type if exists.
|
||||
if frappe.db.exists('Parcel Service', parcel_service):
|
||||
matched_parcel_service_type = \
|
||||
frappe.db.get_value('Parcel Service Type Alias', {
|
||||
'parcel_type_alias': parcel_service_type,
|
||||
'parcel_service': parcel_service
|
||||
}, 'parent')
|
||||
if matched_parcel_service_type:
|
||||
parcel_service_type = matched_parcel_service_type
|
||||
return parcel_service_type
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# import frappe
|
||||
import unittest
|
||||
|
||||
class TestParcelServiceType(unittest.TestCase):
|
||||
pass
|
@ -1,41 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2020-07-23 10:47:23.626510",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"parcel_service",
|
||||
"parcel_type_alias"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "parcel_service",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "Parcel Service",
|
||||
"options": "Parcel Service",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "parcel_type_alias",
|
||||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Parcel Type Alias",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-07-23 10:47:23.626510",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Parcel Service Type Alias",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
# import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class ParcelServiceTypeAlias(Document):
|
||||
pass
|
@ -114,26 +114,6 @@ frappe.ui.form.on('Shipment', {
|
||||
});
|
||||
},
|
||||
refresh: function(frm) {
|
||||
if (frm.doc.docstatus === 1 && !frm.doc.shipment_id) {
|
||||
frm.add_custom_button(__('Fetch Shipping Rates'), function() {
|
||||
return frm.events.fetch_shipping_rates(frm);
|
||||
});
|
||||
}
|
||||
if (frm.doc.shipment_id) {
|
||||
frm.add_custom_button(__('Print Shipping Label'), function() {
|
||||
return frm.events.print_shipping_label(frm);
|
||||
}, __('Tools'));
|
||||
if (frm.doc.tracking_status != 'Delivered') {
|
||||
frm.add_custom_button(__('Update Tracking'), function() {
|
||||
return frm.events.update_tracking(frm, frm.doc.service_provider, frm.doc.shipment_id);
|
||||
}, __('Tools'));
|
||||
|
||||
frm.add_custom_button(__('Track Status'), function() {
|
||||
const urls = frm.doc.tracking_url.split(', ');
|
||||
urls.forEach(url => window.open(url));
|
||||
}, __('View'));
|
||||
}
|
||||
}
|
||||
$('div[data-fieldname=pickup_address] > div > .clearfix').hide();
|
||||
$('div[data-fieldname=pickup_contact] > div > .clearfix').hide();
|
||||
$('div[data-fieldname=delivery_address] > div > .clearfix').hide();
|
||||
@ -598,90 +578,6 @@ frappe.ui.form.on('Shipment', {
|
||||
frm.refresh_fields("pickup_from_send_shipping_notification");
|
||||
frm.refresh_fields("pickup_from_subscribe_to_status_updates");
|
||||
}
|
||||
},
|
||||
fetch_shipping_rates: function(frm) {
|
||||
if (!frm.doc.shipment_id) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.fetch_shipping_rates",
|
||||
freeze: true,
|
||||
freeze_message: __("Fetching Shipping Rates"),
|
||||
args: {
|
||||
pickup_from_type: frm.doc.pickup_from_type,
|
||||
delivery_to_type: frm.doc.delivery_to_type,
|
||||
pickup_address_name: frm.doc.pickup_address_name,
|
||||
delivery_address_name: frm.doc.delivery_address_name,
|
||||
shipment_parcel: frm.doc.shipment_parcel,
|
||||
description_of_content: frm.doc.description_of_content,
|
||||
pickup_date: frm.doc.pickup_date,
|
||||
pickup_contact_name: frm.doc.pickup_from_type === 'Company' ? frm.doc.pickup_contact_person : frm.doc.pickup_contact_name,
|
||||
delivery_contact_name: frm.doc.delivery_contact_name,
|
||||
value_of_goods: frm.doc.value_of_goods
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
select_from_available_services(frm, r.message);
|
||||
}
|
||||
else {
|
||||
frappe.throw(__("No Shipment Services available"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
frappe.throw(__("Shipment already created"));
|
||||
}
|
||||
},
|
||||
print_shipping_label: function(frm) {
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.print_shipping_label",
|
||||
freeze: true,
|
||||
freeze_message: __("Printing Shipping Label"),
|
||||
args: {
|
||||
shipment_id: frm.doc.shipment_id,
|
||||
service_provider: frm.doc.service_provider
|
||||
},
|
||||
callback: function(r) {
|
||||
if (r.message) {
|
||||
if (frm.doc.service_provider == "LetMeShip") {
|
||||
var array = JSON.parse(r.message);
|
||||
// Uint8Array for unsigned bytes
|
||||
array = new Uint8Array(array);
|
||||
const file = new Blob([array], {type: "application/pdf"});
|
||||
const file_url = URL.createObjectURL(file);
|
||||
window.open(file_url);
|
||||
}
|
||||
else {
|
||||
if (Array.isArray(r.message)) {
|
||||
r.message.forEach(url => window.open(url));
|
||||
} else {
|
||||
window.open(r.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
update_tracking: function(frm, service_provider, shipment_id) {
|
||||
let delivery_notes = [];
|
||||
(frm.doc.shipment_delivery_note || []).forEach((d) => {
|
||||
delivery_notes.push(d.delivery_note);
|
||||
});
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.update_tracking",
|
||||
freeze: true,
|
||||
freeze_message: __("Updating Tracking"),
|
||||
args: {
|
||||
shipment: frm.doc.name,
|
||||
shipment_id: shipment_id,
|
||||
service_provider: service_provider,
|
||||
delivery_notes: delivery_notes
|
||||
},
|
||||
callback: function(r) {
|
||||
if (!r.exc) {
|
||||
frm.reload_doc();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -712,82 +608,3 @@ var validate_duplicate = function(frm, table, fieldname, index){
|
||||
: frm.doc[table].some((detail, i) => detail.email === fieldname && !(index === i))
|
||||
);
|
||||
};
|
||||
|
||||
function select_from_available_services(frm, available_services) {
|
||||
var headers = [ __("Service Provider"), __("Carrier"), __("Carrier’s Service"), __("Price"), "" ];
|
||||
cur_frm.render_available_services = function(d, headers, data){
|
||||
const arranged_data = data.reduce((prev, curr) => {
|
||||
if (curr.is_preferred) {
|
||||
prev.preferred_services.push(curr);
|
||||
} else {
|
||||
prev.other_services.push(curr);
|
||||
}
|
||||
return prev;
|
||||
}, { preferred_services: [], other_services: [] });
|
||||
d.fields_dict.available_services.$wrapper.html(
|
||||
frappe.render_template('shipment_service_selector',
|
||||
{'header_columns': headers, 'data': arranged_data}
|
||||
)
|
||||
);
|
||||
};
|
||||
const d = new frappe.ui.Dialog({
|
||||
title: __("Select Shipment Service to create Shipment"),
|
||||
fields: [
|
||||
{
|
||||
fieldtype:'HTML',
|
||||
fieldname:"available_services",
|
||||
label: __('Available Services')
|
||||
}
|
||||
]
|
||||
});
|
||||
cur_frm.render_available_services(d, headers, available_services);
|
||||
let shipment_notific_email = [];
|
||||
let tracking_notific_email = [];
|
||||
(frm.doc.shipment_notification_subscription || []).forEach((d) => {
|
||||
if (!d.unsubscribed) {
|
||||
shipment_notific_email.push(d.email);
|
||||
}
|
||||
});
|
||||
(frm.doc.shipment_status_update_subscription || []).forEach((d) => {
|
||||
if (!d.unsubscribed) {
|
||||
tracking_notific_email.push(d.email);
|
||||
}
|
||||
});
|
||||
let delivery_notes = [];
|
||||
(frm.doc.shipment_delivery_note || []).forEach((d) => {
|
||||
delivery_notes.push(d.delivery_note);
|
||||
});
|
||||
cur_frm.select_row = function(service_data){
|
||||
frappe.call({
|
||||
method: "erpnext.stock.doctype.shipment.shipment.create_shipment",
|
||||
freeze: true,
|
||||
freeze_message: __("Creating Shipment"),
|
||||
args: {
|
||||
shipment: frm.doc.name,
|
||||
pickup_from_type: frm.doc.pickup_from_type,
|
||||
delivery_to_type: frm.doc.delivery_to_type,
|
||||
pickup_address_name: frm.doc.pickup_address_name,
|
||||
delivery_address_name: frm.doc.delivery_address_name,
|
||||
shipment_parcel: frm.doc.shipment_parcel,
|
||||
description_of_content: frm.doc.description_of_content,
|
||||
pickup_date: frm.doc.pickup_date,
|
||||
pickup_contact_name: frm.doc.pickup_from_type === 'Company' ? frm.doc.pickup_contact_person : frm.doc.pickup_contact_name,
|
||||
delivery_contact_name: frm.doc.delivery_contact_name,
|
||||
value_of_goods: frm.doc.value_of_goods,
|
||||
service_data: service_data,
|
||||
shipment_notific_email: shipment_notific_email,
|
||||
tracking_notific_email: tracking_notific_email,
|
||||
delivery_notes: delivery_notes
|
||||
},
|
||||
callback: function(r) {
|
||||
if (!r.exc) {
|
||||
frm.reload_doc();
|
||||
frappe.msgprint(__("Shipment created with {0}, ID is {1}", [r.message.service_provider, r.message.shipment_id]));
|
||||
frm.events.update_tracking(frm, r.message.service_provider, r.message.shipment_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
d.hide();
|
||||
};
|
||||
d.show();
|
||||
}
|
||||
|
@ -358,28 +358,24 @@
|
||||
{
|
||||
"fieldname": "service_provider",
|
||||
"fieldtype": "Data",
|
||||
"label": "Service Provider",
|
||||
"read_only": 1
|
||||
"label": "Service Provider"
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Shipment ID",
|
||||
"read_only": 1
|
||||
"label": "Shipment ID"
|
||||
},
|
||||
{
|
||||
"fieldname": "shipment_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Shipment Amount",
|
||||
"precision": "2",
|
||||
"read_only": 1
|
||||
"precision": "2"
|
||||
},
|
||||
{
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "Draft\nSubmitted\nBooked\nCancelled\nCompleted",
|
||||
"read_only": 1
|
||||
"options": "Draft\nSubmitted\nBooked\nCancelled\nCompleted"
|
||||
},
|
||||
{
|
||||
"fieldname": "tracking_url",
|
||||
@ -391,27 +387,23 @@
|
||||
{
|
||||
"fieldname": "carrier",
|
||||
"fieldtype": "Data",
|
||||
"label": "Carrier",
|
||||
"read_only": 1
|
||||
"label": "Carrier"
|
||||
},
|
||||
{
|
||||
"fieldname": "carrier_service",
|
||||
"fieldtype": "Data",
|
||||
"label": "Carrier Service",
|
||||
"read_only": 1
|
||||
"label": "Carrier Service"
|
||||
},
|
||||
{
|
||||
"fieldname": "awb_number",
|
||||
"fieldtype": "Data",
|
||||
"label": "AWB Number",
|
||||
"read_only": 1
|
||||
"label": "AWB Number"
|
||||
},
|
||||
{
|
||||
"fieldname": "tracking_status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Tracking Status",
|
||||
"options": "\nIn Progress\nDelivered\nReturned\nLost",
|
||||
"read_only": 1
|
||||
"options": "\nIn Progress\nDelivered\nReturned\nLost"
|
||||
},
|
||||
{
|
||||
"fieldname": "tracking_status_info",
|
||||
@ -468,7 +460,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-29 13:59:50.241744",
|
||||
"modified": "2020-11-20 16:19:06.157106",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Shipment",
|
||||
|
@ -10,10 +10,6 @@ from frappe.utils import flt
|
||||
from frappe.model.document import Document
|
||||
from erpnext.accounts.party import get_party_shipping_address
|
||||
from frappe.contacts.doctype.contact.contact import get_default_contact
|
||||
from erpnext.erpnext_integrations.doctype.letmeship.letmeship import LETMESHIP_PROVIDER, get_letmeship_available_services, create_letmeship_shipment, get_letmeship_label, get_letmeship_tracking_data
|
||||
from erpnext.erpnext_integrations.doctype.packlink.packlink import PACKLINK_PROVIDER, get_packlink_available_services, create_packlink_shipment, get_packlink_label, get_packlink_tracking_data
|
||||
from erpnext.erpnext_integrations.doctype.sendcloud.sendcloud import SENDCLOUD_PROVIDER, get_sendcloud_available_services, create_sendcloud_shipment, get_sendcloud_label, get_sendcloud_tracking_data
|
||||
from erpnext.stock.doctype.parcel_service_type.parcel_service_type import match_parcel_service_type_alias
|
||||
|
||||
class Shipment(Document):
|
||||
def validate(self):
|
||||
@ -36,159 +32,6 @@ class Shipment(Document):
|
||||
if flt(parcel.weight) <= 0:
|
||||
frappe.throw(_('Parcel weight cannot be 0'))
|
||||
|
||||
@frappe.whitelist()
|
||||
def fetch_shipping_rates(pickup_from_type, delivery_to_type, pickup_address_name, delivery_address_name,
|
||||
shipment_parcel, description_of_content, pickup_date, value_of_goods,
|
||||
pickup_contact_name=None, delivery_contact_name=None):
|
||||
# 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)
|
||||
if letmeship_enabled:
|
||||
pickup_contact = None
|
||||
delivery_contact = None
|
||||
if pickup_from_type != 'Company':
|
||||
pickup_contact = get_contact(pickup_contact_name)
|
||||
else:
|
||||
pickup_contact = get_company_contact(user=pickup_contact_name)
|
||||
|
||||
if delivery_to_type != 'Company':
|
||||
delivery_contact = get_contact(delivery_contact_name)
|
||||
else:
|
||||
delivery_contact = get_company_contact(user=pickup_contact_name)
|
||||
letmeship_prices = get_letmeship_available_services(
|
||||
delivery_to_type=delivery_to_type,
|
||||
pickup_address=pickup_address,
|
||||
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,
|
||||
)
|
||||
letmeship_prices = match_parcel_service_type_carrier(letmeship_prices, ['carrier', 'carrier_name'])
|
||||
shipment_prices = shipment_prices + letmeship_prices
|
||||
if packlink_enabled:
|
||||
packlink_prices = get_packlink_available_services(
|
||||
pickup_address=pickup_address,
|
||||
delivery_address=delivery_address,
|
||||
shipment_parcel=shipment_parcel,
|
||||
pickup_date=pickup_date
|
||||
)
|
||||
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_prices = get_sendcloud_available_services(
|
||||
delivery_address=delivery_address,
|
||||
shipment_parcel=shipment_parcel
|
||||
)
|
||||
shipment_prices = shipment_prices + sendcloud_prices
|
||||
shipment_prices = sorted(shipment_prices, key=lambda k:k['total_price'])
|
||||
return shipment_prices
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_shipment(shipment, pickup_from_type, delivery_to_type, pickup_address_name,
|
||||
delivery_address_name, shipment_parcel, description_of_content, pickup_date,
|
||||
value_of_goods, service_data, shipment_notific_email, tracking_notific_email,
|
||||
pickup_contact_name=None, delivery_contact_name=None, delivery_notes=[]):
|
||||
# Create Shipment for the selected provider
|
||||
service_info = json.loads(service_data)
|
||||
shipment_info = None
|
||||
pickup_contact = None
|
||||
delivery_contact = None
|
||||
pickup_address = get_address(pickup_address_name)
|
||||
delivery_address = get_address(delivery_address_name)
|
||||
if pickup_from_type != 'Company':
|
||||
pickup_contact = get_contact(pickup_contact_name)
|
||||
else:
|
||||
pickup_contact = get_company_contact(user=pickup_contact_name)
|
||||
|
||||
if delivery_to_type != 'Company':
|
||||
delivery_contact = get_contact(delivery_contact_name)
|
||||
else:
|
||||
delivery_contact = get_company_contact(user=pickup_contact_name)
|
||||
if service_info['service_provider'] == LETMESHIP_PROVIDER:
|
||||
shipment_info = create_letmeship_shipment(
|
||||
pickup_address=pickup_address,
|
||||
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,
|
||||
shipment_notific_email=shipment_notific_email,
|
||||
tracking_notific_email=tracking_notific_email,
|
||||
)
|
||||
|
||||
if service_info['service_provider'] == PACKLINK_PROVIDER:
|
||||
shipment_info = create_packlink_shipment(
|
||||
pickup_address=pickup_address,
|
||||
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:
|
||||
shipment_info = create_sendcloud_shipment(
|
||||
shipment=shipment,
|
||||
delivery_address=delivery_address,
|
||||
shipment_parcel=shipment_parcel,
|
||||
description_of_content=description_of_content,
|
||||
value_of_goods=value_of_goods,
|
||||
delivery_contact=delivery_contact,
|
||||
service_info=service_info,
|
||||
)
|
||||
|
||||
if shipment_info:
|
||||
fields = ['service_provider', 'carrier', 'carrier_service', 'shipment_id', 'shipment_amount', 'awb_number']
|
||||
for field in fields:
|
||||
frappe.db.set_value('Shipment', shipment, field, shipment_info.get(field))
|
||||
frappe.db.set_value('Shipment', shipment, 'status', 'Booked')
|
||||
if delivery_notes:
|
||||
update_delivery_note(delivery_notes=delivery_notes, shipment_info=shipment_info)
|
||||
return shipment_info
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def print_shipping_label(service_provider, shipment_id):
|
||||
if service_provider == LETMESHIP_PROVIDER:
|
||||
shipping_label = get_letmeship_label(shipment_id)
|
||||
elif service_provider == PACKLINK_PROVIDER:
|
||||
shipping_label = get_packlink_label(shipment_id)
|
||||
elif service_provider == SENDCLOUD_PROVIDER:
|
||||
shipping_label = get_sendcloud_label(shipment_id)
|
||||
return shipping_label
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_tracking(shipment, service_provider, shipment_id, delivery_notes=[]):
|
||||
# Update Tracking info in Shipment
|
||||
tracking_data = None
|
||||
if service_provider == LETMESHIP_PROVIDER:
|
||||
tracking_data = get_letmeship_tracking_data(shipment_id)
|
||||
elif service_provider == PACKLINK_PROVIDER:
|
||||
tracking_data = get_packlink_tracking_data(shipment_id)
|
||||
elif service_provider == SENDCLOUD_PROVIDER:
|
||||
tracking_data = get_sendcloud_tracking_data(shipment_id)
|
||||
if tracking_data:
|
||||
if delivery_notes:
|
||||
update_delivery_note(delivery_notes=delivery_notes, tracking_info=tracking_data)
|
||||
frappe.db.set_value('Shipment', shipment, 'awb_number', tracking_data.get('awb_number'))
|
||||
frappe.db.set_value('Shipment', shipment, 'tracking_status', tracking_data.get('tracking_status'))
|
||||
frappe.db.set_value('Shipment', shipment, 'tracking_status_info', tracking_data.get('tracking_status_info'))
|
||||
frappe.db.set_value('Shipment', shipment, 'tracking_url', tracking_data.get('tracking_url'))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_address_name(ref_doctype, docname):
|
||||
# Return address name
|
||||
@ -199,90 +42,6 @@ def get_contact_name(ref_doctype, docname):
|
||||
# Return address name
|
||||
return get_default_contact(ref_doctype, docname)
|
||||
|
||||
def update_delivery_note(delivery_notes, shipment_info=None, tracking_info=None):
|
||||
# Update Shipment Info in Delivery Note
|
||||
# Using db_set since some services might not exist
|
||||
for delivery_note in json.loads(delivery_notes):
|
||||
dl_doc = frappe.get_doc('Delivery Note', delivery_note)
|
||||
if shipment_info:
|
||||
dl_doc.db_set('delivery_type', 'Parcel Service')
|
||||
dl_doc.db_set('parcel_service', shipment_info.get('carrier'))
|
||||
dl_doc.db_set('parcel_service_type', shipment_info.get('carrier_service'))
|
||||
if tracking_info:
|
||||
dl_doc.db_set('tracking_number', tracking_info.get('awb_number'))
|
||||
dl_doc.db_set('tracking_url', tracking_info.get('tracking_url'))
|
||||
dl_doc.db_set('tracking_status', tracking_info.get('tracking_status'))
|
||||
dl_doc.db_set('tracking_status_info', tracking_info.get('tracking_status_info'))
|
||||
|
||||
|
||||
def update_tracking_info():
|
||||
# Daily scheduled event to update Tracking info for not delivered Shipments
|
||||
# Also Updates the related Delivery Notes
|
||||
shipments = frappe.get_all('Shipment', filters={
|
||||
'docstatus': 1,
|
||||
'status': 'Booked',
|
||||
'shipment_id': ['!=', ''],
|
||||
'tracking_status': ['!=', 'Delivered'],
|
||||
})
|
||||
for shipment in shipments:
|
||||
shipment_doc = frappe.get_doc('Shipment', shipment.name)
|
||||
tracking_info = \
|
||||
update_tracking(
|
||||
shipment_doc.service_provider,
|
||||
shipment_doc.shipment_id,
|
||||
shipment_doc.shipment_delivery_notes
|
||||
)
|
||||
if tracking_info:
|
||||
shipment_doc.db_set('awb_number', tracking_info.get('awb_number'))
|
||||
shipment_doc.db_set('tracking_url', tracking_info.get('tracking_url'))
|
||||
shipment_doc.db_set('tracking_status', tracking_info.get('tracking_status'))
|
||||
shipment_doc.db_set('tracking_status_info', tracking_info.get('tracking_status_info'))
|
||||
|
||||
|
||||
def get_address(address_name):
|
||||
address = frappe.db.get_value('Address', address_name, [
|
||||
'address_title',
|
||||
'address_line1',
|
||||
'address_line2',
|
||||
'city',
|
||||
'pincode',
|
||||
'country',
|
||||
], as_dict=1)
|
||||
address.country_code = frappe.db.get_value('Country', address.country, 'code').upper()
|
||||
if not address.pincode or address.pincode == '':
|
||||
frappe.throw(_("Postal Code is mandatory to continue. </br> \
|
||||
Please set Postal Code for Address <a href='#Form/Address/{0}'>{1}</a>"
|
||||
).format(address_name, address_name))
|
||||
address.pincode = address.pincode.replace(' ', '')
|
||||
address.city = address.city.strip()
|
||||
return address
|
||||
|
||||
|
||||
def get_contact(contact_name):
|
||||
contact = frappe.db.get_value('Contact', contact_name, [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email_id',
|
||||
'phone',
|
||||
'mobile_no',
|
||||
'gender',
|
||||
], as_dict=1)
|
||||
if not contact.last_name:
|
||||
frappe.throw(_("Last Name is mandatory to continue. </br> \
|
||||
Please set Last Name for Contact <a href='#Form/Contact/{0}'>{1}</a>"
|
||||
).format(contact_name, contact_name))
|
||||
if not contact.phone:
|
||||
contact.phone = contact.mobile_no
|
||||
return contact
|
||||
|
||||
def match_parcel_service_type_carrier(shipment_prices, reference):
|
||||
for idx, prices in enumerate(shipment_prices):
|
||||
service_name = match_parcel_service_type_alias(prices.get(reference[0]), prices.get(reference[1]))
|
||||
is_preferred = frappe.db.get_value('Parcel Service Type', service_name, 'show_in_preferred_services_list')
|
||||
shipment_prices[idx].service_name = service_name
|
||||
shipment_prices[idx].is_preferred = is_preferred
|
||||
return shipment_prices
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_company_contact(user):
|
||||
contact = frappe.db.get_value('User', user, [
|
||||
@ -295,4 +54,4 @@ def get_company_contact(user):
|
||||
], as_dict=1)
|
||||
if not contact.phone:
|
||||
contact.phone = contact.mobile_no
|
||||
return contact
|
||||
return contact
|
||||
|
@ -1,74 +0,0 @@
|
||||
{% if (data.preferred_services.length || data.other_services.length) { %}
|
||||
<div style="overflow-x:scroll; height: 550px;">
|
||||
<h5>{{ __("Preferred Services") }}</h5>
|
||||
{% if (data.preferred_services.length) { %}
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead class="grid-heading-row">
|
||||
<tr style="text-align: center">
|
||||
{% for (var i = 0; i < header_columns.length; i++) { %}
|
||||
<th style="text-align: center">{{ header_columns[i] }}</th>
|
||||
{% } %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for (var i = 0; i < data.preferred_services.length; i++) { %}
|
||||
<tr style="text-align: center" id="data-list-{{i}}">
|
||||
<td style="width:20%">{{ data.preferred_services[i].service_provider }}</td>
|
||||
<td style="width:20%">{{ data.preferred_services[i].carrier }}</td>
|
||||
<td style="width:40%">{{ data.preferred_services[i].service_name }}</td>
|
||||
<td style="width:10%">{{ format_currency(data.preferred_services[i].total_price, 'EUR', 2) }}</td>
|
||||
<td style="width:10%">
|
||||
<button id="data-list-{{i}}" onclick='cur_frm.select_row({{JSON.stringify(data.preferred_services[i])}})' type="button" class="btn btn-primary">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% } else { %}
|
||||
<div><strong class="text-muted">{{ __("No Preferred Services Available") }}</strong></div>
|
||||
{% } %}
|
||||
<h5>{{ __("Other Services") }}</h5>
|
||||
{% if (data.other_services.length) { %}
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead class="grid-heading-row">
|
||||
<tr style="text-align: center">
|
||||
{% for (var i = 0; i < header_columns.length; i++) { %}
|
||||
<th style="text-align: center" >{{ header_columns[i] }}</th>
|
||||
{% } %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for (var i = 0; i < data.other_services.length; i++) { %}
|
||||
<tr style="text-align: center" id="data-list-{{i}}">
|
||||
<td style="width:20%">{{ data.other_services[i].service_provider }}</td>
|
||||
<td style="width:20%">{{ data.other_services[i].carrier }}</td>
|
||||
<td style="width:40%">{{ data.other_services[i].service_name }}</td>
|
||||
<td style="width:10%">{{ format_currency(data.other_services[i].total_price, 'EUR', 2) }}</td>
|
||||
<td style="width:10%">
|
||||
<button id="data-list-{{i}}" onclick='cur_frm.select_row({{JSON.stringify(data.other_services[i])}})' type="button" class="btn btn-primary">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% } else { %}
|
||||
<div><strong class="text-muted">{{ __("No Services Available") }}</strong></div>
|
||||
{% } %}
|
||||
</div>
|
||||
{% } else { %}
|
||||
<div><strong class="text-muted">{{ __("No Services Available") }}</strong></div>
|
||||
{% } %}
|
||||
|
||||
<style type="text/css" media="screen">
|
||||
.modal-dialog {
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.table > tbody > tr > td, .table > tfoot > tr > td {
|
||||
padding: 4px;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user