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