diff --git a/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.js b/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.js index 601dbbf..1b2ddc3 100644 --- a/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.js +++ b/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.js @@ -1,8 +1,7 @@ // Copyright (c) 2020, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('LetMeShip', { +frappe.ui.form.on("LetMeShip", { // refresh: function(frm) { - // } }); diff --git a/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.py b/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.py index fbbfd4b..d0bb3bb 100644 --- a/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.py +++ b/erpnext_shipping/erpnext_shipping/doctype/letmeship/letmeship.py @@ -28,13 +28,7 @@ def __init__(self, base_url: str, api_id: str, api_password: str): self.api_password = api_password self.api_id = api_id - def request( - self, - method: str, - endpoint: str, - json: dict | None = None, - params: dict | None = None - ): + def request(self, method: str, endpoint: str, json: dict | None = None, params: dict | None = None): """Make a request to LetMeShip API.""" response = requests.request( method, @@ -131,7 +125,7 @@ def create_shipment( pickup_date=pickup_date, service_info=service_info, ) - try: + try: response_data = self.request("POST", "shipments", json=payload) if "shipmentId" in response_data: shipment_amount = response_data["service"]["baseServiceDetails"]["priceInfo"]["totalPrice"] @@ -157,7 +151,9 @@ def get_awb_number(self, shipment_id: str): def get_label(self, shipment_id): try: - shipment_label_response_data = self.request("GET", f"shipments/{shipment_id}/documents", params={"types": "LABEL"}) + shipment_label_response_data = self.request( + "GET", f"shipments/{shipment_id}/documents", params={"types": "LABEL"} + ) if "documents" in shipment_label_response_data: for label in shipment_label_response_data["documents"]: if "data" in label: @@ -337,5 +333,5 @@ def get_letmeship_utils() -> "LetMeShipUtils": return LetMeShipUtils( base_url=TEST_BASE_URL if settings.use_test_environment else PROD_BASE_URL, api_id=settings.api_id, - api_password=settings.get_password("api_password") + api_password=settings.get_password("api_password"), ) diff --git a/erpnext_shipping/erpnext_shipping/doctype/parcel_service/parcel_service.js b/erpnext_shipping/erpnext_shipping/doctype/parcel_service/parcel_service.js index 870a0c8..5af8c12 100644 --- a/erpnext_shipping/erpnext_shipping/doctype/parcel_service/parcel_service.js +++ b/erpnext_shipping/erpnext_shipping/doctype/parcel_service/parcel_service.js @@ -1,8 +1,7 @@ // Copyright (c) 2020, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('Parcel Service', { +frappe.ui.form.on("Parcel Service", { // refresh: function(frm) { - // } }); diff --git a/erpnext_shipping/erpnext_shipping/doctype/parcel_service_type/parcel_service_type.js b/erpnext_shipping/erpnext_shipping/doctype/parcel_service_type/parcel_service_type.js index 34a7a9c..0cbe88d 100644 --- a/erpnext_shipping/erpnext_shipping/doctype/parcel_service_type/parcel_service_type.js +++ b/erpnext_shipping/erpnext_shipping/doctype/parcel_service_type/parcel_service_type.js @@ -1,12 +1,12 @@ // Copyright (c) 2020, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('Parcel Service Type Alias', { - parcel_type_alias: function(frm, cdt, cdn) { +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'); + frappe.model.set_value(cdt, cdn, "parcel_service", frm.doc.parcel_service); + frm.refresh_field("parcel_service_type_alias"); } - } -}); \ No newline at end of file + }, +}); diff --git a/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.js b/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.js index 041b7a5..a62ea99 100644 --- a/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.js +++ b/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.js @@ -1,8 +1,7 @@ // Copyright (c) 2020, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('SendCloud', { +frappe.ui.form.on("SendCloud", { // refresh: function(frm) { - // } }); diff --git a/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.py b/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.py index f8620ec..d5eac61 100644 --- a/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.py +++ b/erpnext_shipping/erpnext_shipping/doctype/sendcloud/sendcloud.py @@ -17,6 +17,7 @@ WEIGHT_DECIMALS = 3 CURRENCY_DECIMALS = 2 + class SendCloud(Document): pass @@ -55,16 +56,10 @@ def get_available_services(self, delivery_address, parcels: list[dict]): available_services = [] for service in responses_dict.get("shipping_methods", []): - countries = [ - country - for country in service["countries"] - if country["iso_2"] == to_country - ] + countries = [country for country in service["countries"] if country["iso_2"] == to_country] if countries and check_weight(service, parcels): - available_service = self.get_service_dict( - service, countries[0], parcels - ) + available_service = self.get_service_dict(service, countries[0], parcels) available_services.append(available_service) return available_services @@ -266,6 +261,5 @@ def check_weight(service: dict, parcels: list[dict]) -> bool: max_weight_kg = float(service["max_weight"]) min_weight_kg = float(service["min_weight"]) return any( - max_weight_kg > parcel.get("weight") and min_weight_kg <= parcel.get("weight") - for parcel in parcels + max_weight_kg > parcel.get("weight") and min_weight_kg <= parcel.get("weight") for parcel in parcels ) diff --git a/erpnext_shipping/erpnext_shipping/patches/create_custom_delivery_note_fields.py b/erpnext_shipping/erpnext_shipping/patches/create_custom_delivery_note_fields.py index 40c0280..f1e87f2 100644 --- a/erpnext_shipping/erpnext_shipping/patches/create_custom_delivery_note_fields.py +++ b/erpnext_shipping/erpnext_shipping/patches/create_custom_delivery_note_fields.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2020, Frappe Technologies and contributors # For license information, please see license.txt -from __future__ import unicode_literals import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields diff --git a/erpnext_shipping/erpnext_shipping/shipping.py b/erpnext_shipping/erpnext_shipping/shipping.py index 176dcb8..96420a2 100644 --- a/erpnext_shipping/erpnext_shipping/shipping.py +++ b/erpnext_shipping/erpnext_shipping/shipping.py @@ -5,7 +5,10 @@ import frappe from erpnext.stock.doctype.shipment.shipment import get_company_contact -from erpnext_shipping.erpnext_shipping.doctype.letmeship.letmeship import LETMESHIP_PROVIDER, get_letmeship_utils +from erpnext_shipping.erpnext_shipping.doctype.letmeship.letmeship import ( + LETMESHIP_PROVIDER, + get_letmeship_utils, +) from erpnext_shipping.erpnext_shipping.doctype.sendcloud.sendcloud import SENDCLOUD_PROVIDER, SendCloudUtils from erpnext_shipping.erpnext_shipping.utils import ( get_address, @@ -71,10 +74,7 @@ def fetch_shipping_rates( if sendcloud_enabled and pickup_from_type == "Company": sendcloud = SendCloudUtils() sendcloud_prices = ( - sendcloud.get_available_services( - delivery_address=delivery_address, parcels=parcels - ) - or [] + sendcloud.get_available_services(delivery_address=delivery_address, parcels=parcels) or [] ) sendcloud_prices = match_parcel_service_type_carrier(sendcloud_prices, "carrier", "service_name") shipment_prices += sendcloud_prices diff --git a/erpnext_shipping/erpnext_shipping/utils.py b/erpnext_shipping/erpnext_shipping/utils.py index 6a6655f..a970e13 100644 --- a/erpnext_shipping/erpnext_shipping/utils.py +++ b/erpnext_shipping/erpnext_shipping/utils.py @@ -69,13 +69,17 @@ def get_contact(contact_name): return contact -def match_parcel_service_type_carrier(shipment_prices: list[dict], carrier_fieldname: str, service_fieldname: str): +def match_parcel_service_type_carrier( + shipment_prices: list[dict], carrier_fieldname: str, service_fieldname: str +): from erpnext_shipping.erpnext_shipping.doctype.parcel_service_type.parcel_service_type import ( match_parcel_service_type_alias, ) for idx, prices in enumerate(shipment_prices): - service_name = match_parcel_service_type_alias(prices.get(carrier_fieldname), prices.get(service_fieldname)) + service_name = match_parcel_service_type_alias( + prices.get(carrier_fieldname), prices.get(service_fieldname) + ) is_preferred = frappe.db.get_value( "Parcel Service Type", service_name, "show_in_preferred_services_list" ) @@ -89,9 +93,7 @@ def show_error_alert(action): log = frappe.log_error(title="Shipping Error") link_to_log = get_link_to_form("Error Log", log.name, "See what happened.") frappe.msgprint( - msg=_("An Error occurred while {0}. {1}").format(action, link_to_log), - indicator="orange", - alert=True + msg=_("An Error occurred while {0}. {1}").format(action, link_to_log), indicator="orange", alert=True ) diff --git a/erpnext_shipping/public/js/shipment.js b/erpnext_shipping/public/js/shipment.js index aa9dc55..3424eaa 100644 --- a/erpnext_shipping/public/js/shipment.js +++ b/erpnext_shipping/public/js/shipment.js @@ -1,36 +1,55 @@ // Copyright (c) 2020, Frappe and contributors // For license information, please see license.txt -frappe.ui.form.on('Shipment', { - refresh: function(frm) { +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() { + 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( + __("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() { - if (frm.doc.tracking_url) { - const urls = frm.doc.tracking_url.split(', '); - urls.forEach(url => window.open(url)); - } else { - let msg = __("Please complete Shipment (ID: {0}) on {1} and Update Tracking.", [frm.doc.shipment_id, frm.doc.service_provider]); - frappe.msgprint({message: msg, title: __("Incomplete Shipment")}); - } - }, __('View')); + frm.add_custom_button( + __("Track Status"), + function () { + if (frm.doc.tracking_url) { + const urls = frm.doc.tracking_url.split(", "); + urls.forEach((url) => window.open(url)); + } else { + let msg = __( + "Please complete Shipment (ID: {0}) on {1} and Update Tracking.", + [frm.doc.shipment_id, frm.doc.service_provider] + ); + frappe.msgprint({ message: msg, title: __("Incomplete Shipment") }); + } + }, + __("View") + ); } } }, - fetch_shipping_rates: function(frm) { + fetch_shipping_rates: function (frm) { if (!frm.doc.shipment_id) { frappe.call({ method: "erpnext_shipping.erpnext_shipping.shipping.fetch_shipping_rates", @@ -44,26 +63,30 @@ frappe.ui.form.on('Shipment', { parcels: 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, + 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 + value_of_goods: frm.doc.value_of_goods, }, - callback: function(r) { + callback: function (r) { if (r.message && r.message.length) { select_from_available_services(frm, r.message); + } else { + frappe.msgprint({ + message: __("No Shipment Services available"), + title: __("Note"), + }); } - else { - frappe.msgprint({message:__("No Shipment Services available"), title:__("Note")}); - } - } + }, }); - } - else { + } else { frappe.throw(__("Shipment already created")); } }, - print_shipping_label: function(frm) { + print_shipping_label: function (frm) { frappe.call({ method: "erpnext_shipping.erpnext_shipping.shipping.print_shipping_label", freeze: true, @@ -71,29 +94,28 @@ frappe.ui.form.on('Shipment', { args: { shipment: frm.doc.name, }, - callback: function(r) { + 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 = new Blob([array], { type: "application/pdf" }); const file_url = URL.createObjectURL(file); window.open(file_url); - } - else { + } else { if (Array.isArray(r.message)) { - r.message.forEach(url => window.open(url)); + r.message.forEach((url) => window.open(url)); } else { window.open(r.message); } } } - } + }, }); }, - update_tracking: function(frm, service_provider, shipment_id) { + update_tracking: function (frm, service_provider, shipment_id) { let delivery_notes = []; (frm.doc.shipment_delivery_note || []).forEach((d) => { delivery_notes.push(d.delivery_note); @@ -106,37 +128,40 @@ frappe.ui.form.on('Shipment', { shipment: frm.doc.name, shipment_id: shipment_id, service_provider: service_provider, - delivery_notes: delivery_notes + delivery_notes: delivery_notes, }, - callback: function(r) { + callback: function (r) { if (!r.exc) { frm.reload_doc(); } - } + }, }); - } + }, }); function select_from_available_services(frm, available_services) { - const arranged_services = available_services.reduce((prev, curr) => { - if (curr.is_preferred) { - prev.preferred_services.push(curr); - } else { - prev.other_services.push(curr); - } - return prev; - }, { preferred_services: [], other_services: [] }); + const arranged_services = available_services.reduce( + (prev, curr) => { + if (curr.is_preferred) { + prev.preferred_services.push(curr); + } else { + prev.other_services.push(curr); + } + return prev; + }, + { preferred_services: [], other_services: [] } + ); const dialog = new frappe.ui.Dialog({ title: __("Select Service to Create Shipment"), size: "extra-large", fields: [ { - fieldtype:'HTML', - fieldname:"available_services", - label: __('Available Services') - } - ] + fieldtype: "HTML", + fieldname: "available_services", + label: __("Available Services"), + }, + ], }); let delivery_notes = []; @@ -145,29 +170,20 @@ function select_from_available_services(frm, available_services) { }); dialog.fields_dict.available_services.$wrapper.html( - frappe.render_template( - 'shipment_service_selector', - { - 'header_columns': [ - __("Platform"), - __("Carrier"), - __("Parcel Service"), - __("Price"), - "" - ], - 'data': arranged_services - } - ) + frappe.render_template("shipment_service_selector", { + header_columns: [__("Platform"), __("Carrier"), __("Parcel Service"), __("Price"), ""], + data: arranged_services, + }) ); - dialog.$body.on('click', '.btn', function() { + dialog.$body.on("click", ".btn", function () { let service_type = $(this).attr("data-type"); let service_index = cint($(this).attr("id").split("-")[2]); let service_data = arranged_services[service_type][service_index]; frm.select_row(service_data); }); - frm.select_row = function(service_data){ + frm.select_row = function (service_data) { frappe.call({ method: "erpnext_shipping.erpnext_shipping.shipping.create_shipment", freeze: true, @@ -181,25 +197,35 @@ function select_from_available_services(frm, available_services) { 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, + 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, - delivery_notes: delivery_notes + delivery_notes: delivery_notes, }, - callback: function(r) { + callback: function (r) { if (!r.exc) { frm.reload_doc(); frappe.msgprint({ - message: __("Shipment {1} has been created with {0}.", [r.message.service_provider, r.message.shipment_id.bold()]), - title: __("Shipment Created"), - indicator: "green" - }); - frm.events.update_tracking(frm, r.message.service_provider, r.message.shipment_id); + message: __("Shipment {1} has been created with {0}.", [ + r.message.service_provider, + r.message.shipment_id.bold(), + ]), + title: __("Shipment Created"), + indicator: "green", + }); + frm.events.update_tracking( + frm, + r.message.service_provider, + r.message.shipment_id + ); } - } + }, }); dialog.hide(); }; dialog.show(); -} \ No newline at end of file +} diff --git a/erpnext_shipping/public/shipping.bundle.js b/erpnext_shipping/public/shipping.bundle.js index 21faff3..c0438a7 100644 --- a/erpnext_shipping/public/shipping.bundle.js +++ b/erpnext_shipping/public/shipping.bundle.js @@ -1 +1 @@ -import "./js/shipment_service_selector.html" +import "./js/shipment_service_selector.html";