refactor!: remove woocommerce
This commit is contained in:
parent
e6c302a397
commit
328ba4b656
@ -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,
|
||||
},
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import unittest
|
||||
|
||||
|
||||
class TestWoocommerceSettings(unittest.TestCase):
|
||||
pass
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
@ -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
|
||||
}
|
@ -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-",
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user