You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
7.8 KiB
Python
177 lines
7.8 KiB
Python
import requests
|
|
import json
|
|
import frappe
|
|
from datetime import datetime, timedelta
|
|
from frappe.utils import get_datetime, now_datetime
|
|
from .oauth import refresh_access_token
|
|
from frappe.utils import nowtime
|
|
|
|
def format_sales_order_ack(data: dict, schedule_shipped_date: str, ack_type: str) -> dict:
|
|
"""
|
|
Format sales order acknowledgment for SPS Commerce API.
|
|
|
|
Args:
|
|
data (dict): Sales order payload.
|
|
|
|
Returns:
|
|
dict: A formatted sales order acknowledgment.
|
|
"""
|
|
try:
|
|
order_header = data.get("Header", {}).get("OrderHeader", {})
|
|
line_items = data.get("LineItem", [])
|
|
|
|
if not order_header or not line_items:
|
|
frappe.log_error(title="Invalid Order Payload", message=str(data))
|
|
return {}
|
|
|
|
purchase_order_date_str = order_header.get("PurchaseOrderDate", "")
|
|
try:
|
|
purchase_order_date = datetime.strptime(purchase_order_date_str, "%Y-%m-%d")
|
|
acknowledgment_date = (purchase_order_date + timedelta(days=1)).strftime("%Y-%m-%d")
|
|
except ValueError:
|
|
print("f")
|
|
# acknowledgment_date = (datetime.utcnow() + timedelta(days=1)).strftime("%Y-%m-%d")
|
|
acknowledgement_payload = {
|
|
"meta": {
|
|
"transactionType": "855"
|
|
},
|
|
"Header": {
|
|
"OrderHeader": {
|
|
"TradingPartnerId": order_header.get("TradingPartnerId", ""),
|
|
"PurchaseOrderNumber": order_header.get("PurchaseOrderNumber"),
|
|
"AcknowledgmentType": ack_type,
|
|
"AcknowledgmentDate": acknowledgment_date,
|
|
"PurchaseOrderDate": purchase_order_date_str,
|
|
"Vendor": order_header.get("Vendor")
|
|
},
|
|
|
|
},
|
|
"Dates" : [ {
|
|
"DateTimeQualifier" : "068",
|
|
"Date" : schedule_shipped_date,
|
|
# "Time" : "14:22:14"
|
|
"Time" : nowtime().split('.')[0]
|
|
} ],
|
|
"lineItems": [
|
|
{
|
|
"lineSequenceNumber": item.get("OrderLine", {}).get("LineSequenceNumber"),
|
|
"vendorPartNumber": item.get("OrderLine", {}).get("VendorPartNumber"),
|
|
"orderQty": item.get("OrderLine", {}).get("OrderQty"),
|
|
"orderQtyUOM": item.get("OrderLine", {}).get("OrderQtyUOM"),
|
|
"purchasePrice": item.get("OrderLine", {}).get("PurchasePrice"),
|
|
"acknowledgmentStatus": "IA",
|
|
"lineItemAcknowledgement": [
|
|
{
|
|
"ItemStatusCode": "IA",
|
|
"ItemScheduleQty": item.get("OrderLine", {}).get("OrderQty", 0),
|
|
"ItemScheduleUOM": item.get("OrderLine", {}).get("OrderQtyUOM", ""),
|
|
"ItemScheduleQualifier": "068",
|
|
"ItemScheduleDate": acknowledgment_date
|
|
}
|
|
]
|
|
}
|
|
for item in line_items
|
|
],
|
|
"notes": [
|
|
{
|
|
"noteCode": "GEN",
|
|
"noteDescription": ""
|
|
}
|
|
],
|
|
"summary": {
|
|
"totalAmount": sum(
|
|
float(item.get("OrderLine", {}).get("PurchasePrice", 0) or 0) *
|
|
float(item.get("OrderLine", {}).get("OrderQty", 0) or 0)
|
|
for item in line_items
|
|
)
|
|
}
|
|
}
|
|
return acknowledgement_payload
|
|
|
|
except Exception as e:
|
|
frappe.log_error(title="SO ACK Payload Formatting Error", message=str(e))
|
|
return {}
|
|
|
|
|
|
|
|
def sales_order_acknowledgement(data: dict , path: str, schedule_shipped_date: str, ack_type:str):
|
|
"""Send Sales Order Acknowledgment to SPS Commerce API."""
|
|
try:
|
|
doc = frappe.get_doc("SPS Integration Settings", {"enabled":1})
|
|
access_token = doc.get_password("access_token")
|
|
|
|
headers = {
|
|
"Content-Type": "application/octet-stream",
|
|
"Authorization": f"Bearer {access_token}"
|
|
}
|
|
|
|
formatted_data = format_sales_order_ack(data, schedule_shipped_date, ack_type)
|
|
|
|
if not formatted_data:
|
|
return
|
|
url = f"{doc.order_acknowledgement_url}ACK_" + path.split("_")[1]
|
|
response = requests.post(url=url, headers=headers, data=json.dumps(formatted_data))
|
|
print(response)
|
|
if response.status_code in [200, 201]:
|
|
frappe.log_error(title="SO Acknowledgment Success", message=f"{response.text}")
|
|
else:
|
|
frappe.log_error(title="SO Acknowledgment Failure", message=f"{response.text}")
|
|
return response.json()
|
|
except Exception as e:
|
|
frappe.log_error(title="SO Acknowledgment Error", message=str(frappe.get_traceback()))
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True)
|
|
def submit_order_acknowledgement(path: str, schedule_shipped_date: str, ack_type: str, sales_order: str):
|
|
"""
|
|
Acknowledge the sales order
|
|
args:
|
|
path (str): ID for sales order to get payload from sps
|
|
schedule_shipped_date (str): Date for ack order
|
|
ack_type (str): Ack Type
|
|
returns:
|
|
Returns the ack sales order ID
|
|
"""
|
|
try:
|
|
doc = frappe.get_doc("SPS Integration Settings", {"enabled":1})
|
|
url = f"{doc.get_sales_order_url}/{path}"
|
|
expires_on = get_datetime(doc.expires_on)
|
|
current_time = now_datetime()
|
|
access_token = ""
|
|
|
|
if expires_on <= current_time or (expires_on - current_time).total_seconds() <= 300:
|
|
refresh_access_token(setting_doc_name=doc.name)
|
|
access_token = doc.get_password("access_token")
|
|
frappe.log_error("SPS Token Refresh", "Token refreshed")
|
|
else:
|
|
access_token = doc.get_password("access_token")
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {access_token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
response = requests.get(url=url, headers=headers)
|
|
if response.status_code == 200:
|
|
frappe.log_error(title="Payload for Ord ACK",message=f"{response.json()}")
|
|
formatted_data = format_sales_order_ack(response.json(),schedule_shipped_date, ack_type)
|
|
frappe.log_error(title="Formatted SO Ack Payload", message=f"{formatted_data}")
|
|
# Sales order ack functionality
|
|
ack_response = sales_order_acknowledgement(data=formatted_data,path=path, schedule_shipped_date=schedule_shipped_date, ack_type=ack_type)
|
|
# ack_response = {
|
|
# "path":"/in/ACK_a86e370c-43b9-3db1-b6bd-6289a132448f}-d76e3c43e0024359960669e9855509ce.dat",
|
|
# "url":"https://api.spscommerce.com/transactions/v5/data/in/ACK_a86e370c-43b9-3db1-b6bd-6289a132448f}-d76e3c43e0024359960669e9855509ce.dat"}
|
|
if ack_response:
|
|
ack_path = ack_response.get("path")
|
|
if frappe.db.exists("Sales Order", {"name": sales_order, "docstatus": 1}):
|
|
so_doc = frappe.get_doc("Sales Order", sales_order)
|
|
so_doc.custom_sales_order_ack_path = ack_path
|
|
so_doc.save()
|
|
frappe.db.commit()
|
|
frappe.log_error(title="Sales order ack path", message=f"{ack_path}")
|
|
else:
|
|
frappe.log_error(title="Payload for Ord ACK error",message=f"{response.json()}")
|
|
frappe.log_error(title="Testing functionality order ack", message=f"Order Ack Required Stuff: {path}\\n{schedule_shipped_date}\\n{ack_type}")
|
|
except Exception as e:
|
|
# frappe.log_error(title="Error while ack the order through button", message=f"{str(e)}")
|
|
frappe.log_error(title="Error while ack the order through button", message=str(frappe.get_traceback())) |