Order sycing functionality updated with filtering

main
vrashank 9 months ago
parent 863b28e98b
commit b34d72dedf

@ -0,0 +1,8 @@
// Copyright (c) 2025, UnifyXperts and contributors
// For license information, please see license.txt
// frappe.ui.form.on("Paths to Skip", {
// refresh(frm) {
// },
// });

@ -0,0 +1,45 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:file_path",
"creation": "2025-04-09 03:39:31.669681",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"file_path"
],
"fields": [
{
"fieldname": "file_path",
"fieldtype": "Data",
"label": "File Path",
"unique": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-04-09 03:42:04.355255",
"modified_by": "Administrator",
"module": "SPS Integration",
"name": "Paths to Skip",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

@ -0,0 +1,9 @@
# Copyright (c) 2025, UnifyXperts and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PathstoSkip(Document):
pass

@ -0,0 +1,9 @@
# Copyright (c) 2025, UnifyXperts and Contributors
# See license.txt
# import frappe
from frappe.tests.utils import FrappeTestCase
class TestPathstoSkip(FrappeTestCase):
pass

@ -103,10 +103,9 @@ def sales_order_acknowledgement(data: dict):
response = requests.post(url=doc.order_acknowledgement_url, headers=headers, data=json.dumps(formatted_data))
if response.status_code in [200, 201]:
response_json = response.json()
frappe.log_error(title="SO Acknowledgment Success", message=f"{response.text}")
else:
frappe.log_error(title="SO Acknowledgment Failure", message=f"{response.text}")
except Exception as e:
frappe.log_error(title="SO Acknowledgment Error", message=str(e))
frappe.log_error(title="SO Acknowledgment Error", message=str(frappe.get_traceback()))

@ -5,7 +5,9 @@ from .orders_utills import (check_customer_if_exists,
get_sps_market_place_order_ID,
create_sps_sales_order_item_row,
check_and_create_contact,
create_customer_if_not_exists)
create_customer_if_not_exists,
get_path_to_skip,
exclude_skipped_file_paths)
# from .order_acknowledgement import get_sales_order_pyload
from .validate_creds import validate_api_user
# from .constants import SPS_SO_URL
@ -62,6 +64,83 @@ def enqueue_sps_sync_order(doc:str):
frappe.log_error(title= "Enqueue failed",message =f"{frappe.get_traceback()}")
# @frappe.whitelist(allow_guest=True)
# def get_sps_sales_order(doc: str):
# """
# Calls the SPS API to retrieve a list of all Sales Order URLs.
# Iterates through the URLs, fetches the corresponding payloads,
# syncs them into ERPNext, and stores the Sales Order URL paths.
# Args:
# doc (str): The settings document.
# Returns:
# None
# """
# try:
# data = retrieve_sps_order_urls(setting_doc_name=doc)
# frappe.log_error(title="Get SPS Sales Order Polling", message=f"{data}")
# sales_orders = frappe.get_all("Sales Order", fields = ["name", "custom_sales_order_path"])
# filtered_sales_orders = {order["custom_sales_order_path"] for order in sales_orders if order["custom_sales_order_path"]}
# frappe.log_error(
# title = "Previously Synced Sales Order",
# message = f"{filtered_sales_orders}"
# )
# results = data.get("results", [])
# failed_requests = []
# skipped_sales_orders = []
# setting_doc = frappe.get_doc("SPS Integration Settings", doc)
# expires_on = get_datetime(setting_doc.expires_on)
# current_time = now_datetime()
# if expires_on <= current_time or (expires_on - current_time).total_seconds() <= 300:
# refresh_access_token(setting_doc_name=doc)
# access_token = setting_doc.get_password("access_token")
# else:
# access_token = setting_doc.get_password("access_token")
# headers = {
# "Authorization": f"Bearer {access_token}",
# "Content-Type": "application/json"
# }
# for record in results:
# so_url = record.get("url")
# path = record.get("path", "").split("/")[-1]
# if path in filtered_sales_orders:
# skipped_sales_orders.append(path)
# continue
# if so_url:
# try:
# response = requests.get(url=so_url, headers=headers)
# if response.status_code == 200:
# sales_order = create_sps_sales_order(
# data=response.json(),
# setting_doc=doc,
# path=path
# )
# if frappe.db.exists("Sales Order", {"name": sales_order, "docstatus":1}):
# sales_order_acknowledgement(data=response.json())
# else:
# failed_requests.append(so_url)
# except requests.RequestException as e:
# failed_requests.append(so_url)
# frappe.log_error(title="Request Error", message=str(e))
# api_info = {
# "Total Sales Order Payload": len(results),
# "Failed Requests": failed_requests
# }
# frappe.log_error(title="Skipped Synced Sales Order", message=f"{skipped_sales_orders}")
# frappe.log_error(title="API Detail Info", message=f"{api_info}")
# except Exception as e:
# frappe.log_error(title="Enqueuing Error", message=f"{frappe.get_traceback()}")
@frappe.whitelist(allow_guest=True)
def get_sps_sales_order(doc: str):
"""
@ -77,19 +156,10 @@ def get_sps_sales_order(doc: str):
"""
try:
data = retrieve_sps_order_urls(setting_doc_name=doc)
frappe.log_error(title="Get SPS Sales Order Polling", message=f"{data}")
sales_orders = frappe.get_all("Sales Order", fields = ["name", "custom_sales_order_path"])
filtered_sales_orders = {order["custom_sales_order_path"] for order in sales_orders if order["custom_sales_order_path"]}
frappe.log_error(
title = "Previously Synced Sales Order",
message = f"{filtered_sales_orders}"
)
results = data.get("results", [])
access_token = ""
failed_requests = []
skipped_sales_orders = []
setting_doc = frappe.get_doc("SPS Integration Settings", doc)
SPS_URL = setting_doc.get_sales_order_url
expires_on = get_datetime(setting_doc.expires_on)
current_time = now_datetime()
if expires_on <= current_time or (expires_on - current_time).total_seconds() <= 300:
@ -97,23 +167,19 @@ def get_sps_sales_order(doc: str):
access_token = setting_doc.get_password("access_token")
else:
access_token = setting_doc.get_password("access_token")
order_url_path = retrieve_sps_order_urls(setting_doc_name=doc).get("results", [])
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
for record in results:
so_url = record.get("url")
path = record.get("path", "").split("/")[-1]
if path in filtered_sales_orders:
skipped_sales_orders.append(path)
continue
if so_url:
# Filtered path url for sales order to avoid duplicates
filtered_url_path = exclude_skipped_file_paths(paths=[d.get("path").split("/")[-1] for d in order_url_path])
for path in filtered_url_path:
# path = record.get("path", "").split("/")[-1]
url = f"{SPS_URL}{path}"
if url:
try:
response = requests.get(url=so_url, headers=headers)
response = requests.get(url=url, headers=headers)
if response.status_code == 200:
sales_order = create_sps_sales_order(
data=response.json(),
@ -121,22 +187,25 @@ def get_sps_sales_order(doc: str):
path=path
)
if frappe.db.exists("Sales Order", {"name": sales_order, "docstatus":1}):
sales_order_acknowledgement(data=response.json())
# Once the sales order sync in ERPNext will ack the sales order
# sales_order_acknowledgement(data=response.json())
path_to_skip = frappe.new_doc("Paths to Skip")
path_to_skip.file_path = path
path_to_skip.save()
frappe.db.commit()
else:
failed_requests.append(so_url)
failed_requests.append(url)
except requests.RequestException as e:
failed_requests.append(so_url)
frappe.log_error(title="Request Error", message=str(e))
api_info = {
"Total Sales Order Payload": len(results),
"Failed Requests": failed_requests
"Total sales order payload": len(filtered_url_path),
"Failed sales order": failed_requests
}
frappe.log_error(title="Skipped Synced Sales Order", message=f"{skipped_sales_orders}")
frappe.log_error(title="API Detail Info", message=f"{api_info}")
except Exception as e:
frappe.log_error(title="Enqueuing Error", message=f"{frappe.get_traceback()}")
frappe.log_error(title="Error while sales order sycing", message=f"{frappe.get_traceback()}")
# start_date: str will add later
def retrieve_sps_order_urls(setting_doc_name: str) -> None:
@ -241,7 +310,8 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
# Adding items to the sales order
for item in data.get("LineItem", []):
line_item = item.get("OrderLine", {})
sku = line_item.get("VendorPartNumber") or line_item.get("BuyerPartNumber")
# sku = line_item.get("VendorPartNumber") or line_item.get("BuyerPartNumber")
sku = line_item.get("VendorPartNumber")
quantity = line_item.get("OrderQty", 0)
uom = line_item.get("OrderQtyUOM")
amount = line_item.get("PurchasePrice", 0.0)

@ -263,3 +263,31 @@ def create_customer_if_not_exists(data: dict, setting_doc: str) -> str:
return doc.name
def get_path_to_skip():
"""Function to get all paths to skip"""
return frappe.get_all("Paths to Skip", pluck="file_path")
def exclude_skipped_file_paths(paths: List[str]) -> List[str]:
"""
Excludes file paths that are marked as skipped in the 'File Skip List' doctype.
Args:
paths (List[str]): List of file paths to filter.
Returns:
List[str]: Filtered list with skipped paths removed.
"""
try:
skipped_set = set(get_path_to_skip())
filtered_paths = [path for path in paths if path not in skipped_set]
frappe.log_error(
title="Exclude skipped file paths",
message=f"Skipped Paths: {skipped_set}\nFiltered Paths: {filtered_paths}"
)
return filtered_paths
except Exception as e:
frappe.log_error(
title="Error while excluding skipped file paths",
message=frappe.get_traceback()
)
return []
Loading…
Cancel
Save