From ce1be909de26445d003a09bec099b4f81becfbbb Mon Sep 17 00:00:00 2001 From: jps Date: Wed, 14 Jan 2026 16:19:55 +0100 Subject: [PATCH] =?UTF-8?q?Am=C3=A9lioration=20trigger=20check=20champ=20t?= =?UTF-8?q?va?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/Plugin.php | 122 +++++++++++++++++++++++++++++++++-- app/helpers/Woo_Helper.php | 102 +++++++++++++++++++++++++++++ templates/admin/settings.php | 28 +++++--- 3 files changed, 238 insertions(+), 14 deletions(-) diff --git a/app/controllers/Plugin.php b/app/controllers/Plugin.php index bf4db59..fba0bec 100644 --- a/app/controllers/Plugin.php +++ b/app/controllers/Plugin.php @@ -15,13 +15,16 @@ class PEPPOL_Plugin { * Méthode appelée lors de l'activation du plugin. * * Elle délègue au modèle principal la création de la table - * `esi_peppol_invoices`. + * `esi_peppol_invoices` et détecte automatiquement les champs TVA. * * @return void */ public static function activate(): void { // Création / mise à jour de la table principale des factures PEPPOL_Main_model::create_table(); + + // Détection automatique des champs TVA (billing -> shipping) + self::auto_detect_vat_field_on_install(); } public function desactivate() { @@ -683,6 +686,91 @@ class PEPPOL_Plugin { wp_send_json_error($payload_response, 200); } + /** + * Détecte automatiquement les champs TVA lors de l'installation. + * Limite la recherche aux champs billing et shipping dans cet ordre. + * Utilise la fonction helper PEPPOL_Woo_Helper::esi_detect_vat_fields_billing_shipping(). + * + * @return string|null La clé du champ TVA détecté, ou null si aucun trouvé + */ + public static function auto_detect_vat_field_on_install(): ?string { + // Ne pas détecter si un champ est déjà sauvegardé + $existing_field = get_option('esi_peppol_vat_field_key', ''); + if ($existing_field !== '') { + return $existing_field; + } + + // Vérifier si WooCommerce est disponible + if (!function_exists('wc_get_orders')) { + // Marquer que la détection a été tentée (même si WooCommerce n'est pas disponible) + update_option('esi_peppol_vat_field_auto_detected', true); + return null; + } + + // Récupérer les dernières commandes pour scanner les champs TVA + $orders = wc_get_orders([ + 'limit' => 50, + 'orderby' => 'date', + 'order' => 'DESC', + 'status' => ['completed', 'processing', 'on-hold'], + ]); + + $vat_fields_found = []; + + // Utiliser la fonction helper pour détecter les champs TVA dans chaque commande + foreach ($orders as $order) { + if (!$order instanceof \WC_Order) { + continue; + } + + $fields = \ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_detect_vat_fields_billing_shipping($order); + + // Compter les occurrences de chaque champ + foreach ($fields as $field) { + $key = $field['key']; + if (!isset($vat_fields_found[$key])) { + $vat_fields_found[$key] = [ + 'key' => $key, + 'count' => 0, + 'group' => $field['group'], + ]; + } + $vat_fields_found[$key]['count']++; + } + } + + // Si aucun champ trouvé, marquer que la détection a été effectuée et retourner null + if (empty($vat_fields_found)) { + update_option('esi_peppol_vat_field_auto_detected', true); + return null; + } + + // Trier : d'abord par groupe (billing avant shipping), puis par nombre d'occurrences + usort($vat_fields_found, function ($a, $b) { + // Priorité au groupe billing + if ($a['group'] === 'billing' && $b['group'] !== 'billing') { + return -1; + } + if ($a['group'] !== 'billing' && $b['group'] === 'billing') { + return 1; + } + // Si même groupe, trier par nombre d'occurrences + return $b['count'] - $a['count']; + }); + + // Prendre le premier champ trouvé (priorité billing) + $selected_field = reset($vat_fields_found); + $vat_field_key = $selected_field['key']; + + // Sauvegarder le champ détecté + update_option('esi_peppol_vat_field_key', $vat_field_key); + + // Marquer que la détection a été effectuée à l'installation + update_option('esi_peppol_vat_field_auto_detected', true); + + return $vat_field_key; + } + /** * Handler AJAX pour détecter les champs TVA dans les commandes WooCommerce. * @@ -1075,16 +1163,31 @@ class PEPPOL_Plugin { /** * Retourne un message d'avertissement à propos du numéro de TVA * de la boutique si celui-ci n'est pas encore renseigné dans - * les réglages WooCommerce. + * les réglages WooCommerce, ou si aucun champ TVA client n'a été détecté. * * - Message d'invitation initial : aucune configuration ESI Peppol * n'a encore été saisie. * - Message de rappel : les identifiants ESI Peppol sont déjà * enregistrés mais la TVA reste vide. + * - Message si aucun champ TVA client détecté : proposer la détection dans settings. * * @return string|null */ public static function get_vat_notice_message(): ?string { + // Vérifier d'abord si un champ TVA client a été détecté + $vat_field_key = (string) get_option('esi_peppol_vat_field_key', ''); + $auto_detected = (bool) get_option('esi_peppol_vat_field_auto_detected', false); + + // Si aucun champ TVA détecté, proposer la détection dans settings + if ($vat_field_key === '' && $auto_detected) { + $settings_url = admin_url('admin.php?page=esi-peppol-settings'); + return sprintf( + /* translators: %s: URL vers la page de réglages */ + __('Aucun champ TVA client n\'a été détecté automatiquement. Vous pouvez utiliser l\'outil de détection dans ESI Peppol > Configuration pour rechercher manuellement les champs TVA dans vos commandes.', 'esi_peppol'), + esc_url($settings_url) + ); + } + $vat_number = (string) get_option('woocommerce_store_vat_number', ''); if ($vat_number !== '') { @@ -1111,7 +1214,8 @@ class PEPPOL_Plugin { /** * Affiche un message d'avertissement dans l'admin WordPress - * si le numéro de TVA de la boutique n'est pas renseigné. + * si le numéro de TVA de la boutique n'est pas renseigné ou + * si aucun champ TVA client n'a été détecté. * * Hooké sur admin_notices. * @@ -1130,10 +1234,18 @@ class PEPPOL_Plugin { $api_key = (string) \get_option('esi_peppol_api_key', ''); $password = (string) \get_option('esi_peppol_password', ''); - $notice_class = ($api_key === '' && $password === '') ? 'notice-info' : 'notice-warning'; + $vat_field_key = (string) \get_option('esi_peppol_vat_field_key', ''); + $auto_detected = (bool) \get_option('esi_peppol_vat_field_auto_detected', false); + + // Si aucun champ TVA détecté, utiliser notice-warning + if ($vat_field_key === '' && $auto_detected) { + $notice_class = 'notice-warning'; + } else { + $notice_class = ($api_key === '' && $password === '') ? 'notice-info' : 'notice-warning'; + } echo '

' . - \esc_html($vat_notice_message) . + \wp_kses_post($vat_notice_message) . '

'; } diff --git a/app/helpers/Woo_Helper.php b/app/helpers/Woo_Helper.php index adaada8..c996fdd 100644 --- a/app/helpers/Woo_Helper.php +++ b/app/helpers/Woo_Helper.php @@ -186,5 +186,107 @@ class PEPPOL_Woo_Helper { 'source' => null, ]; } + + /** + * Détecte tous les champs TVA dans une commande, limités aux groupes billing et shipping. + * Retourne un tableau de tous les champs trouvés avec leur groupe et leur valeur. + * + * @param \WC_Order $order La commande à analyser + * @return array Tableau de champs TVA trouvés : ['key' => string, 'value' => string, 'group' => 'billing'|'shipping'] + */ + public static function esi_detect_vat_fields_billing_shipping( \WC_Order $order ): array { + $vat_fields_found = []; + $patterns = ['vat', 'tva', 'btw', 'ust', 'mwst', 'piva', 'moms', 'mva']; + + // Ordre de recherche : billing d'abord, puis shipping + $search_groups = ['billing', 'shipping']; + + foreach ($search_groups as $group) { + // Chercher dans les meta keys du groupe (billing ou shipping) + foreach ($order->get_meta_data() as $meta) { + $k = (string) $meta->key; + $k_lower = strtolower($k); + + // Vérifier que la clé commence par le groupe recherché (avec ou sans underscore) + $group_prefix = $group . '_'; + $group_prefix_underscore = '_' . $group . '_'; + if (strpos($k_lower, $group_prefix) !== 0 && strpos($k_lower, $group_prefix_underscore) !== 0) { + continue; + } + + // Vérifier si la clé contient un pattern TVA + $found = false; + + foreach ($patterns as $p) { + if (strpos($k_lower, $p) !== false) { + $found = true; + break; + } + } + + if ($found) { + $v = $meta->value; + if (is_string($v)) { + $v = trim($v); + } + if (!empty($v)) { + if (!isset($vat_fields_found[$k])) { + $vat_fields_found[$k] = [ + 'key' => $k, + 'value' => $v, + 'group' => $group, + ]; + } + } + } + } + + // Chercher aussi dans les champs de checkout du groupe + if (function_exists('WC') && WC()->checkout()) { + $fields = WC()->checkout()->get_checkout_fields(); + $group_fields = $fields[$group] ?? []; + + foreach ($group_fields as $key => $def) { + $k = strtolower($key); + $found = false; + + foreach ($patterns as $p) { + if (strpos($k, $p) !== false) { + $found = true; + break; + } + } + + if (!$found) { + $label = strtolower((string) ($def['label'] ?? '')); + foreach ($patterns as $p) { + if (preg_match('/\b' . $p . '\b/i', $label)) { + $found = true; + break; + } + } + } + + if ($found) { + // Essayer avec et sans préfixe underscore + foreach ([$key, '_' . $key] as $meta_key) { + $val = $order->get_meta($meta_key, true); + if (!empty($val)) { + if (!isset($vat_fields_found[$meta_key])) { + $vat_fields_found[$meta_key] = [ + 'key' => $meta_key, + 'value' => is_string($val) ? trim($val) : $val, + 'group' => $group, + ]; + } + } + } + } + } + } + } + + return array_values($vat_fields_found); + } } \ No newline at end of file diff --git a/templates/admin/settings.php b/templates/admin/settings.php index ad39882..558abfc 100644 --- a/templates/admin/settings.php +++ b/templates/admin/settings.php @@ -158,6 +158,7 @@ if ($logo_email_id) {
+ -

- ' . esc_html($saved_vat_field) . '' - ); - ?> -

+
+

+ + +

+ +

+ +

+ +
+ +
+

+ +

+