# erpnext_custom Custom App für NEXTErp mit zuverlässigem Sync von Custom Fields zu WooCommerce (ACF / Meta Data). ## Funktionen - Sync beliebiger Custom Fields aus ERPNext-Item nach WooCommerce - Verwendung von `meta_data` (stabiler als ACF-Block) - Manueller Sync-Button im Item-Formular ## Installation ### 1. App erstellen ```bash cd ~/frappe-bench bench new-app erpnext_custom ``` Bei den Fragen: App Title: NEXTErp Custom App Description: WooCommerce ACF Custom Fields Sync App Publisher: Jens Falk App Email: service@falk.plus ```bash cd ~/frappe-bench/apps/erpnext_custom/erpnext_custom ``` ```bash cat > api.py << 'EOF' import frappe import requests from frappe import _ @frappe.whitelist() def sync_custom_fields_to_woocommerce(item_code): """Sync Custom Fields via meta_data nach WooCommerce""" frappe.msgprint("Sync gestartet fuer Artikel " + str(item_code), indicator="blue", alert=1) doc = frappe.get_doc("Item", item_code) if not doc.get("woocommerce_servers"): frappe.msgprint("Kein WooCommerce Server verknuepft", indicator="red", alert=1) return False # Mappings aus DocType laden mappings = frappe.get_all("WooCommerce ACF Mapping", filters={"enabled": 1}, fields=["erp_field", "acf_field"]) field_mapping = {m.erp_field: m.acf_field for m in mappings if m.erp_field and m.acf_field} if not field_mapping: frappe.msgprint("KEIN Mapping gefunden! Bitte im DocType 'WooCommerce ACF Mapping' Eintraege anlegen.", indicator="red", alert=1) return False for wc_link in doc.woocommerce_servers: if not wc_link.get("woocommerce_id"): continue try: wc_server = frappe.get_doc("WooCommerce Server", wc_link.woocommerce_server) api_key = wc_server.get("api_consumer_key") api_secret = wc_server.get("api_consumer_secret") if not api_key or not api_secret: continue base_url = wc_server.woocommerce_server_url.rstrip("/") if not base_url.endswith("/wp-json/wc/v3"): base_url += "/wp-json/wc/v3" url = base_url + "/products/" + str(wc_link.woocommerce_id) auth = (api_key, api_secret) # Produkt holen resp = requests.get(url, auth=auth, timeout=15) product = resp.json() meta_data = product.get("meta_data", []) for erp_field, acf_field in field_mapping.items(): value = doc.get(erp_field) or "" meta_data = [m for m in meta_data if m.get("key") != acf_field] meta_data.append({"key": acf_field, "value": value}) payload = {"meta_data": meta_data} update_resp = requests.put(url, json=payload, auth=auth, timeout=15) update_resp.raise_for_status() frappe.msgprint("Custom Fields erfolgreich gesendet!", indicator="green", alert=1) except Exception as e: frappe.msgprint("Fehler: " + str(e), indicator="red", alert=1) return True EOF ```