From 3b2dde9664a93461815881e48fb7f5a9f99f5baf Mon Sep 17 00:00:00 2001
From: jps
Date: Fri, 19 Dec 2025 10:54:03 +0100
Subject: [PATCH] =?UTF-8?q?Ajout=20colonne=20+=20d=C3=A9tail=20commande?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/Plugin.php | 181 +++++++++++++-
app/controllers/Woocommerce_controller.php | 67 ++++++
assets/css/admin.css | 17 ++
assets/js/admin.js | 6 +-
templates/admin/logs-detail.php | 263 +++++++++++++++++++++
templates/email/api-error.php | 25 +-
6 files changed, 544 insertions(+), 15 deletions(-)
create mode 100644 templates/admin/logs-detail.php
diff --git a/app/controllers/Plugin.php b/app/controllers/Plugin.php
index f90d14a..69d32e4 100644
--- a/app/controllers/Plugin.php
+++ b/app/controllers/Plugin.php
@@ -40,6 +40,14 @@ class PEPPOL_Plugin {
// Notice globale pour le numéro de TVA
\add_action('admin_notices', [self::class, 'maybe_show_vat_notice']);
+
+ // Ajouter une colonne "Statut Peppol" dans le listing des commandes WooCommerce
+ if (class_exists(\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::class)) {
+ \add_filter('manage_edit-shop_order_columns', [\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::class, 'add_peppol_status_column'], 20);
+ \add_filter('manage_woocommerce_page_wc-orders_columns', [\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::class, 'add_peppol_status_column'], 20);
+ \add_action('manage_shop_order_posts_custom_column', [\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::class, 'show_peppol_status_column'], 10, 2);
+ \add_action('manage_woocommerce_page_wc-orders_custom_column', [\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::class, 'show_peppol_status_column'], 10, 2);
+ }
}
/**
@@ -183,24 +191,181 @@ class PEPPOL_Plugin {
wp_die(esc_html__('Vous n\'avez pas les permissions nécessaires pour accéder à cette page.', 'esi_peppol'));
}
- // Récupération des dernières lignes de la table custom
- $rows = PEPPOL_Main_model::get_recent(50);
+ // Vérifier si on affiche la page de détail
+ $detail_id = isset($_GET['detail']) ? (int) $_GET['detail'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $template = ESI_PEPPOL_DIR . 'templates/admin/logs.php';
+ if ($detail_id > 0) {
+ // Afficher la page de détail
+ $row = PEPPOL_Main_model::get_by_id($detail_id);
- if (file_exists($template)) {
- /** @noinspection PhpIncludeInspection */
- include $template;
+ if (!$row) {
+ wp_die(esc_html__('Aucun enregistrement Peppol trouvé pour cet ID.', 'esi_peppol'));
+ }
+
+ // Préparer les données pour l'affichage (même logique que ajax_get_log_details)
+ $data_sent = $row->data_sent ?? null;
+ $response_data = $row->response_data ?? null;
+
+ // Formater les données JSON si possible
+ $data_sent_formatted = '';
+ if ($data_sent) {
+ if (is_array($data_sent) || is_object($data_sent)) {
+ $data_sent_formatted = wp_json_encode($data_sent, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ } else {
+ $data_sent_formatted = (string) $data_sent;
+ }
+ }
+
+ $response_data_formatted = '';
+ if ($response_data) {
+ if (is_array($response_data) || is_object($response_data)) {
+ $response_data_formatted = wp_json_encode($response_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ } else {
+ $response_data_formatted = (string) $response_data;
+ }
+ }
+
+ // Extraire les informations financières depuis data_sent
+ $invoice_totals = null;
+ $vat_totals = null;
+ $customer_data = null;
+
+ if ($data_sent && (is_array($data_sent) || is_object($data_sent))) {
+ // Convertir en tableau si c'est un objet
+ $data_array = is_object($data_sent) ? (array) $data_sent : $data_sent;
+
+ // Extraire invoice_totals
+ if (isset($data_array['invoice_totals']) && is_array($data_array['invoice_totals'])) {
+ $invoice_totals = $data_array['invoice_totals'];
+ }
+
+ // Extraire vat_totals
+ if (isset($data_array['vat_totals']) && is_array($data_array['vat_totals'])) {
+ $vat_totals = $data_array['vat_totals'];
+ }
+
+ // Extraire les données client (buyer)
+ if (isset($data_array['parties']['buyer']) && is_array($data_array['parties']['buyer'])) {
+ $customer_data = $data_array['parties']['buyer'];
+ }
+ }
+
+ // Récupérer les informations de la commande si disponible
+ $order_info = null;
+ $order_totals = null;
+ if (!empty($row->id_order)) {
+ $order = wc_get_order($row->id_order);
+ if ($order) {
+ $order_info = [
+ 'id' => $order->get_id(),
+ 'number' => $order->get_order_number(),
+ 'status' => $order->get_status(),
+ 'total' => $order->get_total(),
+ 'billing_name' => trim($order->get_billing_first_name() . ' ' . $order->get_billing_last_name()),
+ 'billing_email' => $order->get_billing_email(),
+ 'billing_phone' => $order->get_billing_phone(),
+ 'billing_company' => $order->get_billing_company(),
+ 'billing_address_1' => $order->get_billing_address_1(),
+ 'billing_address_2' => $order->get_billing_address_2(),
+ 'billing_city' => $order->get_billing_city(),
+ 'billing_postcode' => $order->get_billing_postcode(),
+ 'billing_country' => $order->get_billing_country(),
+ 'billing_vat_number' => $order->get_meta('_billing_vat_number') ?: '',
+ 'edit_link' => get_edit_post_link($row->id_order),
+ ];
+
+ // Calculer les totaux depuis la commande si invoice_totals n'est pas disponible
+ if (!$invoice_totals) {
+ $order_totals = [
+ 'total_amount_excluding_vat' => $order->get_total() - $order->get_total_tax(),
+ 'total_vat_amount' => $order->get_total_tax(),
+ 'total_amount_including_vat' => $order->get_total(),
+ ];
+ }
+ }
+ }
+
+ // Extraire le message d'erreur depuis response_data
+ $error_message_to_display = $row->message ?? '';
+
+ if (!empty($response_data) && (is_array($response_data) || is_object($response_data))) {
+ // Convertir en tableau si c'est un objet
+ $error_data = is_object($response_data) ? (array) $response_data : $response_data;
+
+ if (is_array($error_data)) {
+ // Structure avec error.message
+ if (isset($error_data['error']['message'])) {
+ $error_message_to_display = (string) $error_data['error']['message'];
+ }
+ // Structure avec details.validation_error
+ elseif (isset($error_data['details']['validation_error'])) {
+ $error_message_to_display = (string) $error_data['details']['validation_error'];
+ }
+ // Structure avec validation_error directement
+ elseif (isset($error_data['validation_error'])) {
+ $error_message_to_display = (string) $error_data['validation_error'];
+ }
+ // Structure avec message directement
+ elseif (isset($error_data['message'])) {
+ $error_message_to_display = (string) $error_data['message'];
+ }
+ }
+ }
+
+ // Préparer les données pour le template
+ $log_data = [
+ 'id' => $row->id,
+ 'id_order' => $row->id_order ?? 0,
+ 'order_info' => $order_info,
+ 'document_id' => $row->document_id ?? '',
+ 'peppol_document_id' => $row->peppol_document_id ?? '',
+ 'status' => $row->status ?? '',
+ 'success' => !empty($row->success),
+ 'message' => $error_message_to_display,
+ 'http_code' => $row->http_code ?? null,
+ 'date_add' => $row->date_add ?? '',
+ 'date_update' => $row->date_update ?? '',
+ 'invoice_totals' => $invoice_totals ?? $order_totals,
+ 'vat_totals' => $vat_totals,
+ 'customer_data' => $customer_data,
+ 'data_sent' => $data_sent_formatted,
+ 'response_data' => $response_data_formatted,
+ ];
+
+ $template = ESI_PEPPOL_DIR . 'templates/admin/logs-detail.php';
+
+ if (file_exists($template)) {
+ /** @noinspection PhpIncludeInspection */
+ include $template;
+ } else {
+ wp_die(esc_html__('Template de détail introuvable.', 'esi_peppol'));
+ }
+ } else {
+ // Afficher la liste des logs
+ // Récupération des dernières lignes de la table custom
+ $rows = PEPPOL_Main_model::get_recent(50);
+
+ $template = ESI_PEPPOL_DIR . 'templates/admin/logs.php';
+
+ if (file_exists($template)) {
+ /** @noinspection PhpIncludeInspection */
+ include $template;
+ }
}
}
public static function enqueue_admin_assets() {
$screen = function_exists('get_current_screen') ? get_current_screen() : null;
- // Ne charger les assets que sur les pages du plugin
+ // Ne charger les assets que sur les pages du plugin ou la page des commandes WooCommerce
$is_peppol_page = isset($_GET['page']) && strpos((string) $_GET['page'], 'esi-peppol') === 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $is_orders_page = $screen && (
+ strpos((string) $screen->id, 'shop_order') !== false ||
+ strpos((string) $screen->id, 'woocommerce_page_wc-orders') !== false ||
+ $screen->id === 'edit-shop_order'
+ );
- if (!$is_peppol_page && $screen && strpos((string) $screen->base, 'esi-peppol') === false) {
+ if (!$is_peppol_page && !$is_orders_page && $screen && strpos((string) $screen->base, 'esi-peppol') === false) {
return;
}
diff --git a/app/controllers/Woocommerce_controller.php b/app/controllers/Woocommerce_controller.php
index b1a2b0f..e13c948 100644
--- a/app/controllers/Woocommerce_controller.php
+++ b/app/controllers/Woocommerce_controller.php
@@ -191,4 +191,71 @@ class PEPPOL_Woocommerce_controller {
'
';
}
+ /**
+ * Ajoute une colonne "Statut Peppol" dans le listing des commandes WooCommerce.
+ *
+ * @param array $columns Colonnes existantes.
+ * @return array Colonnes modifiées.
+ */
+ public static function add_peppol_status_column(array $columns): array {
+ $new_columns = [];
+
+ foreach ($columns as $key => $column) {
+ $new_columns[$key] = $column;
+
+ // Ajouter la colonne "Statut Peppol" après la colonne "Commande" ou "order_title"
+ if ('order_title' === $key || 'order_number' === $key || 'order_status' === $key) {
+ $new_columns['peppol_status'] = __('Statut Peppol', 'esi_peppol');
+ }
+ }
+
+ // Si aucune colonne appropriée n'a été trouvée, ajouter à la fin
+ if (!isset($new_columns['peppol_status'])) {
+ $new_columns['peppol_status'] = __('Statut Peppol', 'esi_peppol');
+ }
+
+ return $new_columns;
+ }
+
+ /**
+ * Affiche le contenu de la colonne "Statut Peppol" dans le listing des commandes.
+ *
+ * @param string $column Nom de la colonne.
+ * @param int|object $order ID de la commande ou objet commande.
+ * @return void
+ */
+ public static function show_peppol_status_column(string $column, $order): void {
+ if ('peppol_status' !== $column) {
+ return;
+ }
+
+ // Récupérer l'ID de la commande
+ $order_id = is_numeric($order) ? (int) $order : (is_object($order) ? $order->get_id() : 0);
+
+ if (!$order_id) {
+ echo '–';
+ return;
+ }
+
+ // Récupérer le log Peppol associé à cette commande
+ $log = \ESI_PEPPOL\models\PEPPOL_Main_model::get_by_order_id($order_id);
+
+ if (!$log || empty($log->status)) {
+ echo '–';
+ return;
+ }
+
+ // Afficher le macaron cliquable vers la page de détail
+ $detail_url = \admin_url('admin.php?page=esi-peppol-logs&detail=' . $log->id);
+ $status_class = 'statut statut-' . \strtolower(\sanitize_html_class($log->status));
+
+ \printf(
+ '%s',
+ \esc_url($detail_url),
+ \esc_attr($status_class),
+ \esc_attr__('Voir les détails du log Peppol', 'esi_peppol'),
+ \esc_html($log->status)
+ );
+ }
+
}
\ No newline at end of file
diff --git a/assets/css/admin.css b/assets/css/admin.css
index 7ac43d6..756fd39 100644
--- a/assets/css/admin.css
+++ b/assets/css/admin.css
@@ -106,6 +106,23 @@
white-space: nowrap;
}
+/* Styles pour les liens de statut (macarons cliquables) */
+a.statut {
+ text-decoration: none;
+ transition: opacity 0.2s ease, transform 0.1s ease;
+ cursor: pointer;
+}
+
+a.statut:hover {
+ opacity: 0.85;
+ text-decoration: none;
+ transform: scale(1.05);
+}
+
+a.statut:visited {
+ color: inherit;
+}
+
/* Couleurs par défaut pour les statuts communs */
.statut-success,
.statut-succès,
diff --git a/assets/js/admin.js b/assets/js/admin.js
index 89f270d..a762f47 100644
--- a/assets/js/admin.js
+++ b/assets/js/admin.js
@@ -75,7 +75,8 @@
}
// Actions AJAX sur la page de logs : renvoyer / vérifier le statut
- if ($logsTable.length && typeof window.esiPeppolAdmin !== 'undefined') {
+ // Utiliser la délégation d'événements sur le document pour fonctionner aussi sur la page de détail
+ if (typeof window.esiPeppolAdmin !== 'undefined') {
var $logsResult = $('#esi-peppol-logs-result');
var showLogsNotice = function (type, title, message, detail) {
@@ -107,7 +108,8 @@
.append(html);
};
- $logsTable.on('click', '.esi-peppol-log-resend', function (e) {
+ // Gestionnaire pour le bouton "Réenvoyer" (fonctionne dans le tableau et sur la page de détail)
+ $(document).on('click', '.esi-peppol-log-resend', function (e) {
e.preventDefault();
var $btn = $(this);
diff --git a/templates/admin/logs-detail.php b/templates/admin/logs-detail.php
new file mode 100644
index 0000000..dbcc1ed
--- /dev/null
+++ b/templates/admin/logs-detail.php
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ ' . esc_html__('Oui', 'esi_peppol') . ''
+ : '' . esc_html__('Non', 'esi_peppol') . '';
+ ?>
+ |
+
+
+ |
+ |
+
+
+
+ |
+
+
+ #
+
+ |
+
+
+
+ |
+ # |
+
+
+
+
+ |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+
+ |
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+ 0) :
+ ?>
+
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+ |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/templates/email/api-error.php b/templates/email/api-error.php
index a9f315b..c34c802 100644
--- a/templates/email/api-error.php
+++ b/templates/email/api-error.php
@@ -42,6 +42,21 @@ if ($order instanceof WC_Order) {
$customer_email = $order->get_billing_email();
$customer_phone = $order->get_billing_phone();
}
+
+// Récupérer le log Peppol associé à cette commande pour obtenir l'ID du log
+$log_id = null;
+if (class_exists('\ESI_PEPPOL\models\PEPPOL_Main_model')) {
+ $log = \ESI_PEPPOL\models\PEPPOL_Main_model::get_by_order_id($order_id);
+ if ($log && !empty($log->id)) {
+ $log_id = (int) $log->id;
+ }
+}
+
+// Construire l'URL vers la page de détail ou la page de logs
+$logs_url = admin_url('admin.php?page=esi-peppol-logs');
+if ($log_id) {
+ $logs_url = admin_url('admin.php?page=esi-peppol-logs&detail=' . $log_id);
+}
?>
@@ -311,7 +326,7 @@ if ($order instanceof WC_Order) {
-
+
@@ -319,17 +334,17 @@ if ($order instanceof WC_Order) {
|
|