167 lines
5.5 KiB
Markdown
167 lines
5.5 KiB
Markdown
# 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
|
|
|
|
```
|
|
Danach ausführen
|
|
```bash
|
|
bench restart
|
|
```
|
|
|
|
### 2. DocType anlegen
|
|
|
|
DocType Name: WooCommerce ACF Mapping
|
|
**Felder:**
|
|
|
|
- erp_field → Data → Pflicht
|
|
- acf_field → Data → Pflicht
|
|
- enabled → Check → Default = 1
|
|
- description → Small Text
|
|
|
|
**Title Field:** erp_field
|
|
|
|
### Client Script mit Button
|
|
Custom Script → New
|
|
|
|
- DocType: Item
|
|
- Script Type: Client Script
|
|
|
|
```js
|
|
frappe.ui.form.on('Item', {
|
|
refresh: function(frm) {
|
|
frm.add_custom_button('Custom Fields zu WooCommerce syncen', function() {
|
|
if (!frm.doc.woocommerce_servers || frm.doc.woocommerce_servers.length === 0) {
|
|
frappe.msgprint("Kein WooCommerce Server verknüpft!", "Warnung");
|
|
return;
|
|
}
|
|
|
|
frappe.call({
|
|
method: 'erpnext_custom.api.sync_custom_fields_to_woocommerce',
|
|
args: { item_code: frm.doc.name }
|
|
});
|
|
}, "WooCommerce");
|
|
}
|
|
});
|
|
```
|
|
### Nutzung
|
|
|
|
- Im Item-Dokument unter WooCommerce ACF Mapping die gewünschten Felder eintragen.
|
|
- Im Artikel-Formular auf den Button "Custom Fields zu WooCommerce syncen" klicken.
|
|
|
|
## Bekannte Probleme
|
|
|
|
- Der Standard-Sync der `woocommerce_fusion`-App kann bei manchen Artikeln fehlschlagen (Fehler bei WooCommerce ID Parsing). Deshalb wird aktuell ein separater manueller Button verwendet.
|
|
- `frappe.msgprint` Meldungen erscheinen manchmal nicht sofort oder nicht in der Console (besser im Browser testen).
|
|
- Bei neuen Artikeln muss zuerst ein Produkt in WooCommerce existieren und die WooCommerce ID im Item hinterlegt sein.
|
|
- ACF-Felder werden derzeit zuverlässig nur über `meta_data` übertragen (direkter ACF-Block war instabil).
|
|
- Der Sync muss manuell über den Button ausgelöst werden (kein automatischer Sync beim Speichern, um Konflikte mit woocommerce_fusion zu vermeiden).
|
|
|
|
## Zukünftige Erweiterungen
|
|
|
|
- Automatischer Sync beim Speichern des Items (ohne Konflikt mit woocommerce_fusion)
|
|
- Bidirektionaler Sync (WooCommerce → ERPNext)
|
|
- Unterstützung für direkten ACF-Block (falls REST API stabil läuft)
|
|
- Logging-DocType für Sync-Historie und Fehleranalyse
|
|
- Massen-Sync Funktion für mehrere Artikel auf einmal
|
|
- Unterstützung für Varianten und Attribute
|
|
- Möglichkeit, einzelne Felder vom Sync auszuschließen
|
|
- Bessere Fehlermeldungen und Status-Übersicht
|
|
|