amélioration diverse

This commit is contained in:
Jean-Philippe Staelen 2026-01-14 10:02:07 +01:00
parent 7d5032ffdf
commit 3f9a113663
3 changed files with 223 additions and 28 deletions

View File

@ -1 +1,132 @@
<?php <?php
/**
* Configuration du plugin ESI Peppol
*
* @package ESI_PEPPOL
*/
declare(strict_types=1);
if (!defined('ABSPATH')) {
exit;
}
/**
* Configuration de l'API ESI Peppol
*/
return [
/**
* URL de base de l'API ESIPeppol (production)
*
* @var string
*/
'api_base_url' => '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',
],
];

View File

@ -8,22 +8,80 @@ use ESI_PEPPOL\helpers\PEPPOL_Woo_Helper;
class PEPPOL_peppol_controller { class PEPPOL_peppol_controller {
/** /**
* URL de base de l'API ESIPeppol. * Cache de la configuration chargée.
*
* @var array<string,mixed>|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<string,mixed>
*/
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). * 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 * @return string
*/ */
protected static function get_base_url(): 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. * Filtre pour surcharger l'URL de base de l'API ESIPeppol.
* *
* @param string $base_url URL de base actuelle. * @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 = [ $wp_args = [
'method' => $method, 'method' => $method,
'timeout' => 20, 'timeout' => (int) self::get_config_value('api_timeout', 20),
'headers' => $headers, 'headers' => $headers,
]; ];
@ -295,8 +353,8 @@ class PEPPOL_peppol_controller {
'vat_category_code' => 'S', 'vat_category_code' => 'S',
'taxable_amount' => 0.0, 'taxable_amount' => 0.0,
'vat_amount' => 0.0, 'vat_amount' => 0.0,
'tax_scheme_id' => 'VAT', 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'),
'tax_scheme_name' => 'Value Added Tax', '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', 'vat_category_code' => 'S',
'taxable_amount' => 0.0, 'taxable_amount' => 0.0,
'vat_amount' => 0.0, 'vat_amount' => 0.0,
'tax_scheme_id' => 'VAT', 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'),
'tax_scheme_name' => 'Value Added Tax', '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', 'vat_category_code' => 'S',
'taxable_amount' => 0.0, 'taxable_amount' => 0.0,
'vat_amount' => 0.0, 'vat_amount' => 0.0,
'tax_scheme_id' => 'VAT', 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'),
'tax_scheme_name' => 'Value Added Tax', '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', 'vat_category_code' => 'E',
'taxable_amount' => 0.0, 'taxable_amount' => 0.0,
'vat_amount' => 0.0, 'vat_amount' => 0.0,
'tax_scheme_id' => 'VAT', 'tax_scheme_id' => self::get_config_value('tax.scheme_id', 'VAT'),
'tax_scheme_name' => 'Value Added Tax', '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') ? $order->get_date_created()->date('Y-m-d')
: \gmdate('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( $due_date = \apply_filters(
'esi_peppol_invoice_due_date', 'esi_peppol_invoice_due_date',
(new \DateTimeImmutable($invoice_date)) (new \DateTimeImmutable($invoice_date))
->modify('+30 days') ->modify('+' . $default_due_days . ' days')
->format('Y-m-d'), ->format('Y-m-d'),
$order $order
); );
$external_reference_prefix = self::get_config_value('invoice.external_reference_prefix', 'WC-');
$external_reference = \apply_filters( $external_reference = \apply_filters(
'esi_peppol_external_reference', 'esi_peppol_external_reference',
'WC-' . $order_number, $external_reference_prefix . $order_number,
$order $order
); );
@ -482,9 +542,10 @@ class PEPPOL_peppol_controller {
$order $order
); );
$default_payment_terms = self::get_config_value('invoice.default_payment_terms', __('Paiement à 30 jours nets', 'esi_peppol'));
$payment_terms = \apply_filters( $payment_terms = \apply_filters(
'esi_peppol_payment_terms', 'esi_peppol_payment_terms',
__('Paiement à 30 jours nets', 'esi_peppol'), $default_payment_terms,
$order $order
); );
@ -628,7 +689,7 @@ class PEPPOL_peppol_controller {
$is_zero_vat_amount = ($vat_amount == 0.0); $is_zero_vat_amount = ($vat_amount == 0.0);
$vat_category_code = $is_zero_vat_amount ? 'E' : 'S'; $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')) { if ($product && $product->get_meta('unit_of_measure')) {
$unit_of_measure = (string) $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 = ''; $seller_item_id = '';
if ($product) { 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(); $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 // Description courte sans balises HTML pour compatibilité PEPPOL
@ -740,8 +802,9 @@ class PEPPOL_peppol_controller {
$is_zero_vat_amount = ($vat_amount == 0.0); $is_zero_vat_amount = ($vat_amount == 0.0);
$vat_category_code = $is_zero_vat_amount ? 'E' : 'S'; $vat_category_code = $is_zero_vat_amount ? 'E' : 'S';
// Identifiant vendeur pour les frais de livraison : préfixe SHIPCQT_ + n° de ligne // Identifiant vendeur pour les frais de livraison : préfixe configurable + n° de ligne
$seller_item_id = 'SHIPCQT_' . $line_number; $shipping_prefix = self::get_config_value('item_ids.shipping_prefix', 'SHIPCQT_');
$seller_item_id = $shipping_prefix . $line_number;
$line = [ $line = [
'line_number' => $line_number, 'line_number' => $line_number,
@ -749,7 +812,7 @@ class PEPPOL_peppol_controller {
'item_description' => '', 'item_description' => '',
'seller_item_id' => $seller_item_id, 'seller_item_id' => $seller_item_id,
'quantity' => $quantity, '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), 'unit_price' => round($unit_price, 2),
'vat_rate' => $vat_rate, 'vat_rate' => $vat_rate,
'vat_category_code' => $vat_category_code, 'vat_category_code' => $vat_category_code,
@ -826,8 +889,9 @@ class PEPPOL_peppol_controller {
$is_zero_vat_amount = ($vat_amount == 0.0); $is_zero_vat_amount = ($vat_amount == 0.0);
$vat_category_code = $is_zero_vat_amount ? 'E' : 'S'; $vat_category_code = $is_zero_vat_amount ? 'E' : 'S';
// Identifiant vendeur pour les frais supplémentaires : préfixe FEE_ + n° de ligne // Identifiant vendeur pour les frais supplémentaires : préfixe configurable + n° de ligne
$seller_item_id = 'FEE_' . $line_number; $fee_prefix = self::get_config_value('item_ids.fee_prefix', 'FEE_');
$seller_item_id = $fee_prefix . $line_number;
$line = [ $line = [
'line_number' => $line_number, 'line_number' => $line_number,
@ -835,7 +899,7 @@ class PEPPOL_peppol_controller {
'item_description' => '', 'item_description' => '',
'seller_item_id' => $seller_item_id, 'seller_item_id' => $seller_item_id,
'quantity' => $quantity, '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), 'unit_price' => round($unit_price, 2),
'vat_rate' => $vat_rate, 'vat_rate' => $vat_rate,
'vat_category_code' => $vat_category_code, 'vat_category_code' => $vat_category_code,
@ -915,8 +979,8 @@ class PEPPOL_peppol_controller {
'total_amount_excluding_vat' => round($total_excl_vat, 2), 'total_amount_excluding_vat' => round($total_excl_vat, 2),
'total_vat_amount' => round($total_vat, 2), 'total_vat_amount' => round($total_vat, 2),
'total_amount_including_vat' => round($total_incl_vat, 2), 'total_amount_including_vat' => round($total_incl_vat, 2),
'total_paid_amount' => 0.0, 'total_paid_amount' => round($order->get_total(), 2),
'total_payable_amount' => round($order->get_total(), 2), 'total_payable_amount' => 0,
'amount_due' => round($order->get_total(), 2), 'amount_due' => round($order->get_total(), 2),
]; ];

View File

@ -142,7 +142,7 @@ if ($logo_email_id) {
printf( printf(
wp_kses_post( wp_kses_post(
/* translators: %s: URL de la documentation */ /* 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. <a href="%s" target="_blank" rel="noopener noreferrer">En savoir plus</a>.', '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. <a href="%s" target="_blank" rel="noopener noreferrer">En savoir plus</a>.', 'esi_peppol')
), ),
esc_url('https://demo.esi-peppol.be/api-demo.html#webhooks') esc_url('https://demo.esi-peppol.be/api-demo.html#webhooks')
); );