diff --git a/shipstation_integration/__init__.py b/shipstation_integration/__init__.py index 95d1338..4650b23 100644 --- a/shipstation_integration/__init__.py +++ b/shipstation_integration/__init__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -__version__ = '0.0.1' +__version__ = '0.0.2' diff --git a/shipstation_integration/orders.py b/shipstation_integration/orders.py index 5e6c76b..d5afe4d 100644 --- a/shipstation_integration/orders.py +++ b/shipstation_integration/orders.py @@ -61,7 +61,7 @@ def list_orders( if not last_order_datetime: # Get data for the last day, Shipstation API behaves oddly when it's a shorter period last_order_datetime = datetime.datetime.utcnow() - datetime.timedelta( - hours=24 + hours=sss_doc.get("hours_to_fetch", 24) ) store: "ShipstationStore" @@ -209,6 +209,7 @@ def create_erpnext_order( discount_amount = 0.0 for item in order_items: + # skip the item if the quantity is 0 (item was refunded) if item.quantity < 1: continue @@ -223,9 +224,7 @@ def create_erpnext_order( settings = frappe.get_doc("Shipstation Settings", store.parent) item_code = create_item(item, settings=settings, store=store) item_notes = get_item_notes(item) - so.append( - "items", - { + item_dict = { "item_code": item_code, "qty": item.quantity, "uom": frappe.db.get_single_value("Stock Settings", "stock_uom"), @@ -234,8 +233,26 @@ def create_erpnext_order( "warehouse": store.warehouse, "shipstation_order_item_id": item.order_item_id, "shipstation_item_notes": item_notes, - }, - ) + } + + options_import = frappe.get_all("Shipstation Option", + filters=dict(parent=store.parent), + fields=["shipstation_option_name", "item_field"]) + + for option in item.options: + # check to see if the option is in the Options Import table + option_import = next((x for x in options_import if x.shipstation_option_name == option.name), None) + if option_import: + if option_import.item_field: + item_dict[option_import.item_field] = option.value + else: + # if the option name is not in the Options Import table, add it + settings.append("options_import", { + "shipstation_option_name": option.name + }) + settings.save() + + so.append("items", item_dict) if not so.get("items"): return diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/__init__.py b/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/shipstation_item_custom_field.json b/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/shipstation_item_custom_field.json new file mode 100644 index 0000000..f660ef7 --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/shipstation_item_custom_field.json @@ -0,0 +1,111 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2022-07-06 12:17:13.829719", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "label", + "fieldtype", + "fieldname", + "length", + "reqd", + "hidden", + "read_only", + "column_break_8", + "options", + "default", + "fetch_from", + "fetch_if_empty" + ], + "fields": [ + { + "fieldname": "label", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Label", + "reqd": 1 + }, + { + "default": "Data", + "fieldname": "fieldtype", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Type", + "options": "Attach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSmall Text\nTable\nTable MultiSelect\nText\nText Editor\nTime\nSignature", + "reqd": 1 + }, + { + "fieldname": "fieldname", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Name", + "reqd": 1 + }, + { + "fieldname": "options", + "fieldtype": "Small Text", + "in_list_view": 1, + "label": "Options" + }, + { + "default": "0", + "fieldname": "reqd", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Mandatory" + }, + { + "default": "0", + "fieldname": "hidden", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Hidden" + }, + { + "default": "0", + "fieldname": "read_only", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Read Only" + }, + { + "depends_on": "eval:in_list(['Data', 'Link', 'Dynamic Link', 'Password', 'Select', 'Read Only', 'Attach', 'Attach Image', 'Int'], doc.fieldtype)", + "fieldname": "length", + "fieldtype": "Int", + "label": "Length" + }, + { + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, + { + "fieldname": "default", + "fieldtype": "Small Text", + "label": "Default" + }, + { + "fieldname": "fetch_from", + "fieldtype": "Small Text", + "label": "Fetch From" + }, + { + "default": "0", + "fieldname": "fetch_if_empty", + "fieldtype": "Check", + "label": "Fetch If Empty" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2022-11-16 14:14:12.504952", + "modified_by": "Administrator", + "module": "Shipstation Integration", + "name": "Shipstation Item Custom Field", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/shipstation_item_custom_field.py b/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/shipstation_item_custom_field.py new file mode 100644 index 0000000..9d514a4 --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_item_custom_field/shipstation_item_custom_field.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, Parsimony LLC and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class ShipstationItemCustomField(Document): + pass diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/__init__.py b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.js b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.js new file mode 100644 index 0000000..40b906e --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Parsimony LLC and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Shipstation Item Field', { + // refresh: function(frm) { + + // } +}); diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.json b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.json new file mode 100644 index 0000000..b6412ca --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.json @@ -0,0 +1,43 @@ +{ + "actions": [], + "autoname": "format:{fieldname}", + "creation": "2023-03-09 10:18:10.691994", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "fieldname", + "label" + ], + "fields": [ + { + "fieldname": "fieldname", + "fieldtype": "Data", + "label": "Field Name", + "unique": 1 + }, + { + "fieldname": "label", + "fieldtype": "Data", + "label": "Label" + } + ], + "in_create": 1, + "is_virtual": 1, + "links": [], + "modified": "2023-03-09 12:00:57.772150", + "modified_by": "Administrator", + "module": "Shipstation Integration", + "name": "Shipstation Item Field", + "owner": "Administrator", + "permissions": [ + { + "read": 1, + "role": "System Manager" + } + ], + "read_only": 1, + "search_fields": "fieldname,label", + "sort_field": "fieldname", + "sort_order": "DESC", + "title_field": "label" +} \ No newline at end of file diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.py b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.py new file mode 100644 index 0000000..1f3491d --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/shipstation_item_field.py @@ -0,0 +1,24 @@ +# Copyright (c) 2023, Parsimony LLC and contributors +# For license information, please see license.txt + +import frappe +import json +from frappe.model.document import Document + + +class ShipstationItemField(Document): + + def get_list(self, args): + return get_item_fields() + +def get_item_fields(search_text=None): + field_list = [ + {"name": f.fieldname, "fieldname": f.fieldname, "label": f.label} + for f in frappe.get_meta("Sales Order Item").fields + if f.fieldtype in ["Data", "Text", "Small Text", "Link", "Select"] + ] + if search_text: + field_list = [ + f for f in field_list if search_text.lower() in f["fieldname"].lower() or search_text.lower() in f["label"].lower() + ] + return field_list \ No newline at end of file diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/test_shipstation_item_field.py b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/test_shipstation_item_field.py new file mode 100644 index 0000000..4a053d9 --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_item_field/test_shipstation_item_field.py @@ -0,0 +1,8 @@ +# Copyright (c) 2023, Parsimony LLC and Contributors +# See license.txt + +# import frappe +import unittest + +class TestShipstationItemField(unittest.TestCase): + pass diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_option/__init__.py b/shipstation_integration/shipstation_integration/doctype/shipstation_option/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_option/shipstation_option.json b/shipstation_integration/shipstation_integration/doctype/shipstation_option/shipstation_option.json new file mode 100644 index 0000000..d23597b --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_option/shipstation_option.json @@ -0,0 +1,44 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2022-07-05 14:43:09.827242", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "shipstation_option_name", + "column_break", + "item_field" + ], + "fields": [ + { + "fieldname": "shipstation_option_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "ShipStation Option Name", + "reqd": 1 + }, + { + "fieldname": "column_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "item_field", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Item Field", + "options": "Shipstation Item Field" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-03-09 12:03:49.961605", + "modified_by": "Administrator", + "module": "Shipstation Integration", + "name": "Shipstation Option", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" +} \ No newline at end of file diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_option/shipstation_option.py b/shipstation_integration/shipstation_integration/doctype/shipstation_option/shipstation_option.py new file mode 100644 index 0000000..bee002d --- /dev/null +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_option/shipstation_option.py @@ -0,0 +1,8 @@ +# Copyright (c) 2022, Parsimony LLC and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class ShipstationOption(Document): + pass diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.js b/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.js index b52c35c..9c79a17 100644 --- a/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.js +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.js @@ -2,96 +2,129 @@ // For license information, please see license.txt function company_query(frm, cdt, cdn) { - const row = frm.selected_doc || locals[cdt][cdn]; - return { - filters: { - "company": row.company, - "is_group": 0 - } - }; + const row = frm.selected_doc || locals[cdt][cdn]; + return { + filters: { + "company": row.company, + "is_group": 0 + } + }; } frappe.ui.form.on("Shipstation Settings", { - setup: frm => { - frm.set_query("shipstation_warehouses", { "shipstation_warehouse_id": ["!=", ""] }); - frm.set_query("cost_center", "shipstation_stores", company_query); - frm.set_query("warehouse", "shipstation_stores", company_query); - frm.set_query("tax_account", "shipstation_stores", company_query); - frm.set_query("sales_account", "shipstation_stores", company_query); - frm.set_query("expense_account", "shipstation_stores", company_query); - frm.set_query("shipping_income_account", "shipstation_stores", company_query); - frm.set_query("shipping_expense_account", "shipstation_stores", company_query); - }, + setup: frm => { + frm.set_query("shipstation_warehouses", { "shipstation_warehouse_id": ["!=", ""] }); + frm.set_query("cost_center", "shipstation_stores", company_query); + frm.set_query("warehouse", "shipstation_stores", company_query); + frm.set_query("tax_account", "shipstation_stores", company_query); + frm.set_query("sales_account", "shipstation_stores", company_query); + frm.set_query("expense_account", "shipstation_stores", company_query); + frm.set_query("shipping_income_account", "shipstation_stores", company_query); + frm.set_query("shipping_expense_account", "shipstation_stores", company_query); + frm.set_query("item_field", "options_import", () => ({ + query: "shipstation_integration.shipstation_integration.doctype.shipstation_settings.shipstation_settings.item_fields_query" + })); + // workaround for link validation on the item_field field + frappe.meta.get_docfield("Shipstation Option", "item_field", frm.docname).ignore_link_validation = true; + }, - after_save: frm => { - frm.trigger("toggle_mandatory_table_fields"); - }, + after_save: frm => { + frm.trigger("toggle_mandatory_table_fields"); + }, - refresh: frm => { - frm.trigger("toggle_mandatory_table_fields"); - if (frm.doc.carrier_data) { - let wrapper = $(frm.fields_dict["carriers_html"].wrapper); - wrapper.html(frappe.render_template("carriers", { "carriers": frm.doc.__onload.carriers })); - } - }, + refresh: frm => { + frm.trigger("toggle_mandatory_table_fields"); + if (frm.doc.carrier_data) { + const wrapper = $(frm.fields_dict.carriers_html.wrapper); + wrapper.html(frappe.render_template("carriers", { "carriers": frm.doc.__onload.carriers })); + } + }, - update_carriers_and_stores: frm => { - frappe.show_alert("Updating Carriers and Stores") - frm.call({ - doc: frm.doc, - method: "update_carriers_and_stores", - freeze: true - }).done(() => { frm.reload_doc() }) - }, + update_carriers_and_stores: frm => { + frappe.show_alert("Updating Carriers and Stores") + frm.call({ + doc: frm.doc, + method: "update_carriers_and_stores", + freeze: true + }).done(() => { frm.reload_doc() }) + }, - get_items: frm => { - frappe.show_alert("Getting Items"); - frm.call({ - doc: frm.doc, - method: "get_items", - freeze: true - }).done((r) => { frappe.show_alert(r.message) }) - }, + get_items: frm => { + frappe.show_alert("Getting Items"); + frm.call({ + doc: frm.doc, + method: "get_items", + freeze: true + }).done((r) => { frappe.show_alert(r.message) }) + }, - get_orders: frm => { - frappe.show_alert("Getting Orders"); - frm.call({ - doc: frm.doc, - method: "get_orders", - freeze: true - }) - }, + get_orders: frm => { + frappe.show_alert("Getting Orders"); + frm.call({ + doc: frm.doc, + method: "get_orders", + freeze: true + }) + }, - get_shipments: frm => { - frappe.show_alert("Getting Shipments"); - frm.call({ - doc: frm.doc, - method: "get_shipments", - freeze: true - }) - }, + get_shipments: frm => { + frappe.show_alert("Getting Shipments"); + frm.call({ + doc: frm.doc, + method: "get_shipments", + freeze: true + }) + }, - fetch_warehouses: frm => { - frm.call({ - doc: frm.doc, - method: "update_warehouses", - freeze: true - }) - }, + fetch_warehouses: frm => { + frm.call({ + doc: frm.doc, + method: "update_warehouses", + freeze: true + }) + }, - reset_warehouses: frm => { - frm.set_value("shipstation_warehouses", []); - frm.save(); - }, + update_order_item_custom_fields: frm => { + frm.call({ + doc: frm.doc, + method: "update_order_item_custom_fields", + freeze: true + }) + }, + + reset_warehouses: frm => { + frm.set_value("shipstation_warehouses", []); + frm.save(); + }, + + toggle_mandatory_table_fields: frm => { + frm.fields_dict.shipstation_stores.grid.toggle_reqd("company", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("warehouse", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("cost_center", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("shipping_income_account", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("shipping_expense_account", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("tax_account", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("sales_account", !frm.is_new()); + frm.fields_dict.shipstation_stores.grid.toggle_reqd("expense_account", !frm.is_new()); + } - toggle_mandatory_table_fields: frm => { - frm.fields_dict.shipstation_stores.grid.toggle_reqd("company", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("warehouse", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("cost_center", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("shipping_income_account", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("shipping_expense_account", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("tax_account", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("sales_account", !frm.is_new()); - frm.fields_dict.shipstation_stores.grid.toggle_reqd("expense_account", !frm.is_new()); - } }); + +frappe.ui.form.on("Shipstation Item Custom Field", { + before_item_custom_fields_remove: (frm, cdt, cdn) => { + const deleted_row = frappe.get_doc(cdt, cdn); + if (deleted_row.item_field) { + frappe.call({ + method: "shipstation_integration.shipstation_integration.doctype.shipstation_settings.shipstation_settings.remove_item_field", + args: { + "fieldname": deleted_row.item_field + }, + callback: r => { + if (r.message.status === 'Alert') { + frappe.show_alert({ message: r.message.message, indicator: 'orange' }); + } + } + }); + } + } +}); \ No newline at end of file diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.json b/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.json index 585a553..6d58fa8 100644 --- a/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.json +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "Prompt", "creation": "2019-12-10 11:54:44.442858", "doctype": "DocType", @@ -16,6 +17,8 @@ "get_shipments", "update_carriers_and_stores", "sb_filters", + "hours_to_fetch", + "column_break_13", "since_date", "sb_warehouses", "shipstation_warehouses", @@ -23,6 +26,11 @@ "reset_warehouses", "sb_stores", "shipstation_stores", + "sb_itemmeta", + "options_import", + "create_custom_fields_for_items", + "item_custom_fields", + "update_order_item_custom_fields", "sb_carriers", "carrier_data", "carriers_html" @@ -154,10 +162,52 @@ "fieldname": "reset_warehouses", "fieldtype": "Button", "label": "Reset" + }, + { + "fieldname": "sb_itemmeta", + "fieldtype": "Section Break", + "label": "Metadata Import" + }, + { + "depends_on": "eval:doc.create_custom_fields_for_items", + "fieldname": "update_order_item_custom_fields", + "fieldtype": "Button", + "label": "Create/Update Custom Fields" + }, + { + "fieldname": "options_import", + "fieldtype": "Table", + "label": "Shipstation Options", + "options": "Shipstation Option" + }, + { + "default": "0", + "fieldname": "create_custom_fields_for_items", + "fieldtype": "Check", + "label": "Define Custom Fields for Items" + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" + }, + { + "default": "24", + "description": "How many hours should we look back for orders on the initial sync? This should be no less than 24.", + "fieldname": "hours_to_fetch", + "fieldtype": "Int", + "label": "Order Age" + }, + { + "depends_on": "eval:doc.create_custom_fields_for_items", + "fieldname": "item_custom_fields", + "fieldtype": "Table", + "label": "Item Custom Fields", + "options": "Shipstation Item Custom Field" } ], "hide_toolbar": 1, - "modified": "2021-11-24 05:30:10.617590", + "links": [], + "modified": "2022-12-09 16:13:16.647066", "modified_by": "Administrator", "module": "Shipstation Integration", "name": "Shipstation Settings", diff --git a/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.py b/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.py index e74c4de..20fed5b 100644 --- a/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.py +++ b/shipstation_integration/shipstation_integration/doctype/shipstation_settings/shipstation_settings.py @@ -17,6 +17,7 @@ from shipstation_integration.orders import list_orders from shipstation_integration.shipments import list_shipments from shipstation_integration.utils import get_marketplace +from shipstation_integration.shipstation_integration.doctype.shipstation_item_field.shipstation_item_field import get_item_fields class ShipstationSettings(Document): @@ -52,6 +53,9 @@ def after_insert(self): self.update_carriers_and_stores() self.update_warehouses() + def on_update(self): + self.update_item_custom_fields() + @frappe.whitelist() def get_orders(self): list_orders(self) @@ -220,3 +224,75 @@ def get_codes(self, carrier, service, package): _package = pack['code'] return _carrier, _service, _package + + # create custom fields on the Sales Order Item doctype from the item_custom_fields table (for storing Shipstation metadata) + @frappe.whitelist() + def update_item_custom_fields(self): + # first, create any new custom fields + item_custom_fields = self.item_custom_fields + insert_after = "shipstation_item_notes" + item_doctypes = ["Delivery Note Item", "Sales Order Item", "Sales Invoice Item"] + for field in item_custom_fields: + field_def = { + "insert_after": insert_after, + "label": field.label, + "fieldtype": field.fieldtype, + "fieldname": field.fieldname, + "length": field.length, + "reqd": field.reqd, + "hidded": field.hidden, + "read_only": field.read_only, + "options": field.options, + "default": field.default, + "fetch_from": field.fetch_from, + "fetch_if_empty": field.fetch_if_empty + } + for dt in item_doctypes: + if not frappe.db.exists("Custom Field", {"dt": dt, "fieldname": field.fieldname}): + custom_field = frappe.new_doc("Custom Field") + custom_field.dt = dt + custom_field.update(field_def) + custom_field.insert() + else: + custom_field = frappe.get_doc("Custom Field", {"dt": dt, "fieldname": field.fieldname}) + custom_field.update(field_def) + custom_field.save() + if frappe.db.exists("Custom Field", {"dt": dt, "fieldname": field.fieldname}): + insert_after = field.fieldname + frappe.clear_cache(doctype=dt) + frappe.db.updatedb(dt) + # delete any remove custom fields + removed_item_custom_fields = frappe.flags.removed_item_custom_fields or [] + if removed_item_custom_fields: + # make sure that the removed field is not in the item_custom_fields variable + removed_item_custom_fields = [field for field in removed_item_custom_fields if not field in [f.fieldname for f in item_custom_fields]] + for field in removed_item_custom_fields: + for dt in item_doctypes: + if frappe.db.exists("Custom Field", {"dt": dt, "fieldname": field}): + frappe.delete_doc("Custom Field", {"dt": dt, "fieldname": field}) + frappe.clear_cache(doctype=dt) + frappe.db.updatedb(dt) + + + +@frappe.whitelist() +@frappe.validate_and_sanitize_search_inputs +def item_fields_query(doctype, txt, searchfield, start, page_len, filters): + field_list = [[f['fieldname'], f['label']] for f in get_item_fields(txt)] + return field_list + + +@frappe.whitelist() +def get_item_field_link_type(fieldname): + # check if the field is a custom field + if frappe.db.exists("Custom Field", {"dt": "Sales Order Item", "fieldname": fieldname}): + return "Custom Field" + else: + return "DocField" + +@frappe.whitelist() +def remove_item_field(fieldname): + frappe.flags.removed_item_custom_fields = frappe.flags.removed_item_custom_fields or [] + if fieldname not in frappe.flags.removed_item_custom_fields: + frappe.flags.removed_item_custom_fields.append(fieldname) + return {'status': 'Alert', 'message': 'Item field ' + fieldname + ' will be deleted on save.'} \ No newline at end of file diff --git a/shipstation_integration/templates/pages/__pycache__/__init__.py b/shipstation_integration/templates/pages/__pycache__/__init__.py new file mode 100644 index 0000000..e69de29