From 3f9a11366396d56d82dd5efdfe326651d358adf9 Mon Sep 17 00:00:00 2001 From: jps Date: Wed, 14 Jan 2026 10:02:07 +0100 Subject: [PATCH] =?UTF-8?q?am=C3=A9lioration=20diverse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/config.php | 131 ++++++++++++++++++++++++++ app/controllers/Peppol_controller.php | 118 +++++++++++++++++------ templates/admin/settings.php | 2 +- 3 files changed, 223 insertions(+), 28 deletions(-) diff --git a/app/config.php b/app/config.php index b3d9bbc..65d34b9 100644 --- a/app/config.php +++ b/app/config.php @@ -1 +1,132 @@ 'https://peppol.esi-web.be/api', + + /** + * URL de base de l'API ESIPeppol (environnement de test) + * + * @var string + */ + 'api_test_base_url' => 'https://demo.esi-peppol.be/api', + + /** + * Active l'utilisation de l'environnement de test + * Si true, utilise api_test_base_url, sinon utilise api_base_url + * + * @var bool + */ + 'is_test_environment' => true, + + /** + * Timeout pour les requêtes API (en secondes) + * + * @var int + */ + 'api_timeout' => 20, + + /** + * Configuration des factures + */ + 'invoice' => [ + /** + * Nombre de jours avant l'échéance par défaut + * + * @var int + */ + 'default_due_days' => 30, + + /** + * Préfixe pour la référence externe (ex: 'WC-' pour WooCommerce) + * + * @var string + */ + 'external_reference_prefix' => 'WC-', + + /** + * Termes de paiement par défaut + * + * @var string + */ + 'default_payment_terms' => 'Paiement à 30 jours nets', + ], + + /** + * Configuration des identifiants de produits + */ + 'item_ids' => [ + /** + * Préfixe pour les identifiants de produits + * Format: {prefix}{SKU ou ID} + * + * @var string + */ + 'product_prefix' => 'P_', + + /** + * Préfixe pour les frais de livraison + * Format: {prefix}{line_number} + * + * @var string + */ + 'shipping_prefix' => 'SHIPCQT_', + + /** + * Préfixe pour les frais supplémentaires + * Format: {prefix}{line_number} + * + * @var string + */ + 'fee_prefix' => 'FEE_', + ], + + /** + * Configuration des unités de mesure + */ + 'units' => [ + /** + * Code d'unité de mesure par défaut (C62 = "Unit") + * + * @var string + */ + 'default_unit_of_measure' => 'C62', + ], + + /** + * Configuration de la taxe (TVA) + */ + 'tax' => [ + /** + * Identifiant du schéma de taxe + * + * @var string + */ + 'scheme_id' => 'VAT', + + /** + * Nom du schéma de taxe + * + * @var string + */ + 'scheme_name' => 'Value Added Tax', + ], +]; diff --git a/app/controllers/Peppol_controller.php b/app/controllers/Peppol_controller.php index 3a4b78a..3431181 100644 --- a/app/controllers/Peppol_controller.php +++ b/app/controllers/Peppol_controller.php @@ -8,22 +8,80 @@ use ESI_PEPPOL\helpers\PEPPOL_Woo_Helper; class PEPPOL_peppol_controller { /** - * URL de base de l'API ESIPeppol. + * Cache de la configuration chargée. + * + * @var array|null */ - private const API_BASE_URL = 'https://demo.esi-peppol.be/api'; + private static $config_cache = null; + + /** + * Charge la configuration depuis le fichier config.php. + * + * @return array + */ + protected static function get_config(): array { + if (self::$config_cache === null) { + $config_file = ESI_PEPPOL_DIR . 'app/config.php'; + if (file_exists($config_file)) { + self::$config_cache = require $config_file; + } else { + self::$config_cache = []; + } + } + + return self::$config_cache; + } + + /** + * Récupère une valeur de configuration avec une valeur par défaut. + * + * @param string $key Clé de configuration (peut être un chemin avec des points, ex: 'invoice.default_due_days'). + * @param mixed $default Valeur par défaut si la clé n'existe pas. + * + * @return mixed + */ + protected static function get_config_value(string $key, $default = null) { + $config = self::get_config(); + + // Support pour les clés imbriquées (ex: 'invoice.default_due_days') + if (strpos($key, '.') !== false) { + $keys = explode('.', $key); + $value = $config; + + foreach ($keys as $k) { + if (!is_array($value) || !isset($value[$k])) { + return $default; + } + $value = $value[$k]; + } + + return $value; + } + + return isset($config[$key]) ? $config[$key] : $default; + } /** * Retourne l'URL de base de l'API (filtrable). + * Utilise l'URL de test si is_test_environment est activé, sinon l'URL de production. * * @return string */ protected static function get_base_url(): string { + $is_test = (bool) self::get_config_value('is_test_environment', false); + + if ($is_test) { + $api_base_url = self::get_config_value('api_test_base_url', 'https://demo.esi-peppol.be/api'); + } else { + $api_base_url = self::get_config_value('api_base_url', 'https://peppol.esi-web.be/api'); + } + /** * Filtre pour surcharger l'URL de base de l'API ESIPeppol. * * @param string $base_url URL de base actuelle. */ - return (string) \apply_filters('esi_peppol_api_base_url', self::API_BASE_URL); + return (string) \apply_filters('esi_peppol_api_base_url', $api_base_url); } /** @@ -91,7 +149,7 @@ class PEPPOL_peppol_controller { $wp_args = [ 'method' => $method, - 'timeout' => 20, + 'timeout' => (int) self::get_config_value('api_timeout', 20), 'headers' => $headers, ]; @@ -295,8 +353,8 @@ class PEPPOL_peppol_controller { 'vat_category_code' => 'S', 'taxable_amount' => 0.0, 'vat_amount' => 0.0, - 'tax_scheme_id' => 'VAT', - 'tax_scheme_name' => 'Value Added Tax', + 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'), + 'tax_scheme_name' => self::get_config_value('tax.scheme_name', 'Value Added Tax'), ]; } @@ -322,8 +380,8 @@ class PEPPOL_peppol_controller { 'vat_category_code' => 'S', 'taxable_amount' => 0.0, 'vat_amount' => 0.0, - 'tax_scheme_id' => 'VAT', - 'tax_scheme_name' => 'Value Added Tax', + 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'), + 'tax_scheme_name' => self::get_config_value('tax.scheme_name', 'Value Added Tax'), ]; } @@ -359,8 +417,8 @@ class PEPPOL_peppol_controller { 'vat_category_code' => 'S', 'taxable_amount' => 0.0, 'vat_amount' => 0.0, - 'tax_scheme_id' => 'VAT', - 'tax_scheme_name' => 'Value Added Tax', + 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'), + 'tax_scheme_name' => self::get_config_value('tax.scheme_name', 'Value Added Tax'), ]; } @@ -380,8 +438,8 @@ class PEPPOL_peppol_controller { 'vat_category_code' => 'E', 'taxable_amount' => 0.0, 'vat_amount' => 0.0, - 'tax_scheme_id' => 'VAT', - 'tax_scheme_name' => 'Value Added Tax', + 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'), + 'tax_scheme_name' => self::get_config_value('tax.scheme_name', 'Value Added Tax'), ]; } @@ -457,18 +515,20 @@ class PEPPOL_peppol_controller { ? $order->get_date_created()->date('Y-m-d') : \gmdate('Y-m-d'); - // Par défaut, échéance à +30 jours (filtrable) + // Par défaut, échéance configurable (filtrable) + $default_due_days = (int) self::get_config_value('invoice.default_due_days', 30); $due_date = \apply_filters( 'esi_peppol_invoice_due_date', (new \DateTimeImmutable($invoice_date)) - ->modify('+30 days') + ->modify('+' . $default_due_days . ' days') ->format('Y-m-d'), $order ); + $external_reference_prefix = self::get_config_value('invoice.external_reference_prefix', 'WC-'); $external_reference = \apply_filters( 'esi_peppol_external_reference', - 'WC-' . $order_number, + $external_reference_prefix . $order_number, $order ); @@ -482,9 +542,10 @@ class PEPPOL_peppol_controller { $order ); + $default_payment_terms = self::get_config_value('invoice.default_payment_terms', __('Paiement à 30 jours nets', 'esi_peppol')); $payment_terms = \apply_filters( 'esi_peppol_payment_terms', - __('Paiement à 30 jours nets', 'esi_peppol'), + $default_payment_terms, $order ); @@ -628,7 +689,7 @@ class PEPPOL_peppol_controller { $is_zero_vat_amount = ($vat_amount == 0.0); $vat_category_code = $is_zero_vat_amount ? 'E' : 'S'; - $unit_of_measure = 'C62'; // "Unit" code par défaut + $unit_of_measure = self::get_config_value('units.default_unit_of_measure', 'C62'); // "Unit" code par défaut if ($product && $product->get_meta('unit_of_measure')) { $unit_of_measure = (string) $product->get_meta('unit_of_measure'); @@ -636,9 +697,10 @@ class PEPPOL_peppol_controller { $seller_item_id = ''; if ($product) { - // Pour les produits : P_ + SKU si existant, sinon P_ + ID produit + // Pour les produits : préfixe configurable + SKU si existant, sinon préfixe + ID produit + $product_prefix = self::get_config_value('item_ids.product_prefix', 'P_'); $base_id = $product->get_sku() ?: (string) $product->get_id(); - $seller_item_id = 'P_' . $base_id; + $seller_item_id = $product_prefix . $base_id; } // Description courte sans balises HTML pour compatibilité PEPPOL @@ -740,8 +802,9 @@ class PEPPOL_peppol_controller { $is_zero_vat_amount = ($vat_amount == 0.0); $vat_category_code = $is_zero_vat_amount ? 'E' : 'S'; - // Identifiant vendeur pour les frais de livraison : préfixe SHIPCQT_ + n° de ligne - $seller_item_id = 'SHIPCQT_' . $line_number; + // Identifiant vendeur pour les frais de livraison : préfixe configurable + n° de ligne + $shipping_prefix = self::get_config_value('item_ids.shipping_prefix', 'SHIPCQT_'); + $seller_item_id = $shipping_prefix . $line_number; $line = [ 'line_number' => $line_number, @@ -749,7 +812,7 @@ class PEPPOL_peppol_controller { 'item_description' => '', 'seller_item_id' => $seller_item_id, 'quantity' => $quantity, - 'unit_of_measure' => 'C62', + 'unit_of_measure' => self::get_config_value('units.default_unit_of_measure', 'C62'), 'unit_price' => round($unit_price, 2), 'vat_rate' => $vat_rate, 'vat_category_code' => $vat_category_code, @@ -826,8 +889,9 @@ class PEPPOL_peppol_controller { $is_zero_vat_amount = ($vat_amount == 0.0); $vat_category_code = $is_zero_vat_amount ? 'E' : 'S'; - // Identifiant vendeur pour les frais supplémentaires : préfixe FEE_ + n° de ligne - $seller_item_id = 'FEE_' . $line_number; + // Identifiant vendeur pour les frais supplémentaires : préfixe configurable + n° de ligne + $fee_prefix = self::get_config_value('item_ids.fee_prefix', 'FEE_'); + $seller_item_id = $fee_prefix . $line_number; $line = [ 'line_number' => $line_number, @@ -835,7 +899,7 @@ class PEPPOL_peppol_controller { 'item_description' => '', 'seller_item_id' => $seller_item_id, 'quantity' => $quantity, - 'unit_of_measure' => 'C62', + 'unit_of_measure' => self::get_config_value('units.default_unit_of_measure', 'C62'), 'unit_price' => round($unit_price, 2), 'vat_rate' => $vat_rate, 'vat_category_code' => $vat_category_code, @@ -915,8 +979,8 @@ class PEPPOL_peppol_controller { 'total_amount_excluding_vat' => round($total_excl_vat, 2), 'total_vat_amount' => round($total_vat, 2), 'total_amount_including_vat' => round($total_incl_vat, 2), - 'total_paid_amount' => 0.0, - 'total_payable_amount' => round($order->get_total(), 2), + 'total_paid_amount' => round($order->get_total(), 2), + 'total_payable_amount' => 0, 'amount_due' => round($order->get_total(), 2), ]; diff --git a/templates/admin/settings.php b/templates/admin/settings.php index f063fe3..d73804b 100644 --- a/templates/admin/settings.php +++ b/templates/admin/settings.php @@ -142,7 +142,7 @@ if ($logo_email_id) { printf( wp_kses_post( /* translators: %s: URL de la documentation */ - __('Configurez cette URL dans votre profil d\'entreprise via l\'interface d\'administration Filament de l\'API ESI Peppol. Les webhooks permettent de recevoir des notifications automatiques lorsque le statut d\'un document change. En savoir plus.', 'esi_peppol') + __('Configurez cette URL dans votre profil d\'entreprise sur la plateforme https://peppol.esi-web.be/. Les webhooks permettent de recevoir des notifications automatiques lorsque le statut d\'un document change. En savoir plus.', 'esi_peppol') ), esc_url('https://demo.esi-peppol.be/api-demo.html#webhooks') );