Merge pull request #37015 from s-aga-r/REMOVE-WOOCOMMERCE

refactor!: remove `woocommerce` integration
diff --git a/erpnext/erpnext_integrations/connectors/__init__.py b/erpnext/erpnext_integrations/connectors/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/erpnext_integrations/connectors/__init__.py
+++ /dev/null
diff --git a/erpnext/erpnext_integrations/connectors/woocommerce_connection.py b/erpnext/erpnext_integrations/connectors/woocommerce_connection.py
deleted file mode 100644
index 2b2da7b..0000000
--- 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 e69de29..0000000
--- a/erpnext/erpnext_integrations/doctype/woocommerce_settings/__init__.py
+++ /dev/null
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 9945823..0000000
--- 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 d7a3d36..0000000
--- 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 956ae09..0000000
--- 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 4aa98aa..0000000
--- 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-",
-	}
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b3d6d3e..d0ee2e4 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -340,5 +340,6 @@
 erpnext.patches.v14_0.single_to_multi_dunning
 execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for_items', 0)
 erpnext.patches.v15_0.correct_asset_value_if_je_with_workflow
+erpnext.patches.v15_0.delete_woocommerce_settings_doctype
 # below migration patch should always run last
 erpnext.patches.v14_0.migrate_gl_to_payment_ledger
diff --git a/erpnext/patches/v15_0/delete_woocommerce_settings_doctype.py b/erpnext/patches/v15_0/delete_woocommerce_settings_doctype.py
new file mode 100644
index 0000000..fb92ca5
--- /dev/null
+++ b/erpnext/patches/v15_0/delete_woocommerce_settings_doctype.py
@@ -0,0 +1,5 @@
+import frappe
+
+
+def execute():
+	frappe.delete_doc("DocType", "Woocommerce Settings", ignore_missing=True)