SPS Integration
parent
b5d6a1edde
commit
464b59bb51
@ -0,0 +1,19 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
SALES_ORDER_ACKNOWLEDGEMENT_URL = "https://api.spscommerce.com/transactions/v5/"
|
||||||
|
SPS_SO_URL = "https://api.spscommerce.com/transactions/v5/data/out/"
|
||||||
|
BASE_AUTH_URL = "https://auth.spscommerce.com"
|
||||||
|
def AUTHORIZATION_URL(
|
||||||
|
audience: str,
|
||||||
|
client_id: str,
|
||||||
|
redirect_uri: str,
|
||||||
|
state: str,
|
||||||
|
response_type : str = "code",
|
||||||
|
scope="offline_access"
|
||||||
|
) -> str:
|
||||||
|
result = f"{BASE_AUTH_URL}/authorize?audience={audience}&client_id={client_id}&redirect_uri={redirect_uri}&response_type={response_type}&state={state}"
|
||||||
|
if scope != None:
|
||||||
|
result += f"&scope={scope}"
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"custom_fields": [],
|
||||||
|
"custom_perms": [],
|
||||||
|
"doctype": "Packed Item",
|
||||||
|
"links": [],
|
||||||
|
"property_setters": [
|
||||||
|
{
|
||||||
|
"_assign": null,
|
||||||
|
"_comments": null,
|
||||||
|
"_liked_by": null,
|
||||||
|
"_user_tags": null,
|
||||||
|
"creation": "2024-04-03 00:11:59.728639",
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Packed Item",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype_or_field": "DocField",
|
||||||
|
"field_name": "rate",
|
||||||
|
"idx": 0,
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2024-04-03 00:11:59.728639",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Packed Item-rate-read_only",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"property": "read_only",
|
||||||
|
"property_type": "Check",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sync_on_migrate": 1
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,715 @@
|
|||||||
|
{
|
||||||
|
"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-02-21 19:35:28.155094",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_shopify_fulfillment_line_item_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 10,
|
||||||
|
"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": "item_name",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Shopify Fulfillment Line Item Id",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2025-02-21 19:35:28.155094",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_shopify_fulfillment_line_item_id",
|
||||||
|
"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": "2024-09-09 00:45:56.927625",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_drop_ship_fee_breakdown",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"hidden": 1,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 46,
|
||||||
|
"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_shipping_fee_breakdown",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Drop Ship Fee Breakdown",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-09-09 00:45:56.927625",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_drop_ship_fee_breakdown",
|
||||||
|
"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": "2024-09-09 00:45:56.589647",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_shipping_fee_breakdown",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"hidden": 1,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 45,
|
||||||
|
"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_drop_ship_fee",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Shipping Fee Breakdown",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-09-09 00:45:56.589647",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_shipping_fee_breakdown",
|
||||||
|
"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": "2024-09-09 00:24:04.004874",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_drop_ship_fee",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"hidden": 1,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 44,
|
||||||
|
"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_shipping_fee",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Drop Ship Fee",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-09-09 00:24:04.004874",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_drop_ship_fee",
|
||||||
|
"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": 0,
|
||||||
|
"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": "2024-08-12 22:44:28.200605",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_shipping_fee",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"hidden": 1,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 43,
|
||||||
|
"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": "item_tax_template",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Shipping Fee",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-08-12 22:44:28.200605",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_shipping_fee",
|
||||||
|
"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": 0,
|
||||||
|
"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": "2024-08-05 22:28:23.425753",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_item_zone",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 76,
|
||||||
|
"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": "quotation_item",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Item Zone",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-08-05 22:28:23.425753",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_item_zone",
|
||||||
|
"no_copy": 0,
|
||||||
|
"non_negative": 0,
|
||||||
|
"options": "Freight Rates for Zone",
|
||||||
|
"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": 0,
|
||||||
|
"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": "2024-04-11 00:16:49.489163",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "marketplace_order_id",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 0,
|
||||||
|
"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": "accounting_dimensions_section",
|
||||||
|
"is_system_generated": 1,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Marketplace Order ID",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-11 00:16:49.489163",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-marketplace_order_id",
|
||||||
|
"no_copy": 0,
|
||||||
|
"non_negative": 0,
|
||||||
|
"options": "Marketplace Order ID",
|
||||||
|
"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": 0,
|
||||||
|
"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": "2024-04-11 00:12:53.971293",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "marketplace",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 0,
|
||||||
|
"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": "dimension_col_break",
|
||||||
|
"is_system_generated": 1,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Marketplace",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-11 00:12:53.971293",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-marketplace",
|
||||||
|
"no_copy": 0,
|
||||||
|
"non_negative": 0,
|
||||||
|
"options": "Marketplace",
|
||||||
|
"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": 0,
|
||||||
|
"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": "2024-04-07 22:33:32.121127",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": "item_code.custom_ecommerce_sku",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_sku",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 7,
|
||||||
|
"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_extensiv_order_item_id",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "SKU",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-07 22:33:32.121127",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_sku",
|
||||||
|
"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": 1,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"collapsible_depends_on": null,
|
||||||
|
"columns": 0,
|
||||||
|
"creation": "2024-04-04 22:28:52.823146",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_extensiv_order_item_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 6,
|
||||||
|
"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": "reserve_stock",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Extensiv Order Item Id",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-04 22:28:52.823146",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-custom_extensiv_order_item_id",
|
||||||
|
"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": "2024-04-03 03:31:54.410586",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Order Item",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "shopify_item_discount",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 27,
|
||||||
|
"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": "discount_and_margin",
|
||||||
|
"is_system_generated": 1,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Shopify Discount per unit",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-04 22:01:03.999479",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-shopify_item_discount",
|
||||||
|
"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": 1,
|
||||||
|
"read_only_depends_on": null,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"show_dashboard": 0,
|
||||||
|
"sort_options": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0,
|
||||||
|
"width": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_perms": [],
|
||||||
|
"doctype": "Sales Order Item",
|
||||||
|
"links": [],
|
||||||
|
"property_setters": [
|
||||||
|
{
|
||||||
|
"_assign": null,
|
||||||
|
"_comments": null,
|
||||||
|
"_liked_by": null,
|
||||||
|
"_user_tags": null,
|
||||||
|
"creation": "2025-02-21 19:35:27.983137",
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "Sales Order Item",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype_or_field": "DocType",
|
||||||
|
"field_name": null,
|
||||||
|
"idx": 0,
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2025-02-21 19:35:27.983137",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Order Item-main-field_order",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"property": "field_order",
|
||||||
|
"property_type": "Data",
|
||||||
|
"row_name": null,
|
||||||
|
"value": "[\"item_code\", \"customer_item_code\", \"ensure_delivery_based_on_produced_serial_no\", \"is_stock_item\", \"reserve_stock\", \"custom_extensiv_order_item_id\", \"custom_sku\", \"col_break1\", \"delivery_date\", \"item_name\", \"shopify_fulfillment_line_item_id\", \"section_break_5\", \"description\", \"item_group\", \"brand\", \"image_section\", \"image\", \"image_view\", \"quantity_and_rate\", \"qty\", \"stock_uom\", \"col_break2\", \"uom\", \"conversion_factor\", \"stock_qty\", \"stock_reserved_qty\", \"section_break_16\", \"price_list_rate\", \"base_price_list_rate\", \"discount_and_margin\", \"shopify_item_discount\", \"margin_type\", \"margin_rate_or_amount\", \"rate_with_margin\", \"column_break_19\", \"discount_percentage\", \"discount_amount\", \"base_rate_with_margin\", \"section_break_simple1\", \"rate\", \"amount\", \"item_tax_template\", \"custom_shipping_fee\", \"custom_drop_ship_fee\", \"custom_shipping_fee_breakdown\", \"custom_drop_ship_fee_breakdown\", \"col_break3\", \"base_rate\", \"base_amount\", \"pricing_rules\", \"stock_uom_rate\", \"is_free_item\", \"grant_commission\", \"section_break_24\", \"net_rate\", \"net_amount\", \"column_break_27\", \"base_net_rate\", \"base_net_amount\", \"billed_amt\", \"valuation_rate\", \"gross_profit\", \"drop_ship_section\", \"delivered_by_supplier\", \"supplier\", \"item_weight_details\", \"weight_per_unit\", \"total_weight\", \"column_break_21\", \"weight_uom\", \"warehouse_and_reference\", \"warehouse\", \"target_warehouse\", \"prevdoc_docname\", \"quotation_item\", \"custom_item_zone\", \"col_break4\", \"against_blanket_order\", \"blanket_order\", \"blanket_order_rate\", \"manufacturing_section_section\", \"bom_no\", \"planning_section\", \"projected_qty\", \"actual_qty\", \"ordered_qty\", \"planned_qty\", \"production_plan_qty\", \"column_break_69\", \"work_order_qty\", \"delivered_qty\", \"produced_qty\", \"returned_qty\", \"picked_qty\", \"shopping_cart_section\", \"additional_notes\", \"section_break_63\", \"page_break\", \"item_tax_rate\", \"transaction_date\", \"inter_transfer_reference_section\", \"material_request\", \"purchase_order\", \"column_break_89\", \"material_request_item\", \"purchase_order_item\", \"marketplace\", \"marketplace_order_id\"]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sync_on_migrate": 1
|
||||||
|
}
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
{
|
||||||
|
"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": "2024-04-11 00:16:50.544770",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Taxes and Charges",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "marketplace_order_id",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 0,
|
||||||
|
"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": "accounting_dimensions_section",
|
||||||
|
"is_system_generated": 1,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Marketplace Order ID",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-11 00:16:50.544770",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Taxes and Charges-marketplace_order_id",
|
||||||
|
"no_copy": 0,
|
||||||
|
"non_negative": 0,
|
||||||
|
"options": "Marketplace Order ID",
|
||||||
|
"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": 0,
|
||||||
|
"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": "2024-04-11 00:12:54.982066",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "Sales Taxes and Charges",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "marketplace",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 0,
|
||||||
|
"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": "dimension_col_break",
|
||||||
|
"is_system_generated": 1,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Marketplace",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2024-04-11 00:12:54.982066",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "Sales Taxes and Charges-marketplace",
|
||||||
|
"no_copy": 0,
|
||||||
|
"non_negative": 0,
|
||||||
|
"options": "Marketplace",
|
||||||
|
"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": 0,
|
||||||
|
"unique": 0,
|
||||||
|
"width": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_perms": [],
|
||||||
|
"doctype": "Sales Taxes and Charges",
|
||||||
|
"links": [],
|
||||||
|
"property_setters": [],
|
||||||
|
"sync_on_migrate": 1
|
||||||
|
}
|
||||||
@ -0,0 +1,219 @@
|
|||||||
|
{
|
||||||
|
"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-02-02 20:31:11.575254",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "SPS Integration Settings",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_default_item_group",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 15,
|
||||||
|
"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_default_uom",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Default Item Group",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2025-02-02 20:31:11.575254",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "SPS Integration Settings-custom_default_item_group",
|
||||||
|
"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-02-02 20:31:11.376121",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "SPS Integration Settings",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_default_uom",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 14,
|
||||||
|
"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_defaults",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Default UOM",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2025-02-02 20:31:11.376121",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "SPS Integration Settings-custom_default_uom",
|
||||||
|
"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-02-02 20:31:11.198473",
|
||||||
|
"default": null,
|
||||||
|
"depends_on": null,
|
||||||
|
"description": null,
|
||||||
|
"docstatus": 0,
|
||||||
|
"dt": "SPS Integration Settings",
|
||||||
|
"fetch_from": null,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
|
"fieldname": "custom_defaults",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"hide_border": 0,
|
||||||
|
"hide_days": 0,
|
||||||
|
"hide_seconds": 0,
|
||||||
|
"idx": 13,
|
||||||
|
"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": "expires_on",
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"is_virtual": 0,
|
||||||
|
"label": "Defaults",
|
||||||
|
"length": 0,
|
||||||
|
"mandatory_depends_on": null,
|
||||||
|
"modified": "2025-02-02 20:31:11.198473",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "SPS Integration Settings-custom_defaults",
|
||||||
|
"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": 0,
|
||||||
|
"unique": 0,
|
||||||
|
"width": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_perms": [],
|
||||||
|
"doctype": "SPS Integration Settings",
|
||||||
|
"links": [],
|
||||||
|
"property_setters": [
|
||||||
|
{
|
||||||
|
"_assign": null,
|
||||||
|
"_comments": null,
|
||||||
|
"_liked_by": null,
|
||||||
|
"_user_tags": null,
|
||||||
|
"creation": "2025-02-02 20:31:11.118583",
|
||||||
|
"default_value": null,
|
||||||
|
"doc_type": "SPS Integration Settings",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype_or_field": "DocType",
|
||||||
|
"field_name": null,
|
||||||
|
"idx": 0,
|
||||||
|
"is_system_generated": 0,
|
||||||
|
"modified": "2025-02-02 20:31:11.118583",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": null,
|
||||||
|
"name": "SPS Integration Settings-main-field_order",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"property": "field_order",
|
||||||
|
"property_type": "Data",
|
||||||
|
"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\"]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sync_on_migrate": 1
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2025, UnifyXperts and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on("SPS Integration Settings", {
|
||||||
|
authenticate(frm) {
|
||||||
|
frappe.call({
|
||||||
|
method: "sps_integration.sps_integration.oauth.authenticate",
|
||||||
|
args: {
|
||||||
|
setting_doc_name: frm.doc.name
|
||||||
|
},
|
||||||
|
callback: function(r){
|
||||||
|
if(!r.exc){
|
||||||
|
window.open(r.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refresh_access_token(frm){
|
||||||
|
frappe.call({
|
||||||
|
method: "sps_integration.sps_integration.oauth.refresh_access_token",
|
||||||
|
args: {
|
||||||
|
setting_doc_name: frm.doc.name
|
||||||
|
},
|
||||||
|
// callback: function(r){
|
||||||
|
// if(!r.exc){
|
||||||
|
// window.open(r.message)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -0,0 +1,202 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "field:settings_name",
|
||||||
|
"creation": "2025-01-08 01:28:09.776008",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"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",
|
||||||
|
"default_uom",
|
||||||
|
"default_item_group",
|
||||||
|
"marketplace",
|
||||||
|
"column_break_rxhv",
|
||||||
|
"customer_type",
|
||||||
|
"shipping_category",
|
||||||
|
"days",
|
||||||
|
"order_syncing_tab",
|
||||||
|
"sync_start_date",
|
||||||
|
"sync_orders",
|
||||||
|
"section_break_lafq",
|
||||||
|
"sync_duration"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "authenticate",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"label": "Authenticate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "access_token",
|
||||||
|
"fieldtype": "Password",
|
||||||
|
"label": "Access Token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "refresh_token",
|
||||||
|
"fieldtype": "Password",
|
||||||
|
"label": "Refresh Token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "expires_on",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"label": "Expires on"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "settings_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Settings Name",
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "enabled",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sps_api_uri",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "SPS API URI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "redirect_uri",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Redirect URI",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "client_id",
|
||||||
|
"fieldtype": "Password",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Client ID",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "client_secret",
|
||||||
|
"fieldtype": "Password",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Client Secret",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_ynjw",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "state",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "State"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "refresh_access_token",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"label": "Refresh Access Token"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "default_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "default_uom",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Default UOM",
|
||||||
|
"options": "UOM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "default_item_group",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Default Item Group",
|
||||||
|
"options": "Item Group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "marketplace",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Marketplace",
|
||||||
|
"options": "Marketplace"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_rxhv",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "customer_type",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Customer Type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shipping_category",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Shipping Category",
|
||||||
|
"options": "Shipping Category for Item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "days",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Days",
|
||||||
|
"non_negative": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "order_syncing_tab",
|
||||||
|
"fieldtype": "Tab Break",
|
||||||
|
"label": "Order Syncing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sync_start_date",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Sync Start Date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sync_orders",
|
||||||
|
"fieldtype": "Button",
|
||||||
|
"label": "Sync Orders"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_lafq",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "sync_duration",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Sync Duration"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2025-03-26 21:29:14.654011",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "SPS Integration",
|
||||||
|
"name": "SPS Integration Settings",
|
||||||
|
"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,10 @@
|
|||||||
|
# Copyright (c) 2025, UnifyXperts and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class SPSIntegrationSettings(Document):
|
||||||
|
|
||||||
|
pass
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# Copyright (c) 2025, UnifyXperts and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestSPSIntegrationSettings(FrappeTestCase):
|
||||||
|
pass
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
import requests
|
||||||
|
import frappe
|
||||||
|
from sps_integration.sps_integration.constants import AUTHORIZATION_URL
|
||||||
|
import secrets
|
||||||
|
import json
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def authenticate(setting_doc_name:str,**kwargs) -> None:
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Maintain Secret State
|
||||||
|
state = secrets.token_hex(10)
|
||||||
|
frappe.cache().set_value("state",state)
|
||||||
|
|
||||||
|
# Pre-requisites
|
||||||
|
setting_doc = frappe.get_doc("SPS Integration Settings",setting_doc_name)
|
||||||
|
setting_doc.state = state
|
||||||
|
setting_doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
return AUTHORIZATION_URL(
|
||||||
|
audience="api://api.spscommerce.com/",
|
||||||
|
client_id=setting_doc.get_password("client_id"),
|
||||||
|
redirect_uri = setting_doc.redirect_uri,
|
||||||
|
response_type = "code",
|
||||||
|
state = state,
|
||||||
|
scope = "offline_access"
|
||||||
|
)
|
||||||
|
|
||||||
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
def redirect_uri(**kwargs) -> None:
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
code = kwargs.get("code")
|
||||||
|
state = kwargs.get("state")
|
||||||
|
frappe.log_error(title="Code",message=f"{code},{state}")
|
||||||
|
if not state == frappe.cache().get_value("state"):
|
||||||
|
# frappe.respond_as_webpages()
|
||||||
|
return
|
||||||
|
setting_doc = frappe.get_doc("SPS Integration Settings",{"state":state})
|
||||||
|
# setting_doc.state = ""
|
||||||
|
# setting_doc.save()
|
||||||
|
# frappe.db.commit()
|
||||||
|
client_id = setting_doc.get_password('client_id')
|
||||||
|
client_secret = setting_doc.get_password('client_secret')
|
||||||
|
redirect_uri = setting_doc.redirect_uri
|
||||||
|
api_url = setting_doc.sps_api_uri
|
||||||
|
grant_type = "authorization_code"
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"client_id":client_id,
|
||||||
|
"client_secret":client_secret,
|
||||||
|
"grant_type":grant_type,
|
||||||
|
"code":code,
|
||||||
|
"redirect_uri":redirect_uri
|
||||||
|
}
|
||||||
|
url = api_url + "oauth/token"
|
||||||
|
response = requests.post(url = url,data=json.dumps(data),headers = headers)
|
||||||
|
if response.status_code in [200,201]:
|
||||||
|
response_json = response.json()
|
||||||
|
access_token = response_json.get("access_token")
|
||||||
|
refresh_token = response_json.get("refresh_token")
|
||||||
|
expires_in_sec = response_json.get('expires_in')
|
||||||
|
expires_in = frappe.utils.add_to_date(frappe.utils.now_datetime(),seconds=expires_in_sec)
|
||||||
|
setting_doc.access_token = access_token
|
||||||
|
setting_doc.refresh_token = refresh_token
|
||||||
|
setting_doc.expires_on = expires_in
|
||||||
|
setting_doc.state = ""
|
||||||
|
setting_doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
else:
|
||||||
|
frappe.log_error(title= 'SPS API Error',message =f'Error in Access Token API Call \n\n Response:{response.text}')
|
||||||
|
# return data
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def refresh_access_token(setting_doc_name:str) -> None:
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
setting_doc = frappe.get_doc("SPS Integration Settings",setting_doc_name)
|
||||||
|
client_id = setting_doc.get_password('client_id')
|
||||||
|
client_secret = setting_doc.get_password('client_secret')
|
||||||
|
refresh_token = setting_doc.get_password('refresh_token')
|
||||||
|
api_url = setting_doc.sps_api_uri
|
||||||
|
url = api_url + "oauth/token"
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"client_id":client_id,
|
||||||
|
"client_secret":client_secret,
|
||||||
|
"grant_type":"refresh_token",
|
||||||
|
"refresh_token":refresh_token,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(url = url,data=json.dumps(data),headers = headers)
|
||||||
|
frappe.log_error(title="Response",message=f"{response.text}")
|
||||||
|
if response.status_code in [200,201]:
|
||||||
|
response_json = response.json()
|
||||||
|
access_token = response_json.get("access_token")
|
||||||
|
expires_in_sec = response_json.get('expires_in')
|
||||||
|
expires_in = frappe.utils.add_to_date(frappe.utils.now_datetime(),seconds=expires_in_sec)
|
||||||
|
setting_doc.access_token = access_token
|
||||||
|
setting_doc.expires_on = expires_in
|
||||||
|
setting_doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
else:
|
||||||
|
frappe.log_error(title= 'SPS API Error',message =f'Error in Refreshing access Token \n\n Response:{response.text}')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,328 @@
|
|||||||
|
# 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 json
|
||||||
|
|
||||||
|
# SPS Commerce API URL (Updated)
|
||||||
|
SPS_API_URL = "https://api.spscommerce.com/transactions/v5/data/testin/"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import json
|
||||||
|
import frappe
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
def format_sales_order_ack(data: dict) -> 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))
|
||||||
|
print("Invalid order payload received.")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
# Get purchase order date and add 1 day
|
||||||
|
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:
|
||||||
|
# Default to current date +1 if purchaseOrderDate is invalid or missing
|
||||||
|
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": "AK",
|
||||||
|
"acknowledgmentDate": acknowledgment_date,
|
||||||
|
"purchaseOrderDate": purchase_order_date_str,
|
||||||
|
"vendor": order_header.get("Vendor")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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": "064",
|
||||||
|
"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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Formatted Sales Order Acknowledgment Payload:", json.dumps(acknowledgement_payload, indent=2))
|
||||||
|
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 Acknowledgment to SPS Commerce API."""
|
||||||
|
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/octet-stream",
|
||||||
|
"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 Acknowledgment.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Debugging prints
|
||||||
|
print("Final JSON Payload:", json.dumps(formatted_data, indent=2))
|
||||||
|
print(f"Request URL: {SPS_API_URL}")
|
||||||
|
print(f"Headers: {headers}")
|
||||||
|
print(f"Sending Request to SPS Commerce...")
|
||||||
|
|
||||||
|
# Corrected API request (Using json= instead of data=)
|
||||||
|
response = requests.post(url=SPS_API_URL, headers=headers, data=json.dumps(formatted_data))
|
||||||
|
|
||||||
|
print(f"Response Status Code: {response.status_code}")
|
||||||
|
print(f"Response Headers: {response.headers}")
|
||||||
|
print(f"Response Text: {response.text}")
|
||||||
|
|
||||||
|
if response.status_code in [200, 201]:
|
||||||
|
response_json = response.json()
|
||||||
|
frappe.log_error(title="SO Acknowledgment Success", message=f"{response.text}")
|
||||||
|
print("Sales Order Acknowledgment Successful:", response_json)
|
||||||
|
else:
|
||||||
|
frappe.log_error(title="SO Acknowledgment Failure", message=f"{response.text}")
|
||||||
|
print("Sales Order Acknowledgment Failed:", response.text)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
frappe.log_error(title="SO Acknowledgment Error", message=str(e))
|
||||||
|
print(f"Error in Sales Order Acknowledgment: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
# format_sales_order_ack(data)
|
||||||
|
# sales_order_acknowledgement(data)
|
||||||
@ -0,0 +1,363 @@
|
|||||||
|
import frappe
|
||||||
|
import datetime
|
||||||
|
from .orders_utills import (check_customer_if_exists,
|
||||||
|
create_address_contact,
|
||||||
|
get_sps_market_place_order_ID,
|
||||||
|
create_sps_sales_order_item_row,
|
||||||
|
check_and_create_contact,
|
||||||
|
create_customer_if_not_exists)
|
||||||
|
# from .order_acknowledgement import get_sales_order_pyload
|
||||||
|
from .validate_creds import validate_api_user
|
||||||
|
from .constants import SPS_SO_URL
|
||||||
|
import requests
|
||||||
|
from frappe.utils import get_datetime, now_datetime
|
||||||
|
from .oauth import refresh_access_token
|
||||||
|
from .order_acknowledgement import sales_order_acknowledgement
|
||||||
|
|
||||||
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
def web_hook():
|
||||||
|
api_key = frappe.get_request_header("API-Key")
|
||||||
|
api_secret = frappe.get_request_header("API-Secret")
|
||||||
|
|
||||||
|
auth_response = validate_api_user(api_key, api_secret)
|
||||||
|
|
||||||
|
if not auth_response:
|
||||||
|
return {"status": "failed", "message": "Unauthorized access"}
|
||||||
|
|
||||||
|
frappe.log_error(
|
||||||
|
title="SPS Web Hook",
|
||||||
|
message=f"Authenticated request from {frappe.session.user}: {frappe.request.get_data()}",
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"message": "Webhook received successfully"}
|
||||||
|
|
||||||
|
def sps_order_sync_job():
|
||||||
|
"""
|
||||||
|
Function to sync the job in background.
|
||||||
|
Args:
|
||||||
|
None
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
setting_doc_list = frappe.get_list("SPS Integration Settings",{"enabled":1})
|
||||||
|
for doc in setting_doc_list:
|
||||||
|
enqueue_sps_sync_order(doc['name'])
|
||||||
|
|
||||||
|
def enqueue_sps_sync_order(doc:str):
|
||||||
|
"""
|
||||||
|
Enqueues the SPS order synchronization functionality as a background job.
|
||||||
|
The job executes every 30 minutes to sync orders.
|
||||||
|
Args:
|
||||||
|
doc : str
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
frappe.enqueue(
|
||||||
|
"sps_integration.sps_integration.order_sync.get_sps_sales_order",
|
||||||
|
doc = doc,
|
||||||
|
timeout = 1800
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
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:
|
||||||
|
create_sps_sales_order(
|
||||||
|
data=response.json(),
|
||||||
|
setting_doc=doc,
|
||||||
|
path=path
|
||||||
|
)
|
||||||
|
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()}")
|
||||||
|
|
||||||
|
# start_date: str will add later
|
||||||
|
def retrieve_sps_order_urls(setting_doc_name: str) -> None:
|
||||||
|
"""
|
||||||
|
Calls the SPS API to retrieve a list of all URLs.
|
||||||
|
Args:
|
||||||
|
setting_doc_name (str): The name of the settings document.
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
setting_doc = frappe.get_doc("SPS Integration Settings", setting_doc_name)
|
||||||
|
access_token = setting_doc.get_password("access_token")
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {access_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
response = requests.get(url=SPS_SO_URL,
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
if response.status_code == 200:
|
||||||
|
frappe.log_error(
|
||||||
|
title="SPS Order Sync Success",
|
||||||
|
message=f"Response:\n{response.json()}"
|
||||||
|
)
|
||||||
|
return response.json()
|
||||||
|
frappe.log_error(
|
||||||
|
title="SPS Order API Call Failed",
|
||||||
|
message=f"Error: {response.status_code}\nResponse: {response.json()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
frappe.log_error(
|
||||||
|
title="SPS API error",
|
||||||
|
message=f"Traceback{frappe.get_traceback()}\n\nError:SPS Order API Call Error",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_sps_sales_order(data: dict, setting_doc: str, path: str) -> None:
|
||||||
|
"""
|
||||||
|
Processes an SPS sales order and syncs it to ERPNext.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (dict): Sales order payload.
|
||||||
|
setting_doc (str): SPS Integration Settings document.
|
||||||
|
"""
|
||||||
|
print("Initializing Sales Order creation...")
|
||||||
|
|
||||||
|
# Extract order details
|
||||||
|
order_header = data.get("Header", {}).get("OrderHeader", {})
|
||||||
|
po_no = order_header.get("PurchaseOrderNumber")
|
||||||
|
consumer_order_number = order_header.get("CustomerOrderNumber")
|
||||||
|
po_date = order_header.get("PurchaseOrderDate")
|
||||||
|
doc = frappe.get_doc("SPS Integration Settings", setting_doc)
|
||||||
|
# print(f"Extracted CustomerOrderNumber: {consumer_order_number}, Marketplace Order ID: {mo_id}, PO Date: {po_date}")
|
||||||
|
|
||||||
|
# Get delivery date
|
||||||
|
delivery_date = next(
|
||||||
|
(date.get("Date") for date in data.get("Header", {}).get("Dates", [])
|
||||||
|
if date.get("DateTimeQualifier") == "001"), None
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Extracted Delivery Date: {delivery_date}")
|
||||||
|
|
||||||
|
# Check if customer exists, otherwise create
|
||||||
|
_, customer_name = check_customer_if_exists(data)
|
||||||
|
# if not customer_exists:
|
||||||
|
# print("Customer not found, creating new customer...")
|
||||||
|
# customer_name = create_customer_if_not_exists(data, setting_doc)
|
||||||
|
# print(f"New customer created: {customer_name}")
|
||||||
|
|
||||||
|
# Check and create contact if not exists
|
||||||
|
contact_name = check_and_create_contact(data, setting_doc)
|
||||||
|
print("")
|
||||||
|
if contact_name:
|
||||||
|
print(f"Contact verified/created: {contact_name}")
|
||||||
|
|
||||||
|
# Create addresses if not exists
|
||||||
|
billing_address, shipping_address = create_address_contact(data, customer_name)
|
||||||
|
print(f"Billing Address: {billing_address}, Shipping Address: {shipping_address}")
|
||||||
|
|
||||||
|
# Get marketplace details
|
||||||
|
marketplace_data = frappe.get_list(
|
||||||
|
"Marketplace",
|
||||||
|
filters={"is_wholesale": 1},
|
||||||
|
fields=["name", "naming_series"],
|
||||||
|
as_list=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not marketplace_data:
|
||||||
|
frappe.log_error("SPS Order Error", "No wholesale marketplace found.")
|
||||||
|
print("No wholesale marketplace found. Aborting order creation.")
|
||||||
|
return
|
||||||
|
|
||||||
|
marketplace_name, series_name = marketplace_data[0]
|
||||||
|
print(f"Marketplace found: {marketplace_name}, Series: {series_name}")
|
||||||
|
|
||||||
|
# Create Sales Order
|
||||||
|
sales_order = frappe.new_doc("Sales Order")
|
||||||
|
sales_order.naming_series = series_name
|
||||||
|
sales_order.customer = customer_name
|
||||||
|
sales_order.custom_spss_purchase_order = po_no
|
||||||
|
sales_order.po_no = consumer_order_number
|
||||||
|
sales_order.transaction_date = datetime.datetime.strptime(po_date, "%Y-%m-%d").date()
|
||||||
|
# sales_order.marketplace_order_id = get_sps_market_place_order_ID(mo_id, setting_doc)
|
||||||
|
sales_order.marketplace = marketplace_name
|
||||||
|
sales_order.delivery_date = frappe.utils.add_to_date(po_date, days=doc.days)
|
||||||
|
sales_order.customer_address = billing_address
|
||||||
|
sales_order.shipping_address_name = shipping_address
|
||||||
|
sales_order.custom_sales_order_path = path
|
||||||
|
if contact_name:
|
||||||
|
sales_order.contact_person = contact_name
|
||||||
|
|
||||||
|
print(f"Created Sales Order Document: {sales_order.customer}")
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
quantity = line_item.get("OrderQty", 0)
|
||||||
|
uom = line_item.get("OrderQtyUOM")
|
||||||
|
amount = line_item.get("PurchasePrice", 0.0)
|
||||||
|
|
||||||
|
description = next(
|
||||||
|
(desc.get("ProductDescription") for desc in item.get("ProductOrItemDescription", [])), ""
|
||||||
|
)
|
||||||
|
|
||||||
|
item_row = create_sps_sales_order_item_row(sku, quantity, amount, uom, description, setting_doc)
|
||||||
|
sales_order.append("items", item_row)
|
||||||
|
print(f"Added item: {sku}, Quantity: {quantity}, Amount: {amount}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("Saving and submitting Sales Order...")
|
||||||
|
print(sales_order.__dict__) # Debugging
|
||||||
|
|
||||||
|
sales_order.save()
|
||||||
|
sales_order.submit()
|
||||||
|
frappe.db.commit()
|
||||||
|
|
||||||
|
print(f"Sales order successfully created and submitted: {sales_order.name}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = frappe.get_traceback()
|
||||||
|
frappe.log_error(
|
||||||
|
title="Sales Order Creation Error",
|
||||||
|
message=f"Marketplace: SPS\n\nTraceback:\n{error_msg}",
|
||||||
|
)
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,304 @@
|
|||||||
|
import frappe
|
||||||
|
from typing import List, Dict, Tuple, Optional
|
||||||
|
|
||||||
|
def check_customer_if_exists(data: dict) -> Tuple[bool, Optional[str]]:
|
||||||
|
"""Check if customer exists."""
|
||||||
|
order_header = data.get("Header", {}).get("OrderHeader", {})
|
||||||
|
trading_partner_id = order_header.get("TradingPartnerId")
|
||||||
|
if trading_partner_id:
|
||||||
|
customer = frappe.db.get_value("Customer", {"custom_trading_partner_id": trading_partner_id}, "name")
|
||||||
|
return bool(customer), customer
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
def check_address_exists_or_not(address: dict) -> Optional[str]:
|
||||||
|
"""Check if address exists and return its name."""
|
||||||
|
return frappe.db.exists("Address", {"address_line1": address.get("Address1")})
|
||||||
|
|
||||||
|
def check_postal_code_exists_or_not(address_name: str) -> bool:
|
||||||
|
"""Check if postal code exists for a given address."""
|
||||||
|
return bool(frappe.db.get_value("Address", address_name, "pincode"))
|
||||||
|
|
||||||
|
def create_or_update_address(address: dict, address_type: str, customer: str) -> str:
|
||||||
|
"""Create or update an address."""
|
||||||
|
address_name = check_address_exists_or_not(address)
|
||||||
|
postal_code = address.get("PostalCode")
|
||||||
|
|
||||||
|
if address_name:
|
||||||
|
# If address exists, ensure postal code is present only for shipping address
|
||||||
|
if address_type == "Shipping" and not check_postal_code_exists_or_not(address_name):
|
||||||
|
assert postal_code, f"Postal code is required for existing shipping address: {address_name}"
|
||||||
|
# Update address if postal code is provided in the payload
|
||||||
|
frappe.db.set_value("Address", address_name, "pincode", postal_code)
|
||||||
|
frappe.db.commit()
|
||||||
|
return address_name
|
||||||
|
|
||||||
|
# If address does not exist, ensure postal code is provided only for shipping address
|
||||||
|
if address_type == "Shipping":
|
||||||
|
assert postal_code, "Postal code is required for a new shipping address."
|
||||||
|
|
||||||
|
address_doc = frappe.new_doc("Address")
|
||||||
|
country = "United States" if address.get("Country") in ["US", "USA", "United States"] else address.get("Country")
|
||||||
|
|
||||||
|
|
||||||
|
address_doc.update({
|
||||||
|
"title": address.get("AddressName"),
|
||||||
|
"address_line1": address.get("Address1"),
|
||||||
|
"address_line2": address.get("Address2"),
|
||||||
|
"city": address.get("City"),
|
||||||
|
"state": address.get("State"),
|
||||||
|
"pincode": postal_code,
|
||||||
|
"country": country,
|
||||||
|
"address_type": address_type,
|
||||||
|
})
|
||||||
|
|
||||||
|
address_doc.append("links", {"link_doctype": "Customer", "link_name": customer})
|
||||||
|
address_doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
return address_doc.name
|
||||||
|
|
||||||
|
def create_address_contact(data: dict, customer: str) -> Tuple[str, str]:
|
||||||
|
"""Create or retrieve billing and shipping addresses for the customer."""
|
||||||
|
addresses = data.get("Header", {}).get("Address", [])
|
||||||
|
billing_address_name, shipping_address_name = None, None
|
||||||
|
|
||||||
|
for address in addresses:
|
||||||
|
address_type = address.get("AddressTypeCode")
|
||||||
|
if address_type == "BT":
|
||||||
|
billing_address_name = create_or_update_address(address, "Billing", customer)
|
||||||
|
elif address_type == "ST":
|
||||||
|
shipping_address_name = create_or_update_address(address, "Shipping", customer)
|
||||||
|
|
||||||
|
return billing_address_name, shipping_address_name
|
||||||
|
|
||||||
|
def get_sps_item_code_if_exists(order_uom: str, description: str, sku: str, setting_doc: str) -> str:
|
||||||
|
"""Get or create item code."""
|
||||||
|
if frappe.db.exists("Item", {"item_code": sku}):
|
||||||
|
return sku
|
||||||
|
|
||||||
|
item_doc = frappe.new_doc("Item")
|
||||||
|
item_doc.update({
|
||||||
|
"item_code": sku,
|
||||||
|
"item_name": description,
|
||||||
|
"stock_uom": get_uom(order_uom) if order_uom != "EA" and order_uom != None else frappe.get_value("SPS Integration Settings", setting_doc, "default_uom"),
|
||||||
|
"item_group": frappe.get_value("SPS Integration Settings", setting_doc, "default_item_group"),
|
||||||
|
"custom_item_shipping_category": frappe.get_value("SPS Integration Settings", setting_doc, "shipping_category")
|
||||||
|
})
|
||||||
|
|
||||||
|
try:
|
||||||
|
item_doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
except:
|
||||||
|
print(frappe.get_traceback())
|
||||||
|
|
||||||
|
return item_doc.name
|
||||||
|
|
||||||
|
def get_uom(uom: str) -> str:
|
||||||
|
"""Get or create UOM."""
|
||||||
|
if frappe.db.exists("UOM", uom):
|
||||||
|
return uom
|
||||||
|
|
||||||
|
new_uom = frappe.new_doc("UOM")
|
||||||
|
new_uom.uom_name = uom
|
||||||
|
new_uom.enabled = 1
|
||||||
|
new_uom.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
return uom
|
||||||
|
|
||||||
|
def create_sps_sales_order_item_row(sku: str, qty: int, amount: float, uom: str, description: str, setting_doc: str) -> Dict:
|
||||||
|
"""Create sales order item row."""
|
||||||
|
return {
|
||||||
|
"item_code": get_sps_item_code_if_exists(uom, description, sku, setting_doc),
|
||||||
|
"qty": qty,
|
||||||
|
"rate": amount,
|
||||||
|
"custom_sku": sku,
|
||||||
|
}
|
||||||
|
|
||||||
|
# def get_sps_market_place_order_ID(market_place_order_id: str, setting_doc: str) -> str:
|
||||||
|
# """Get or create Marketplace Order ID."""
|
||||||
|
# if frappe.db.exists("Marketplace Order ID", market_place_order_id):
|
||||||
|
# return market_place_order_id
|
||||||
|
|
||||||
|
# doc = frappe.new_doc("Marketplace Order ID")
|
||||||
|
# doc.update({
|
||||||
|
# "marketplace_order_id": market_place_order_id,
|
||||||
|
# "marketplace": frappe.get_value("SPS Integration Settings", setting_doc, "marketplace"),
|
||||||
|
# })
|
||||||
|
# doc.save()
|
||||||
|
# frappe.db.commit()
|
||||||
|
# return doc.name
|
||||||
|
|
||||||
|
|
||||||
|
def get_sps_market_place_order_ID(market_place_order_id: str, setting_doc: str) -> str:
|
||||||
|
"""Get or create Marketplace Order ID."""
|
||||||
|
|
||||||
|
# Skip if market_place_order_id is empty or None
|
||||||
|
if not market_place_order_id:
|
||||||
|
frappe.log_error(
|
||||||
|
title="Missing Marketplace Order ID",
|
||||||
|
message=f"Marketplace Order ID is missing for setting_doc: {setting_doc}. Skipping creation."
|
||||||
|
)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Check if the Marketplace Order ID already exists
|
||||||
|
if frappe.db.exists("Marketplace Order ID", market_place_order_id):
|
||||||
|
return market_place_order_id
|
||||||
|
|
||||||
|
# Create new Marketplace Order ID
|
||||||
|
try:
|
||||||
|
doc = frappe.new_doc("Marketplace Order ID")
|
||||||
|
doc.update({
|
||||||
|
"marketplace_order_id": market_place_order_id,
|
||||||
|
"marketplace": frappe.get_value("SPS Integration Settings", setting_doc, "marketplace"),
|
||||||
|
})
|
||||||
|
doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
return doc.name
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
frappe.log_error(title="Error Creating Marketplace Order ID", message=frappe.get_traceback())
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_link_row(docname: str, link_name: str) -> Dict:
|
||||||
|
"""Creates link doctype table row"""
|
||||||
|
row = {}
|
||||||
|
row["link_doctype"] = docname
|
||||||
|
row["link_name"] = link_name
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def check_and_create_contact(data, setting_doc):
|
||||||
|
"""Check if contacts exist, else create new contacts"""
|
||||||
|
print("Checking for contacts in data...")
|
||||||
|
|
||||||
|
addresses = data.get('Header', {}).get('Address', [])
|
||||||
|
contacts = None
|
||||||
|
|
||||||
|
|
||||||
|
for address in addresses:
|
||||||
|
if address.get("AddressTypeCode") == "BT" and address.get("Contacts"):
|
||||||
|
contacts = address["Contacts"]
|
||||||
|
print(f"Billing contact found: {contacts}")
|
||||||
|
break # Stop once billing contacts are found
|
||||||
|
|
||||||
|
if not contacts:
|
||||||
|
for address in addresses:
|
||||||
|
if address.get("AddressTypeCode") == "ST" and address.get("Contacts"):
|
||||||
|
contacts = address["Contacts"]
|
||||||
|
print(f"Shipping contact found: {contacts}")
|
||||||
|
break # Stop once shipping contacts are found
|
||||||
|
|
||||||
|
if not contacts:
|
||||||
|
print("No contacts available in the provided data.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Check if customer exists
|
||||||
|
print("Checking if customer exists...")
|
||||||
|
customer_exists, customer_name = check_customer_if_exists(data)
|
||||||
|
print(f"Customer Exists: {customer_exists}, Customer Name: {customer_name}")
|
||||||
|
|
||||||
|
if customer_exists:
|
||||||
|
# Check if the contact email already exists
|
||||||
|
email_id = contacts[0].get("PrimaryEmail", "")
|
||||||
|
print(f"Checking if contact email {email_id} exists in the system...")
|
||||||
|
if frappe.db.exists("Contact Email", {"email_id": email_id}):
|
||||||
|
contact_name = frappe.get_value(
|
||||||
|
"Contact Email", {"email_id": email_id}, "parent"
|
||||||
|
)
|
||||||
|
print(f"Existing contact found: {contact_name}")
|
||||||
|
else:
|
||||||
|
print("No existing contact found. Creating a new contact...")
|
||||||
|
|
||||||
|
doc = frappe.new_doc("Contact")
|
||||||
|
doc.first_name = customer_name
|
||||||
|
print(f"Setting contact first name: {customer_name}")
|
||||||
|
if email_id:
|
||||||
|
email_row = {
|
||||||
|
"email_id": email_id,
|
||||||
|
"is_primary": 1
|
||||||
|
}
|
||||||
|
doc.append("email_ids", email_row)
|
||||||
|
print(f"Added email: {email_id}")
|
||||||
|
|
||||||
|
phone_number = contacts[0].get("PrimaryPhone", "")
|
||||||
|
if phone_number:
|
||||||
|
num_row = {
|
||||||
|
"phone": phone_number,
|
||||||
|
"is_primary_phone": 1
|
||||||
|
}
|
||||||
|
doc.append("phone_nos", num_row)
|
||||||
|
print(f"Added phone number: {phone_number}")
|
||||||
|
|
||||||
|
link_row = get_link_row("Customer", customer_name)
|
||||||
|
doc.append("links", link_row)
|
||||||
|
print(f"Linked contact to customer: {customer_name}")
|
||||||
|
|
||||||
|
doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
contact_name = doc.name
|
||||||
|
|
||||||
|
return contact_name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_customer_if_not_exists(data: dict, setting_doc: str) -> str:
|
||||||
|
"""
|
||||||
|
Create new customer if not exists.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (Dict): Payload from webhook
|
||||||
|
setting_doc (str): setting doc name
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
customer_name (str): Return customer name after creation of customer.
|
||||||
|
"""
|
||||||
|
print("Checking Trading Partner ID in the payload...")
|
||||||
|
trading_id = data.get("Header", {}).get("OrderHeader", {}).get("TradingPartnerId")
|
||||||
|
print(f"Trading Partner ID: {trading_id}")
|
||||||
|
|
||||||
|
print("Fetching addresses from payload...")
|
||||||
|
addresses = data.get("Header", {}).get("Address", [])
|
||||||
|
address_names = [address.get("AddressName") for address in addresses]
|
||||||
|
print(f"Extracted Address Names: {address_names}")
|
||||||
|
|
||||||
|
print("Checking if customer already exists...")
|
||||||
|
if frappe.db.exists("Customer", {"custom_trading_partner_id": trading_id}):
|
||||||
|
customer_name = frappe.get_value(
|
||||||
|
"Customer",
|
||||||
|
{"custom_trading_partner_id": trading_id},
|
||||||
|
"name"
|
||||||
|
)
|
||||||
|
print(f"Customer already exists: {customer_name}")
|
||||||
|
else:
|
||||||
|
print("Customer does not exist. Creating a new customer...")
|
||||||
|
|
||||||
|
doc = frappe.new_doc("Customer")
|
||||||
|
doc.custom_trading_partner_id = trading_id
|
||||||
|
doc.customer_name = address_names[0].capitalize()
|
||||||
|
print(f"Assigned customer name: {doc.customer_name}")
|
||||||
|
|
||||||
|
doc.customer_type = frappe.get_value(
|
||||||
|
"SPS Integration Settings", setting_doc, "customer_type"
|
||||||
|
)
|
||||||
|
print(f"Fetched customer type from settings: {doc.customer_type}")
|
||||||
|
|
||||||
|
doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
print(f"New customer created: {doc.name}")
|
||||||
|
|
||||||
|
for address in addresses:
|
||||||
|
address_type = address.get("AddressTypeCode")
|
||||||
|
print(f"Processing address type: {address_type}")
|
||||||
|
|
||||||
|
if address_type == "BT":
|
||||||
|
print("Billing address found, creating or updating address...")
|
||||||
|
doc.customer_primary_contact = create_or_update_address(address, "Billing", doc.name)
|
||||||
|
print(f"Primary contact assigned: {doc.customer_primary_contact}")
|
||||||
|
|
||||||
|
doc.save()
|
||||||
|
frappe.db.commit()
|
||||||
|
print(f"Customer document saved: {doc.name}")
|
||||||
|
|
||||||
|
return doc.name
|
||||||
|
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def fetch_SPS_label():
|
||||||
|
"""
|
||||||
|
Enqueue
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def push_SPS_label_extensiv():
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def push_asn_to_sps():
|
||||||
|
"""
|
||||||
|
Enqueue
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_submit(doc,method):
|
||||||
|
try:
|
||||||
|
if doc.doctype == "Delivery Note":
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise Exception("Invalid Doctype")
|
||||||
|
except:
|
||||||
|
frappe.log_error(title="",message="")
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def validate_api_user(api_key: str, api_secret: str):
|
||||||
|
"""
|
||||||
|
Validate the api user's credentials.
|
||||||
|
args:
|
||||||
|
api_key: str
|
||||||
|
api_secret: str
|
||||||
|
return:
|
||||||
|
True | False: bool
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not api_key or not api_secret:
|
||||||
|
raise frappe.AuthenticationError("Missing API key or secret")
|
||||||
|
|
||||||
|
user = frappe.db.get_value("User", {"api_key": api_key}, "name")
|
||||||
|
if not user:
|
||||||
|
raise frappe.AuthenticationError("Invalid API key")
|
||||||
|
|
||||||
|
stored_api_secret = frappe.utils.password.get_decrypted_password("User", user, "api_secret")
|
||||||
|
|
||||||
|
if stored_api_secret != api_secret:
|
||||||
|
raise frappe.AuthenticationError("Invalid API secret")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except frappe.AuthenticationError as auth_err:
|
||||||
|
frappe.log_error(message=str(auth_err), title="API Authentication Failed")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
frappe.log_error(message=frappe.get_traceback(), title="Unexpected Error in API Authentication")
|
||||||
|
return False
|
||||||
Loading…
Reference in New Issue