diff --git a/erpnext/erpnext_integrations/connectors/__init__.py b/erpnext/erpnext_integrations/connectors/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py deleted file mode 100644 index 2b2da7b971..0000000000 --- a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py +++ /dev/null @@ -1,256 +0,0 @@ -import base64 -import hashlib -import hmac -import json - -import frappe -from frappe import _ -from frappe.utils import cstr - - -def verify_request(): - woocommerce_settings = frappe.get_doc("Woocommerce Settings") - sig = base64.b64encode( - hmac.new( - woocommerce_settings.secret.encode("utf8"), frappe.request.data, hashlib.sha256 - ).digest() - ) - - if ( - frappe.request.data - and not sig == frappe.get_request_header("X-Wc-Webhook-Signature", "").encode() - ): - frappe.throw(_("Unverified Webhook Data")) - frappe.set_user(woocommerce_settings.creation_user) - - -@frappe.whitelist(allow_guest=True) -def order(*args, **kwargs): - try: - _order(*args, **kwargs) - except Exception: - error_message = ( - frappe.get_traceback() + "\n\n Request Data: \n" + json.loads(frappe.request.data).__str__() - ) - frappe.log_error("WooCommerce Error", error_message) - raise - - -def _order(*args, **kwargs): - woocommerce_settings = frappe.get_doc("Woocommerce Settings") - if frappe.flags.woocomm_test_order_data: - order = frappe.flags.woocomm_test_order_data - event = "created" - # Ignore the test ping issued during WooCommerce webhook configuration - # Ref: https://github.com/woocommerce/woocommerce/issues/15642 - if frappe.request.data.decode("utf-8").startswith("webhook_id="): - return "success" - elif frappe.request and frappe.request.data: - verify_request() - try: - order = json.loads(frappe.request.data) - except ValueError: - # woocommerce returns 'webhook_id=value' for the first request which is not JSON - order = frappe.request.data - event = frappe.get_request_header("X-Wc-Webhook-Event") - - else: - return "success" - - if event == "created": - sys_lang = frappe.get_single("System Settings").language or "en" - raw_billing_data = order.get("billing") - raw_shipping_data = order.get("shipping") - customer_name = raw_billing_data.get("first_name") + " " + raw_billing_data.get("last_name") - link_customer_and_address(raw_billing_data, raw_shipping_data, customer_name) - link_items(order.get("line_items"), woocommerce_settings, sys_lang) - create_sales_order(order, woocommerce_settings, customer_name, sys_lang) - - -def link_customer_and_address(raw_billing_data, raw_shipping_data, customer_name): - customer_woo_com_email = raw_billing_data.get("email") - customer_exists = frappe.get_value("Customer", {"woocommerce_email": customer_woo_com_email}) - if not customer_exists: - # Create Customer - customer = frappe.new_doc("Customer") - else: - # Edit Customer - customer = frappe.get_doc("Customer", {"woocommerce_email": customer_woo_com_email}) - old_name = customer.customer_name - - customer.customer_name = customer_name - customer.woocommerce_email = customer_woo_com_email - customer.flags.ignore_mandatory = True - customer.save() - - if customer_exists: - # Fixes https://github.com/frappe/erpnext/issues/33708 - if old_name != customer_name: - frappe.rename_doc("Customer", old_name, customer_name) - for address_type in ( - "Billing", - "Shipping", - ): - try: - address = frappe.get_doc( - "Address", {"woocommerce_email": customer_woo_com_email, "address_type": address_type} - ) - rename_address(address, customer) - except ( - frappe.DoesNotExistError, - frappe.DuplicateEntryError, - frappe.ValidationError, - ): - pass - else: - create_address(raw_billing_data, customer, "Billing") - create_address(raw_shipping_data, customer, "Shipping") - create_contact(raw_billing_data, customer) - - -def create_contact(data, customer): - email = data.get("email", None) - phone = data.get("phone", None) - - if not email and not phone: - return - - contact = frappe.new_doc("Contact") - contact.first_name = data.get("first_name") - contact.last_name = data.get("last_name") - contact.is_primary_contact = 1 - contact.is_billing_contact = 1 - - if phone: - contact.add_phone(phone, is_primary_mobile_no=1, is_primary_phone=1) - - if email: - contact.add_email(email, is_primary=1) - - contact.append("links", {"link_doctype": "Customer", "link_name": customer.name}) - - contact.flags.ignore_mandatory = True - contact.save() - - -def create_address(raw_data, customer, address_type): - address = frappe.new_doc("Address") - - address.address_line1 = raw_data.get("address_1", "Not Provided") - address.address_line2 = raw_data.get("address_2", "Not Provided") - address.city = raw_data.get("city", "Not Provided") - address.woocommerce_email = customer.woocommerce_email - address.address_type = address_type - address.country = frappe.get_value("Country", {"code": raw_data.get("country", "IN").lower()}) - address.state = raw_data.get("state") - address.pincode = raw_data.get("postcode") - address.phone = raw_data.get("phone") - address.email_id = customer.woocommerce_email - address.append("links", {"link_doctype": "Customer", "link_name": customer.name}) - - address.flags.ignore_mandatory = True - address.save() - - -def rename_address(address, customer): - old_address_title = address.name - new_address_title = customer.name + "-" + address.address_type - address.address_title = customer.customer_name - address.save() - - frappe.rename_doc("Address", old_address_title, new_address_title) - - -def link_items(items_list, woocommerce_settings, sys_lang): - for item_data in items_list: - item_woo_com_id = cstr(item_data.get("product_id")) - - if not frappe.db.get_value("Item", {"woocommerce_id": item_woo_com_id}, "name"): - # Create Item - item = frappe.new_doc("Item") - item.item_code = _("woocommerce - {0}", sys_lang).format(item_woo_com_id) - item.stock_uom = woocommerce_settings.uom or _("Nos", sys_lang) - item.item_group = _("WooCommerce Products", sys_lang) - - item.item_name = item_data.get("name") - item.woocommerce_id = item_woo_com_id - item.flags.ignore_mandatory = True - item.save() - - -def create_sales_order(order, woocommerce_settings, customer_name, sys_lang): - new_sales_order = frappe.new_doc("Sales Order") - new_sales_order.customer = customer_name - - new_sales_order.po_no = new_sales_order.woocommerce_id = order.get("id") - new_sales_order.naming_series = woocommerce_settings.sales_order_series or "SO-WOO-" - - created_date = order.get("date_created").split("T") - new_sales_order.transaction_date = created_date[0] - delivery_after = woocommerce_settings.delivery_after_days or 7 - new_sales_order.delivery_date = frappe.utils.add_days(created_date[0], delivery_after) - - new_sales_order.company = woocommerce_settings.company - - set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_lang) - new_sales_order.flags.ignore_mandatory = True - new_sales_order.insert() - new_sales_order.submit() - - frappe.db.commit() - - -def set_items_in_sales_order(new_sales_order, woocommerce_settings, order, sys_lang): - company_abbr = frappe.db.get_value("Company", woocommerce_settings.company, "abbr") - - default_warehouse = _("Stores - {0}", sys_lang).format(company_abbr) - if not frappe.db.exists("Warehouse", default_warehouse) and not woocommerce_settings.warehouse: - frappe.throw(_("Please set Warehouse in Woocommerce Settings")) - - for item in order.get("line_items"): - woocomm_item_id = item.get("product_id") - found_item = frappe.get_doc("Item", {"woocommerce_id": cstr(woocomm_item_id)}) - - ordered_items_tax = item.get("total_tax") - - new_sales_order.append( - "items", - { - "item_code": found_item.name, - "item_name": found_item.item_name, - "description": found_item.item_name, - "delivery_date": new_sales_order.delivery_date, - "uom": woocommerce_settings.uom or _("Nos", sys_lang), - "qty": item.get("quantity"), - "rate": item.get("price"), - "warehouse": woocommerce_settings.warehouse or default_warehouse, - }, - ) - - add_tax_details( - new_sales_order, ordered_items_tax, "Ordered Item tax", woocommerce_settings.tax_account - ) - - # shipping_details = order.get("shipping_lines") # used for detailed order - - add_tax_details( - new_sales_order, order.get("shipping_tax"), "Shipping Tax", woocommerce_settings.f_n_f_account - ) - add_tax_details( - new_sales_order, - order.get("shipping_total"), - "Shipping Total", - woocommerce_settings.f_n_f_account, - ) - - -def add_tax_details(sales_order, price, desc, tax_account_head): - sales_order.append( - "taxes", - { - "charge_type": "Actual", - "account_head": tax_account_head, - "tax_amount": price, - "description": desc, - }, - ) diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/__init__.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py deleted file mode 100644 index 9945823bf7..0000000000 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/test_woocommerce_settings.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors -# See license.txt - -import unittest - - -class TestWoocommerceSettings(unittest.TestCase): - pass diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.js b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.js deleted file mode 100644 index d7a3d36a5f..0000000000 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Woocommerce Settings', { - refresh (frm) { - frm.trigger("add_button_generate_secret"); - frm.trigger("check_enabled"); - frm.set_query("tax_account", ()=>{ - return { - "filters": { - "company": frappe.defaults.get_default("company"), - "is_group": 0 - } - }; - }); - }, - - enable_sync (frm) { - frm.trigger("check_enabled"); - }, - - add_button_generate_secret(frm) { - frm.add_custom_button(__('Generate Secret'), () => { - frappe.confirm( - __("Apps using current key won't be able to access, are you sure?"), - () => { - frappe.call({ - type:"POST", - method:"erpnext.erpnext_integrations.doctype.woocommerce_settings.woocommerce_settings.generate_secret", - }).done(() => { - frm.reload_doc(); - }).fail(() => { - frappe.msgprint(__("Could not generate Secret")); - }); - } - ); - }); - }, - - check_enabled (frm) { - frm.set_df_property("woocommerce_server_url", "reqd", frm.doc.enable_sync); - frm.set_df_property("api_consumer_key", "reqd", frm.doc.enable_sync); - frm.set_df_property("api_consumer_secret", "reqd", frm.doc.enable_sync); - } -}); - -frappe.ui.form.on("Woocommerce Settings", "onload", function () { - frappe.call({ - method: "erpnext.erpnext_integrations.doctype.woocommerce_settings.woocommerce_settings.get_series", - callback: function (r) { - $.each(r.message, function (key, value) { - set_field_options(key, value); - }); - } - }); -}); diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json deleted file mode 100644 index 956ae09cbd..0000000000 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "creation": "2018-02-12 15:10:05.495713", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "enable_sync", - "sb_00", - "woocommerce_server_url", - "secret", - "cb_00", - "api_consumer_key", - "api_consumer_secret", - "sb_accounting_details", - "tax_account", - "column_break_10", - "f_n_f_account", - "defaults_section", - "creation_user", - "warehouse", - "sales_order_series", - "column_break_14", - "company", - "delivery_after_days", - "uom", - "endpoints", - "endpoint" - ], - "fields": [ - { - "default": "0", - "fieldname": "enable_sync", - "fieldtype": "Check", - "label": "Enable Sync" - }, - { - "fieldname": "sb_00", - "fieldtype": "Section Break" - }, - { - "fieldname": "woocommerce_server_url", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Woocommerce Server URL" - }, - { - "fieldname": "secret", - "fieldtype": "Code", - "label": "Secret", - "read_only": 1 - }, - { - "fieldname": "cb_00", - "fieldtype": "Column Break" - }, - { - "fieldname": "api_consumer_key", - "fieldtype": "Data", - "in_list_view": 1, - "label": "API consumer key" - }, - { - "fieldname": "api_consumer_secret", - "fieldtype": "Data", - "in_list_view": 1, - "label": "API consumer secret" - }, - { - "fieldname": "sb_accounting_details", - "fieldtype": "Section Break", - "label": "Accounting Details" - }, - { - "fieldname": "tax_account", - "fieldtype": "Link", - "label": "Tax Account", - "options": "Account", - "reqd": 1 - }, - { - "fieldname": "column_break_10", - "fieldtype": "Column Break" - }, - { - "fieldname": "f_n_f_account", - "fieldtype": "Link", - "label": "Freight and Forwarding Account", - "options": "Account", - "reqd": 1 - }, - { - "fieldname": "defaults_section", - "fieldtype": "Section Break", - "label": "Defaults" - }, - { - "description": "The user that will be used to create Customers, Items and Sales Orders. This user should have the relevant permissions.", - "fieldname": "creation_user", - "fieldtype": "Link", - "label": "Creation User", - "options": "User", - "reqd": 1 - }, - { - "description": "This warehouse will be used to create Sales Orders. The fallback warehouse is \"Stores\".", - "fieldname": "warehouse", - "fieldtype": "Link", - "label": "Warehouse", - "options": "Warehouse" - }, - { - "fieldname": "column_break_14", - "fieldtype": "Column Break" - }, - { - "description": "The fallback series is \"SO-WOO-\".", - "fieldname": "sales_order_series", - "fieldtype": "Select", - "label": "Sales Order Series" - }, - { - "description": "This is the default UOM used for items and Sales orders. The fallback UOM is \"Nos\".", - "fieldname": "uom", - "fieldtype": "Link", - "label": "UOM", - "options": "UOM" - }, - { - "fieldname": "endpoints", - "fieldtype": "Section Break", - "label": "Endpoints" - }, - { - "fieldname": "endpoint", - "fieldtype": "Code", - "label": "Endpoint", - "read_only": 1 - }, - { - "description": "This company will be used to create Sales Orders.", - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 - }, - { - "description": "This is the default offset (days) for the Delivery Date in Sales Orders. The fallback offset is 7 days from the order placement date.", - "fieldname": "delivery_after_days", - "fieldtype": "Int", - "label": "Delivery After (Days)" - } - ], - "issingle": 1, - "modified": "2019-11-04 00:45:21.232096", - "modified_by": "Administrator", - "module": "ERPNext Integrations", - "name": "Woocommerce Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "email": 1, - "print": 1, - "read": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py b/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py deleted file mode 100644 index 4aa98aab56..0000000000 --- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/woocommerce_settings.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors -# For license information, please see license.txt - - -from urllib.parse import urlparse - -import frappe -from frappe import _ -from frappe.custom.doctype.custom_field.custom_field import create_custom_fields -from frappe.model.document import Document -from frappe.utils.nestedset import get_root_of - - -class WoocommerceSettings(Document): - def validate(self): - self.validate_settings() - self.create_delete_custom_fields() - self.create_webhook_url() - - def create_delete_custom_fields(self): - if self.enable_sync: - create_custom_fields( - { - ("Customer", "Sales Order", "Item", "Address"): dict( - fieldname="woocommerce_id", - label="Woocommerce ID", - fieldtype="Data", - read_only=1, - print_hide=1, - ), - ("Customer", "Address"): dict( - fieldname="woocommerce_email", - label="Woocommerce Email", - fieldtype="Data", - read_only=1, - print_hide=1, - ), - } - ) - - if not frappe.get_value("Item Group", {"name": _("WooCommerce Products")}): - item_group = frappe.new_doc("Item Group") - item_group.item_group_name = _("WooCommerce Products") - item_group.parent_item_group = get_root_of("Item Group") - item_group.insert() - - def validate_settings(self): - if self.enable_sync: - if not self.secret: - self.set("secret", frappe.generate_hash()) - - if not self.woocommerce_server_url: - frappe.throw(_("Please enter Woocommerce Server URL")) - - if not self.api_consumer_key: - frappe.throw(_("Please enter API Consumer Key")) - - if not self.api_consumer_secret: - frappe.throw(_("Please enter API Consumer Secret")) - - def create_webhook_url(self): - endpoint = "/api/method/erpnext.erpnext_integrations.connectors.woocommerce_connection.order" - - try: - url = frappe.request.url - except RuntimeError: - # for CI Test to work - url = "http://localhost:8000" - - server_url = "{uri.scheme}://{uri.netloc}".format(uri=urlparse(url)) - - delivery_url = server_url + endpoint - self.endpoint = delivery_url - - -@frappe.whitelist() -def generate_secret(): - woocommerce_settings = frappe.get_doc("Woocommerce Settings") - woocommerce_settings.secret = frappe.generate_hash() - woocommerce_settings.save() - - -@frappe.whitelist() -def get_series(): - return { - "sales_order_series": frappe.get_meta("Sales Order").get_options("naming_series") or "SO-WOO-", - }