Order ack if sales order saved or submitted

main
vrashank 10 months ago
parent 464b59bb51
commit c37513df2e

@ -1,7 +1,7 @@
import frappe import frappe
SALES_ORDER_ACKNOWLEDGEMENT_URL = "https://api.spscommerce.com/transactions/v5/" SALES_ORDER_ACKNOWLEDGEMENT_URL = "https://api.spscommerce.com/transactions/v5/"
SPS_SO_URL = "https://api.spscommerce.com/transactions/v5/data/out/" # SPS_SO_URL = "https://api.spscommerce.com/transactions/v5/data/out/"
BASE_AUTH_URL = "https://auth.spscommerce.com" BASE_AUTH_URL = "https://auth.spscommerce.com"
def AUTHORIZATION_URL( def AUTHORIZATION_URL(
audience: str, audience: str,

@ -1,5 +1,129 @@
{ {
"custom_fields": [ "custom_fields": [
{
"_assign": null,
"_comments": null,
"_liked_by": null,
"_user_tags": null,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"creation": "2025-04-03 23:32:49.326476",
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"dt": "SPS Integration Settings",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "custom_order_acknowledgement_url",
"fieldtype": "Data",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"idx": 25,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "custom_get_sales_order_url",
"is_system_generated": 0,
"is_virtual": 0,
"label": "Order Acknowledgement URL",
"length": 0,
"mandatory_depends_on": null,
"modified": "2025-04-03 23:32:49.326476",
"modified_by": "Administrator",
"module": null,
"name": "SPS Integration Settings-custom_order_acknowledgement_url",
"no_copy": 0,
"non_negative": 0,
"options": null,
"owner": "Administrator",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"show_dashboard": 0,
"sort_options": 0,
"translatable": 1,
"unique": 0,
"width": null
},
{
"_assign": null,
"_comments": null,
"_liked_by": null,
"_user_tags": null,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"creation": "2025-04-03 23:32:49.039907",
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"dt": "SPS Integration Settings",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "custom_get_sales_order_url",
"fieldtype": "Data",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"idx": 24,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "days",
"is_system_generated": 0,
"is_virtual": 0,
"label": "Get Sales Order URL",
"length": 0,
"mandatory_depends_on": null,
"modified": "2025-04-03 23:32:49.039907",
"modified_by": "Administrator",
"module": null,
"name": "SPS Integration Settings-custom_get_sales_order_url",
"no_copy": 0,
"non_negative": 0,
"options": null,
"owner": "Administrator",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"show_dashboard": 0,
"sort_options": 0,
"translatable": 1,
"unique": 0,
"width": null
},
{ {
"_assign": null, "_assign": null,
"_comments": null, "_comments": null,
@ -25,7 +149,7 @@
"hide_border": 0, "hide_border": 0,
"hide_days": 0, "hide_days": 0,
"hide_seconds": 0, "hide_seconds": 0,
"idx": 15, "idx": 17,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_global_search": 0, "in_global_search": 0,
@ -87,7 +211,7 @@
"hide_border": 0, "hide_border": 0,
"hide_days": 0, "hide_days": 0,
"hide_seconds": 0, "hide_seconds": 0,
"idx": 14, "idx": 16,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_global_search": 0, "in_global_search": 0,
@ -149,14 +273,14 @@
"hide_border": 0, "hide_border": 0,
"hide_days": 0, "hide_days": 0,
"hide_seconds": 0, "hide_seconds": 0,
"idx": 13, "idx": 14,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_preview": 0, "in_preview": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"insert_after": "expires_on", "insert_after": "default_tab",
"is_system_generated": 0, "is_system_generated": 0,
"is_virtual": 0, "is_virtual": 0,
"label": "Defaults", "label": "Defaults",
@ -196,7 +320,7 @@
"_comments": null, "_comments": null,
"_liked_by": null, "_liked_by": null,
"_user_tags": null, "_user_tags": null,
"creation": "2025-02-02 20:31:11.118583", "creation": "2025-04-03 23:32:48.857025",
"default_value": null, "default_value": null,
"doc_type": "SPS Integration Settings", "doc_type": "SPS Integration Settings",
"docstatus": 0, "docstatus": 0,
@ -204,7 +328,7 @@
"field_name": null, "field_name": null,
"idx": 0, "idx": 0,
"is_system_generated": 0, "is_system_generated": 0,
"modified": "2025-02-02 20:31:11.118583", "modified": "2025-04-03 23:32:48.857025",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": null, "module": null,
"name": "SPS Integration Settings-main-field_order", "name": "SPS Integration Settings-main-field_order",
@ -212,7 +336,7 @@
"property": "field_order", "property": "field_order",
"property_type": "Data", "property_type": "Data",
"row_name": null, "row_name": null,
"value": "[\"settings_name\", \"authenticate\", \"refresh_access_token\", \"redirect_uri\", \"sps_api_uri\", \"enabled\", \"column_break_ynjw\", \"client_secret\", \"client_id\", \"state\", \"access_token\", \"refresh_token\", \"expires_on\", \"defaults_tab\", \"default_uom\", \"default_item_group\"]" "value": "[\"settings_name\", \"authenticate\", \"refresh_access_token\", \"redirect_uri\", \"sps_api_uri\", \"enabled\", \"column_break_ynjw\", \"client_secret\", \"client_id\", \"state\", \"access_token\", \"refresh_token\", \"expires_on\", \"default_tab\", \"custom_defaults\", \"custom_default_uom\", \"custom_default_item_group\", \"default_uom\", \"default_item_group\", \"marketplace\", \"column_break_rxhv\", \"customer_type\", \"shipping_category\", \"days\", \"get_sales_order_url\", \"order_acknowledgement_url\", \"order_syncing_tab\", \"sync_start_date\", \"sync_orders\", \"section_break_lafq\", \"sync_duration\"]"
} }
], ],
"sync_on_migrate": 1 "sync_on_migrate": 1

@ -1,194 +1,4 @@
# import frappe
# import requests
# from .constants import SALES_ORDER_ACKNOWLEDGEMENT_URL
# def format_sales_order_ack(data: dict) -> dict:
# """
# Format sales order acknowledgement.
# Args:
# data (dict): Sales order payload.
# Returns:
# dict: A formatted sales order acknowledgement.
# """
# try:
# order_header = data.get("Header", {}).get("OrderHeader", {})
# line_item = data.get("LineItem", [])
# if not order_header or not line_item:
# frappe.log_error(title="Invalid Order Payload", message=str(data))
# print("Invalid order payload received.")
# return {}
# acknowledgement_payload = {
# "Header": {
# "OrderHeader": {
# "TradingPartnerId": order_header.get("TradingPartnerId", ""),
# "PurchaseOrderNumber": order_header.get("PurchaseOrderNumber"),
# "TsetPurposeCode": "00",
# "AcknowledgementType": "AK",
# "AcknowledgementNumber": "",
# "AcknowledgementDate": order_header.get("PurchaseOrderDate"),
# },
# "Dates": [
# {
# "DateTimeQualifier": "064",
# "Date": order_header.get("PurchaseOrderDate")
# }
# ]
# },
# "LineItem": [
# {
# "OrderLine": {
# "LineSequenceNumber": item.get("OrderLine", {}).get("LineSequenceNumber"),
# "VendorPartNumber": item.get("OrderLine", {}).get("VendorPartNumber"),
# "ConsumerPackageCode": item.get("OrderLine", {}).get("ConsumerPackageCode"),
# "OrderQty": item.get("OrderLine", {}).get("OrderQty"),
# "OrderQtyUOM": item.get("OrderLine", {}).get("OrderQtyUOM"),
# "PurchasePrice": item.get("OrderLine", {}).get("PurchasePrice"),
# },
# "LineItemAcknowledgement": [
# {
# "ItemStatusCode": "IA",
# "ItemScheduleQty": item.get("OrderLine", {}).get("OrderQty"),
# "ItemScheduleUOM": item.get("OrderLine", {}).get("OrderQtyUOM"),
# "ItemScheduleQualifier": "",
# "ItemScheduleDate": order_header.get("PurchaseOrderDate"),
# }
# ]
# }
# for item in line_item
# ]
# }
# print("Formatted Sales Order Acknowledgement Payload:", acknowledgement_payload)
# return acknowledgement_payload
# except Exception as e:
# frappe.log_error(title="SO ACK Payload Formatting Error", message=str(e))
# print(f"Error formatting payload: {str(e)}")
# return {}
# def sales_order_acknowledgement(data: dict):
# """Send Sales Order Acknowledgement."""
# try:
# print("Fetching SPS Integration Settings...")
# doc = frappe.get_doc("SPS Integration Settings", "Develop")
# access_token = doc.get_password("access_token")
# headers = {
# "Content-Type": "application/json; charset=utf-8",
# "Authorization": f"Bearer {access_token}"
# }
# formatted_data = format_sales_order_ack(data)
# if not formatted_data:
# print("Error: No data to send in Sales Order Acknowledgement.")
# return
# print("Sending Sales Order Acknowledgement...")
# response = requests.post(url=SALES_ORDER_ACKNOWLEDGEMENT_URL, headers=headers, json=formatted_data)
# print(f"Response Status Code: {response.status_code}")
# if response.status_code in [200, 201]:
# response_json = response.json()
# frappe.log_error(title="SO Acknowledgement Success", message=str(response_json))
# print("Sales Order Acknowledgement Successful:", response_json)
# else:
# frappe.log_error(title="SO Acknowledgement Failure", message=response.text)
# print("Sales Order Acknowledgement Failed:", response.text)
# except Exception as e:
# frappe.log_error(title="SO Acknowledgement Error", message=str(e))
# print(f"Error in Sales Order Acknowledgement: {str(e)}")
# data = {
# "Meta" : {
# "OrderManagement" : "SA"
# },
# "Header" : {
# "OrderHeader" : {
# "TradingPartnerId" : "0RXALLALPHARDGO",
# "PurchaseOrderNumber" : "WGE680227-29",
# "TsetPurposeCode" : "00",
# "PrimaryPOTypeCode" : "SA",
# "PurchaseOrderDate" : "2025-02-10",
# "Vendor" : "ALPHAR"
# },
# "Dates" : [ {
# "DateTimeQualifier" : "010",
# "Date" : "2025-02-28"
# }, {
# "DateTimeQualifier" : "001",
# "Date" : "2025-03-30"
# } ],
# "Contacts" : [ {
# "ContactTypeCode" : "BD",
# "ContactName" : "XAX XAX"
# } ],
# "Address" : [ {
# "AddressTypeCode" : "BT",
# "LocationCodeQualifier" : "92",
# "AddressLocationNumber" : "00",
# "AddressName" : "Worldwide Golf Enterprises",
# "Address1" : "1430 Village Way",
# "Address2" : "Suite J",
# "City" : "Santa Ana",
# "State" : "CA",
# "PostalCode" : "92705"
# }, {
# "AddressTypeCode" : "ST",
# "LocationCodeQualifier" : "92",
# "AddressLocationNumber" : "29",
# "AddressName" : "ROGER DUNN",
# "Address1" : "11849 Foothill Blvd. Ste. D",
# "City" : "RANCHO CUCAMONGA",
# "State" : "CA",
# "PostalCode" : "91730",
# "Country" : "US"
# } ],
# "Notes" : [ {
# "Note" : "https://commerce.spscommerce.com/fulfillment/redirect/?searchType=exact&documentType=Order&keyword=WGE680227-29"
# }, {
# "Note" : "https: //commerce.spscommerce.com/fulfillment-monitor"
# } ]
# },
# "LineItem" : [ {
# "OrderLine" : {
# "LineSequenceNumber" : "1",
# "VendorPartNumber" : "CYBERE-BL",
# "ConsumerPackageCode" : "849650001612",
# "OrderQty" : 1.0,
# "OrderQtyUOM" : "EA",
# "PurchasePrice" : 949.0
# },
# "ProductOrItemDescription" : [ {
# "ProductCharacteristicCode" : "08",
# "ProductDescription" : "CYBERCART"
# } ]
# } ],
# "Summary" : {
# "TotalAmount" : 949.0
# }
# }
import frappe
import requests import requests
import json
# SPS Commerce API URL (Updated)
SPS_API_URL = "https://api.spscommerce.com/transactions/v5/data/testin/"
import json import json
import frappe import frappe
from datetime import datetime, timedelta from datetime import datetime, timedelta
@ -299,13 +109,13 @@ def sales_order_acknowledgement(data: dict):
return return
# Debugging prints # Debugging prints
print("Final JSON Payload:", json.dumps(formatted_data, indent=2)) # print("Final JSON Payload:", json.dumps(formatted_data, indent=2))
print(f"Request URL: {SPS_API_URL}") # print(f"Request URL: {SPS_API_URL}")
print(f"Headers: {headers}") # print(f"Headers: {headers}")
print(f"Sending Request to SPS Commerce...") # print(f"Sending Request to SPS Commerce...")
# Corrected API request (Using json= instead of data=) # Corrected API request (Using json= instead of data=)
response = requests.post(url=SPS_API_URL, headers=headers, data=json.dumps(formatted_data)) response = requests.post(url=doc.custom_order_acknowledgement_url, headers=headers, data=json.dumps(formatted_data))
print(f"Response Status Code: {response.status_code}") print(f"Response Status Code: {response.status_code}")
print(f"Response Headers: {response.headers}") print(f"Response Headers: {response.headers}")

@ -8,7 +8,7 @@ from .orders_utills import (check_customer_if_exists,
create_customer_if_not_exists) create_customer_if_not_exists)
# from .order_acknowledgement import get_sales_order_pyload # from .order_acknowledgement import get_sales_order_pyload
from .validate_creds import validate_api_user from .validate_creds import validate_api_user
from .constants import SPS_SO_URL # from .constants import SPS_SO_URL
import requests import requests
from frappe.utils import get_datetime, now_datetime from frappe.utils import get_datetime, now_datetime
from .oauth import refresh_access_token from .oauth import refresh_access_token
@ -115,12 +115,13 @@ def get_sps_sales_order(doc: str):
response = requests.get(url=so_url, headers=headers) response = requests.get(url=so_url, headers=headers)
if response.status_code == 200: if response.status_code == 200:
create_sps_sales_order( sales_order = create_sps_sales_order(
data=response.json(), data=response.json(),
setting_doc=doc, setting_doc=doc,
path=path path=path
) )
sales_order_acknowledgement(data=response.json()) if frappe.db.exists("Sales Order", {"name": sales_order, "docstatus":1}):
sales_order_acknowledgement(data=response.json())
else: else:
failed_requests.append(so_url) failed_requests.append(so_url)
except requests.RequestException as e: except requests.RequestException as e:
@ -153,7 +154,7 @@ def retrieve_sps_order_urls(setting_doc_name: str) -> None:
"Authorization": f"Bearer {access_token}", "Authorization": f"Bearer {access_token}",
"Content-Type": "application/json" "Content-Type": "application/json"
} }
response = requests.get(url=SPS_SO_URL, response = requests.get(url=setting_doc.custom_get_sales_order_url,
headers=headers headers=headers
) )
if response.status_code == 200: if response.status_code == 200:
@ -182,7 +183,7 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
data (dict): Sales order payload. data (dict): Sales order payload.
setting_doc (str): SPS Integration Settings document. setting_doc (str): SPS Integration Settings document.
""" """
print("Initializing Sales Order creation...") # print("Initializing Sales Order creation...")
# Extract order details # Extract order details
order_header = data.get("Header", {}).get("OrderHeader", {}) order_header = data.get("Header", {}).get("OrderHeader", {})
@ -209,9 +210,9 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
# Check and create contact if not exists # Check and create contact if not exists
contact_name = check_and_create_contact(data, setting_doc) contact_name = check_and_create_contact(data, setting_doc)
print("") # print("")
if contact_name: # if contact_name:
print(f"Contact verified/created: {contact_name}") # print(f"Contact verified/created: {contact_name}")
# Create addresses if not exists # Create addresses if not exists
billing_address, shipping_address = create_address_contact(data, customer_name) billing_address, shipping_address = create_address_contact(data, customer_name)
@ -227,11 +228,11 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
if not marketplace_data: if not marketplace_data:
frappe.log_error("SPS Order Error", "No wholesale marketplace found.") frappe.log_error("SPS Order Error", "No wholesale marketplace found.")
print("No wholesale marketplace found. Aborting order creation.") # print("No wholesale marketplace found. Aborting order creation.")
return return
marketplace_name, series_name = marketplace_data[0] marketplace_name, series_name = marketplace_data[0]
print(f"Marketplace found: {marketplace_name}, Series: {series_name}") # print(f"Marketplace found: {marketplace_name}, Series: {series_name}")
# Create Sales Order # Create Sales Order
sales_order = frappe.new_doc("Sales Order") sales_order = frappe.new_doc("Sales Order")
@ -249,7 +250,7 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
if contact_name: if contact_name:
sales_order.contact_person = contact_name sales_order.contact_person = contact_name
print(f"Created Sales Order Document: {sales_order.customer}") # print(f"Created Sales Order Document: {sales_order.customer}")
# Adding items to the sales order # Adding items to the sales order
for item in data.get("LineItem", []): for item in data.get("LineItem", []):
@ -265,17 +266,17 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
item_row = create_sps_sales_order_item_row(sku, quantity, amount, uom, description, setting_doc) item_row = create_sps_sales_order_item_row(sku, quantity, amount, uom, description, setting_doc)
sales_order.append("items", item_row) sales_order.append("items", item_row)
print(f"Added item: {sku}, Quantity: {quantity}, Amount: {amount}") # print(f"Added item: {sku}, Quantity: {quantity}, Amount: {amount}")
try: try:
print("Saving and submitting Sales Order...") # print("Saving and submitting Sales Order...")
print(sales_order.__dict__) # Debugging # print(sales_order.__dict__) # Debugging
sales_order.save() sales_order.save()
sales_order.submit() sales_order.submit()
frappe.db.commit() frappe.db.commit()
return sales_order.name
print(f"Sales order successfully created and submitted: {sales_order.name}") # print(f"Sales order successfully created and submitted: {sales_order.name}")
except Exception as e: except Exception as e:
error_msg = frappe.get_traceback() error_msg = frappe.get_traceback()
@ -283,81 +284,8 @@ def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
title="Sales Order Creation Error", title="Sales Order Creation Error",
message=f"Marketplace: SPS\n\nTraceback:\n{error_msg}", message=f"Marketplace: SPS\n\nTraceback:\n{error_msg}",
) )
print(f"Error while creating sales order: {e}") # print(f"Error while creating sales order: {e}")
data = {
"Meta" : {
"OrderManagement" : "SA"
},
"Header" : {
"OrderHeader" : {
"TradingPartnerId" : "0RXALLALPHARDGO",
"PurchaseOrderNumber" : "WGE686124-176",
"TsetPurposeCode" : "00",
"PrimaryPOTypeCode" : "SA",
"PurchaseOrderDate" : "2025-02-27",
"Vendor" : "ALPHAR"
},
"Dates" : [ {
"DateTimeQualifier" : "010",
"Date" : "2025-02-27"
}, {
"DateTimeQualifier" : "001",
"Date" : "2025-03-27"
} ],
"Contacts" : [ {
"ContactTypeCode" : "BD",
"ContactName" : "Roland Anderson"
} ],
"Address" : [ {
"AddressTypeCode" : "BT",
"LocationCodeQualifier" : "92",
"AddressLocationNumber" : "00",
"AddressName" : "Worldwide Golf Enterprises",
"Address1" : "1430 Village Way",
"Address2" : "Suite J",
"City" : "Santa Ana",
"State" : "CA",
"PostalCode" : "92705"
}, {
"AddressTypeCode" : "ST",
"LocationCodeQualifier" : "92",
"AddressLocationNumber" : "176",
"AddressName" : "GOLF & SKI WAREHOUSE",
"Address1" : "290 PLAINFIELD ROAD",
"City" : "WEST LEBANON",
"State" : "NH",
"PostalCode" : "03784",
"Country" : "US"
} ],
"Notes" : [ {
"Note" : "https://commerce.spscommerce.com/fulfillment/redirect/?searchType=exact&documentType=Order&keyword=WGE686124-176"
}, {
"Note" : "https: //commerce.spscommerce.com/fulfillment-monitor"
} ]
},
"LineItem" : [ {
"OrderLine" : {
"LineSequenceNumber" : "1",
"VendorPartNumber" : "CYBERE-BL",
"ConsumerPackageCode" : "849650001612",
"OrderQty" : 6.0,
"OrderQtyUOM" : "EA",
"PurchasePrice" : 949.0
},
"ProductOrItemDescription" : [ {
"ProductCharacteristicCode" : "08",
"ProductDescription" : "CYBERCART"
} ]
} ],
"Summary" : {
"TotalAmount" : 5694.0
}
}
# Trigger the order processing
create_sps_sales_order(data, setting_doc="Develop", path="")
# from sps_integration.sps_integration import order_sync

Loading…
Cancel
Save