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

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()))