get_taxes(); // ['total' => [rate_id => amount], 'subtotal' => ...] $out = []; if ( ! empty( $taxes['total'] ) ) { foreach ( $taxes['total'] as $rate_id => $tax_amount ) { $tax_amount = floatval( $tax_amount ); if ( $tax_amount == 0 ) continue; $rate = \WC_Tax::_get_tax_rate( $rate_id ); $out[] = [ 'rate_id' => (int) $rate_id, 'percent' => floatval( $rate['tax_rate'] ), 'name' => $rate['tax_rate_name'], 'class' => $rate['tax_rate_class'], // 'standard', 'reduced-rate', etc. 'amount' => $tax_amount, 'compound'=> (bool) $rate['tax_rate_compound'], ]; } } return $out; } public static function esi_get_order_vat_number( $order ) { if ( is_numeric( $order ) ) { $order = wc_get_order( $order ); } if ( ! $order instanceof \WC_Order ) { return ''; } // 1) Clés les plus courantes (ajuste/complète si besoin) $known_keys = [ '_billing_vat_number', 'billing_vat_number', '_vat_number', 'vat_number', '_billing_vat', 'billing_vat', '_billing_tva', 'billing_tva', '_tva', 'tva', 'eu_vat_number', '_eu_vat_number', 'vat_id', '_vat_id', ]; foreach ( $known_keys as $key ) { $val = $order->get_meta( $key, true ); if ( ! empty( $val ) ) { return is_string($val) ? trim($val) : $val; } } // 2) Fallback: scan des meta keys contenant vat/tva $vat_candidates = []; foreach ( $order->get_meta_data() as $meta ) { $k = (string) $meta->key; if ( preg_match('/\b(vat|tva)\b/i', $k) || preg_match('/(vat|tva)/i', $k) ) { $v = $meta->value; if ( is_string($v) ) { $v = trim($v); } if ( ! empty($v) ) { $vat_candidates[$k] = $v; } } } // Si plusieurs candidats, tu peux choisir une règle // Ici: si un seul => return, sinon priorise ceux qui contiennent "billing" if ( count($vat_candidates) === 1 ) { return reset($vat_candidates); } foreach ( $vat_candidates as $k => $v ) { if ( stripos($k, 'billing') !== false ) { return $v; } } // sinon le 1er trouvé return ! empty($vat_candidates) ? reset($vat_candidates) : ''; } public static function esi_get_order_vat( $order ) { if ( is_numeric($order) ) { $order = wc_get_order($order); } if ( ! $order instanceof WC_Order ) { return [ 'found' => false, 'key' => null, 'value' => null, 'source' => null, ]; } $patterns = [ 'vat','tva','btw','ust','mwst','piva','moms','mva' ]; /* ================================================== * 1) CHECKOUT FIELDS (si présents) * ================================================== */ if ( function_exists('WC') && WC()->checkout() ) { $fields = WC()->checkout()->get_checkout_fields(); foreach ( $fields as $group_fields ) { foreach ( $group_fields as $key => $def ) { $k = strtolower($key); foreach ( $patterns as $p ) { if ( strpos($k, $p) !== false ) { // tentatives de lecture meta foreach ( [ $key, '_' . $key ] as $meta_key ) { $val = $order->get_meta($meta_key, true); if ( ! empty($val) ) { return [ 'found' => true, 'key' => $meta_key, 'value' => trim((string)$val), 'source' => 'checkout_field', ]; } } } } // fallback label $label = strtolower((string)($def['label'] ?? '')); if ( $label && preg_match('/\b(vat|tva|btw|mwst|ust|piva|moms|mva)\b/i', $label) ) { foreach ( [ $key, '_' . $key ] as $meta_key ) { $val = $order->get_meta($meta_key, true); if ( ! empty($val) ) { return [ 'found' => true, 'key' => $meta_key, 'value' => trim((string)$val), 'source' => 'checkout_label', ]; } } } } } } /* ================================================== * 2) SCAN META (fallback ultime) * ================================================== */ foreach ( $order->get_meta_data() as $meta ) { $k = strtolower((string)$meta->key); foreach ( $patterns as $p ) { if ( strpos($k, $p) !== false ) { $v = $meta->value; if ( is_string($v) ) $v = trim($v); if ( ! empty($v) ) { return [ 'found' => true, 'key' => $meta->key, 'value' => $v, 'source' => 'meta_scan', ]; } } } } return [ 'found' => false, 'key' => null, 'value' => null, '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, ]; } } } } } } } // Si aucun champ n'a été trouvé dans les groupes billing/shipping, // chercher dans toutes les meta keys contenant un pattern if (empty($vat_fields_found)) { foreach ($order->get_meta_data() as $meta) { $k = (string) $meta->key; $k_lower = strtolower($k); // 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' => 'other', // Groupe "other" pour les champs hors billing/shipping ]; } } } } } return array_values($vat_fields_found); } /** * Retourne les infos de paiement utiles pour Peppol. * * @param \WC_Order|int $order * @return array{payment_method:string,payment_method_title:string,payment_means_code:string,payment_terms:string} */ public static function esi_get_order_payment_data( $order ): array { if ( is_numeric( $order ) ) { $order = wc_get_order( $order ); } if ( ! $order instanceof \WC_Order ) { return [ 'payment_method' => '', 'payment_method_title' => '', 'payment_means_code' => '30', 'payment_terms' => '', ]; } $payment_method = (string) $order->get_payment_method(); $payment_method_title = (string) $order->get_payment_method_title(); // Valeur par defaut : virement (code 30) $payment_means_code = '30'; $map = [ 'bacs' => '30', // virement bancaire 'cheque' => '20', 'cod' => '10', // cash on delivery ]; if ( isset( $map[ $payment_method ] ) ) { $payment_means_code = $map[ $payment_method ]; } $data = [ 'payment_method' => $payment_method, 'payment_method_title' => $payment_method_title, 'payment_means_code' => $payment_means_code, 'payment_terms' => '', ]; return apply_filters( 'esi_peppol_order_payment_data', $data, $order ); } public static function esi_is_wpo_wcpdf_installed(): bool { if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $plugins = get_plugins(); // [ 'dir/main.php' => headers... ] foreach ($plugins as $file => $data) { if ($file === 'woocommerce-pdf-invoices-packing-slips/woocommerce-pdf-invoices-packingslips.php') { return true; } // Optionnel : fallback par Name (plus fragile, dépend de la traduction / headers) if (!empty($data['Name']) && stripos($data['Name'], 'PDF Invoices') !== false) { // pas ultra fiable, mais utile en dernier recours } } return false; } /** * detecte les num de facture enregistré */ //wpo_wcpdf_documents_settings_invoice /* Array ( [enabled] => 1 [attach_to_email_ids] => Array ( [customer_on_hold_order] => 1 [customer_processing_order] => 1 [customer_completed_order] => 1 ) [my_account_buttons] => available [display_email] => 1 [display_customer_notes] => 1 [display_shipping_address] => [display_number] => invoice_number [number_format] => Array ( [prefix] => 2026- [suffix] => [padding] => ) [display_date] => )*/ /** * Vérifie la présence de numéros de facture WPO WCPDF. * - Plugin installé * - Paramètres facture activés * - Au moins une commande avec meta _wcpdf_invoice_number */ public static function esi_has_wpo_invoice_numbers(): bool { if ( ! self::esi_is_wpo_wcpdf_installed() ) { return false; } if ( ! function_exists( 'wc_get_orders' ) ) { return false; } $settings = get_option( 'wpo_wcpdf_documents_settings_invoice', [] ); if ( empty( $settings ) || ! is_array( $settings ) ) { return false; } if ( empty( $settings['enabled'] ) ) { return false; } if ( empty( $settings['display_number'] ) || $settings['display_number'] !== 'invoice_number' ) { return false; } $orders = wc_get_orders( [ 'limit' => 1, 'status' => 'any', 'meta_key' => '_wcpdf_invoice_number', 'meta_compare' => 'EXISTS', 'return' => 'ids', ] ); return ! empty( $orders ); } /** * Retourne un libellé lisible du format des numéros WPO WCPDF. */ public static function esi_get_wpo_invoice_number_format_label(): string { $settings = get_option( 'wpo_wcpdf_documents_settings_invoice', [] ); if ( empty( $settings ) || ! is_array( $settings ) ) { return ''; } $number_format = $settings['number_format'] ?? []; if ( ! is_array( $number_format ) ) { return ''; } $prefix = (string) ( $number_format['prefix'] ?? '' ); $suffix = (string) ( $number_format['suffix'] ?? '' ); $padding = (string) ( $number_format['padding'] ?? '' ); $format = $prefix . '{number}' . $suffix; if ( $padding !== '' ) { $format .= ' (padding: ' . $padding . ')'; } return $format; } }