diff --git a/ChangeLog.md b/ChangeLog.md index b7b80ac..b31604f 100755 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,12 @@ # CHANGELOG MODULE DELIVERYINVOICEADDRESS FOR [DOLIBARR ERP CRM](https://www.dolibarr.org) -1.1 +## 1.2 + +- Fix: `{*_contact_name}` liefert jetzt Nachname statt Vorname +- Neu: `{*_contact_fullname}` Platzhalter (Vorname + Nachname, berücksichtigt MAIN_FIRSTNAME_NAME_POSITION) +- Refactoring: Kontaktdaten per JOIN in einer Query statt N+1 Queries +- Code aufgeräumt: Mapping-Array statt if/elseif, Null-Coalescing, weniger Logging + +## 1.1 Initial version diff --git a/README.md b/README.md index 7730a01..6771113 100755 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Dolibarr-Modul zur Verwendung von Rechnungs-, Liefer- und Serviceadressen in ODT - Lieferadresse für Versanddokumente - Serviceadresse für Servicedokumente - Automatische Erkennung des Dokumenttyps (Angebot/Auftrag/Rechnung) -- Fallback auf Kundenadresse wenn kein spezieller Kontakt vorhanden +- CUSTOMER-Kontakt als Fallback für BILLING bei Angeboten/Aufträgen ## Installation @@ -30,7 +30,8 @@ Dolibarr-Modul zur Verwendung von Rechnungs-, Liefer- und Serviceadressen in ODT | Tag | Beschreibung | |-----|--------------| | `{billing_contact_firstname}` | Vorname | -| `{billing_contact_name}` | Vorname (Fallback: Nachname) | +| `{billing_contact_name}` | Nachname | +| `{billing_contact_fullname}` | Vorname + Nachname (berücksichtigt `MAIN_FIRSTNAME_NAME_POSITION`) | | `{billing_contact_address}` | Straße und Hausnummer | | `{billing_contact_zip}` | Postleitzahl | | `{billing_contact_town}` | Ort | @@ -41,7 +42,8 @@ Dolibarr-Modul zur Verwendung von Rechnungs-, Liefer- und Serviceadressen in ODT | Tag | Beschreibung | |-----|--------------| | `{delivery_contact_firstname}` | Vorname | -| `{delivery_contact_name}` | Vorname (Fallback: Nachname) | +| `{delivery_contact_name}` | Nachname | +| `{delivery_contact_fullname}` | Vorname + Nachname | | `{delivery_contact_address}` | Straße und Hausnummer | | `{delivery_contact_zip}` | Postleitzahl | | `{delivery_contact_town}` | Ort | @@ -52,7 +54,8 @@ Dolibarr-Modul zur Verwendung von Rechnungs-, Liefer- und Serviceadressen in ODT | Tag | Beschreibung | |-----|--------------| | `{service_contact_firstname}` | Vorname | -| `{service_contact_name}` | Vorname (Fallback: Nachname) | +| `{service_contact_name}` | Nachname | +| `{service_contact_fullname}` | Vorname + Nachname | | `{service_contact_address}` | Straße und Hausnummer | | `{service_contact_zip}` | Postleitzahl | | `{service_contact_town}` | Ort | @@ -63,22 +66,22 @@ Dolibarr-Modul zur Verwendung von Rechnungs-, Liefer- und Serviceadressen in ODT ### Beispiel: Rechnungsadresse mit Fallback auf Kundenadresse ``` -[!-- IF {billing_contact_name} --] -{billing_contact_name} +[!-- IF {billing_contact_fullname} --] +{billing_contact_fullname} {billing_contact_address} {billing_contact_zip} {billing_contact_town} -[!-- ELSE {billing_contact_name} --] +[!-- ELSE {billing_contact_fullname} --] {company_name} {company_address} {company_zip} {company_town} -[!-- ENDIF {billing_contact_name} --] +[!-- ENDIF {billing_contact_fullname} --] ``` ### Beispiel: Zwei Adressen nebeneinander ``` Rechnungsadresse: Lieferadresse: -{billing_contact_name} {delivery_contact_name} +{billing_contact_fullname} {delivery_contact_fullname} {billing_contact_address} {delivery_contact_address} {billing_contact_zip} {billing_contact_town} {delivery_contact_zip} {delivery_contact_town} ``` @@ -92,16 +95,6 @@ Rechnungsadresse: Lieferadresse: - **Kundenkontakt für Lieferung** (SHIPPING) → `delivery_contact_*` - **Kundenkontakt für Service** (SERVICE) → `service_contact_*` -## Debugging - -Bei Problemen Log-Level auf DEBUG setzen: - -1. Home → Setup → Logs → Syslog aktivieren -2. Dokument generieren -3. Log prüfen (z.B. `dolibarr.log`) - -Relevante Log-Einträge beginnen mit: `DeliveryInvoiceAddress:` - ## Technische Details ### Datenbankstruktur @@ -111,6 +104,7 @@ Relevante Log-Einträge beginnen mit: `DeliveryInvoiceAddress:` | `llx_element_contact` | Verknüpfung Dokument ↔ Kontakt | | `llx_c_type_contact` | Kontakttyp-Definitionen | | `llx_socpeople` | Kontaktdaten | +| `llx_c_country` | Länderbezeichnung | ### Hauptfunktion diff --git a/core/substitutions/functions_deliveryinvoiceaddress.lib.php b/core/substitutions/functions_deliveryinvoiceaddress.lib.php index 063358b..4f88eb8 100755 --- a/core/substitutions/functions_deliveryinvoiceaddress.lib.php +++ b/core/substitutions/functions_deliveryinvoiceaddress.lib.php @@ -1,140 +1,95 @@ id)) { - dol_syslog("DeliveryInvoiceAddress: Object ist null oder hat keine ID - überspringe", LOG_DEBUG); return; } - dol_syslog("DeliveryInvoiceAddress: START - Object class: ".get_class($object).", ID: ".$object->id, LOG_DEBUG); - - // Bestimme den Element-Typ basierend auf dem Objekt - $elementType = isset($object->element) ? $object->element : ''; - + // Element-Typ bestimmen (facture, propal, commande) + $elementType = $object->element ?? ''; if (empty($elementType)) { - dol_syslog("DeliveryInvoiceAddress: Kein Element-Typ gefunden - überspringe", LOG_DEBUG); return; } - dol_syslog("DeliveryInvoiceAddress: Element-Typ: ".$elementType, LOG_DEBUG); + // Platzhalter-Prefixe je Kontakttyp + $codeToPrefix = array( + 'BILLING' => 'billing_contact', + 'CUSTOMER' => 'billing_contact', // Fallback für Angebote/Aufträge + 'SERVICE' => 'service_contact', + 'SHIPPING' => 'delivery_contact', + ); - // Initialisiere alle Felder - $substitutionarray['billing_contact_firstname'] = ''; - $substitutionarray['billing_contact_name'] = ''; - $substitutionarray['billing_contact_address'] = ''; - $substitutionarray['billing_contact_zip'] = ''; - $substitutionarray['billing_contact_town'] = ''; - $substitutionarray['billing_contact_country'] = ''; + // Felder pro Kontakt + $fields = array('firstname', 'name', 'fullname', 'address', 'zip', 'town', 'country'); - $substitutionarray['service_contact_firstname'] = ''; - $substitutionarray['service_contact_name'] = ''; - $substitutionarray['service_contact_address'] = ''; - $substitutionarray['service_contact_zip'] = ''; - $substitutionarray['service_contact_town'] = ''; - $substitutionarray['service_contact_country'] = ''; + // Alle Platzhalter leer initialisieren + foreach (array('billing_contact', 'service_contact', 'delivery_contact') as $prefix) { + foreach ($fields as $field) { + $substitutionarray[$prefix.'_'.$field] = ''; + } + } - $substitutionarray['delivery_contact_firstname'] = ''; - $substitutionarray['delivery_contact_name'] = ''; - $substitutionarray['delivery_contact_address'] = ''; - $substitutionarray['delivery_contact_zip'] = ''; - $substitutionarray['delivery_contact_town'] = ''; - $substitutionarray['delivery_contact_country'] = ''; - - // Lade Kontakte direkt aus der DB - mit korrektem element-Typ! - $sql = "SELECT ec.rowid, ec.fk_socpeople, tc.code"; + // Kontaktdaten per JOIN direkt laden + $sql = "SELECT tc.code, sp.rowid, sp.firstname, sp.lastname, sp.address, sp.zip, sp.town,"; + $sql .= " co.label as country"; $sql .= " FROM ".MAIN_DB_PREFIX."element_contact as ec"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_type_contact as tc ON ec.fk_c_type_contact = tc.rowid"; + $sql .= " JOIN ".MAIN_DB_PREFIX."c_type_contact as tc ON ec.fk_c_type_contact = tc.rowid"; + $sql .= " JOIN ".MAIN_DB_PREFIX."socpeople as sp ON ec.fk_socpeople = sp.rowid"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as co ON sp.fk_pays = co.rowid"; $sql .= " WHERE ec.element_id = ".((int) $object->id); $sql .= " AND tc.element = '".$db->escape($elementType)."'"; $sql .= " AND tc.code IN ('BILLING', 'SERVICE', 'SHIPPING', 'CUSTOMER')"; - dol_syslog("DeliveryInvoiceAddress: SQL: ".$sql, LOG_DEBUG); - $resql = $db->query($sql); if (!$resql) { - dol_syslog("DeliveryInvoiceAddress: SQL ERROR: ".$db->lasterror(), LOG_ERR); + dol_syslog("DeliveryInvoiceAddress: SQL FEHLER: ".$db->lasterror(), LOG_ERR); return; } - $num = $db->num_rows($resql); - dol_syslog("DeliveryInvoiceAddress: ".$num." Kontakte gefunden", LOG_DEBUG); - - if ($num == 0) { - dol_syslog("DeliveryInvoiceAddress: Keine Kontakte gefunden - ENDE", LOG_DEBUG); - return; - } - - require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; - while ($obj = $db->fetch_object($resql)) { - dol_syslog("DeliveryInvoiceAddress: Verarbeite Kontakt - ID: ".$obj->fk_socpeople.", Code: ".$obj->code, LOG_DEBUG); - - $contactobj = new Contact($db); - $result = $contactobj->fetch($obj->fk_socpeople); - - if ($result > 0) { - $firstname = isset($contactobj->firstname) ? $contactobj->firstname : ''; - $lastname = isset($contactobj->lastname) ? $contactobj->lastname : ''; - $address = isset($contactobj->address) ? $contactobj->address : ''; - $zip = isset($contactobj->zip) ? $contactobj->zip : ''; - $town = isset($contactobj->town) ? $contactobj->town : ''; - $country = isset($contactobj->country) ? $contactobj->country : ''; - - // Name-Logik: Vorname falls vorhanden, sonst Nachname - $name = !empty($firstname) ? $firstname : $lastname; - - dol_syslog("DeliveryInvoiceAddress: Kontakt geladen - Vorname: ".$firstname.", Nachname: ".$lastname.", Code: ".$obj->code, LOG_DEBUG); - - // BILLING und CUSTOMER werden beide als Rechnungskontakt behandelt - // BILLING hat Priorität, CUSTOMER nur wenn BILLING noch leer ist - if ($obj->code == 'BILLING') { - $substitutionarray['billing_contact_firstname'] = $firstname; - $substitutionarray['billing_contact_name'] = $name; - $substitutionarray['billing_contact_address'] = $address; - $substitutionarray['billing_contact_zip'] = $zip; - $substitutionarray['billing_contact_town'] = $town; - $substitutionarray['billing_contact_country'] = $country; - dol_syslog("DeliveryInvoiceAddress: BILLING gesetzt: ".$name." - ".$address, LOG_DEBUG); - } - elseif ($obj->code == 'CUSTOMER' && empty($substitutionarray['billing_contact_name'])) { - // CUSTOMER als Fallback für billing_contact (bei Angeboten/Aufträgen) - $substitutionarray['billing_contact_firstname'] = $firstname; - $substitutionarray['billing_contact_name'] = $name; - $substitutionarray['billing_contact_address'] = $address; - $substitutionarray['billing_contact_zip'] = $zip; - $substitutionarray['billing_contact_town'] = $town; - $substitutionarray['billing_contact_country'] = $country; - dol_syslog("DeliveryInvoiceAddress: CUSTOMER als BILLING gesetzt: ".$name." - ".$address, LOG_DEBUG); - } - elseif ($obj->code == 'SERVICE') { - $substitutionarray['service_contact_firstname'] = $firstname; - $substitutionarray['service_contact_name'] = $name; - $substitutionarray['service_contact_address'] = $address; - $substitutionarray['service_contact_zip'] = $zip; - $substitutionarray['service_contact_town'] = $town; - $substitutionarray['service_contact_country'] = $country; - dol_syslog("DeliveryInvoiceAddress: SERVICE gesetzt: ".$name." - ".$address, LOG_DEBUG); - } - elseif ($obj->code == 'SHIPPING') { - $substitutionarray['delivery_contact_firstname'] = $firstname; - $substitutionarray['delivery_contact_name'] = $name; - $substitutionarray['delivery_contact_address'] = $address; - $substitutionarray['delivery_contact_zip'] = $zip; - $substitutionarray['delivery_contact_town'] = $town; - $substitutionarray['delivery_contact_country'] = $country; - dol_syslog("DeliveryInvoiceAddress: SHIPPING gesetzt: ".$name." - ".$address, LOG_DEBUG); - } - } else { - dol_syslog("DeliveryInvoiceAddress: FEHLER beim Laden von Kontakt ID ".$obj->fk_socpeople, LOG_ERR); + $prefix = $codeToPrefix[$obj->code] ?? null; + if (!$prefix) { + continue; } + + // CUSTOMER nur als Fallback wenn BILLING noch leer + if ($obj->code == 'CUSTOMER' && !empty($substitutionarray['billing_contact_name'])) { + continue; + } + + $firstname = $obj->firstname ?? ''; + $lastname = $obj->lastname ?? ''; + + // Fullname: Vorname + Nachname, Reihenfolge je nach Dolibarr-Einstellung + $fullname = trim($firstname.' '.$lastname); + if (getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION')) { + $fullname = trim($lastname.' '.$firstname); + } + + $substitutionarray[$prefix.'_firstname'] = $firstname; + $substitutionarray[$prefix.'_name'] = $lastname; + $substitutionarray[$prefix.'_fullname'] = $fullname; + $substitutionarray[$prefix.'_address'] = $obj->address ?? ''; + $substitutionarray[$prefix.'_zip'] = $obj->zip ?? ''; + $substitutionarray[$prefix.'_town'] = $obj->town ?? ''; + $substitutionarray[$prefix.'_country'] = $obj->country ?? ''; } $db->free($resql); - - dol_syslog("DeliveryInvoiceAddress: ENDE - Alle Substitutionen gesetzt", LOG_DEBUG); } -?>