From 79ba4ad2e5a84a0ebe21466b456b3c4d76657ccc Mon Sep 17 00:00:00 2001 From: jps Date: Tue, 16 Dec 2025 09:51:22 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20modal=20d=C3=A9tail=20transaction=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ESI_peppol.php | 6 + app/controllers/Plugin.php | 160 +++++++++++++++++ app/models/Main_model.php | 36 ++++ assets/css/admin.css | 145 +++++++++++++++ assets/js/admin.js | 218 +++++++++++++++++++++++ templates/admin/logs.php | 14 ++ templates/modules/logs_details_modal.php | 28 +++ 7 files changed, 607 insertions(+) create mode 100644 templates/modules/logs_details_modal.php diff --git a/ESI_peppol.php b/ESI_peppol.php index 85d9b9a..e03edaf 100644 --- a/ESI_peppol.php +++ b/ESI_peppol.php @@ -143,6 +143,12 @@ add_action( [PEPPOL_Plugin::class, 'ajax_check_invoice_status'] ); +// AJAX admin pour récupérer les détails d'un log Peppol +add_action( + 'wp_ajax_esi_peppol_get_log_details', + [PEPPOL_Plugin::class, 'ajax_get_log_details'] +); + // Champ TVA de la boutique dans les réglages WooCommerce > Général. add_filter( 'woocommerce_general_settings', diff --git a/app/controllers/Plugin.php b/app/controllers/Plugin.php index aabe403..ad7313f 100644 --- a/app/controllers/Plugin.php +++ b/app/controllers/Plugin.php @@ -247,6 +247,7 @@ class PEPPOL_Plugin { 'nonce' => wp_create_nonce('esi_peppol_test_connection'), 'logs_nonce_resend' => wp_create_nonce('esi_peppol_resend_invoice'), 'logs_nonce_status' => wp_create_nonce('esi_peppol_check_invoice_status'), + 'logs_nonce_details' => wp_create_nonce('esi_peppol_get_log_details'), 'i18n_missing' => __('Veuillez renseigner l\'API Key et le Password avant de tester la connexion.', 'esi_peppol'), 'i18n_success' => __('Connexion réussie à l\'API ESIPeppol.', 'esi_peppol'), 'i18n_error' => __('La connexion a échoué. Veuillez vérifier vos identifiants.', 'esi_peppol'), @@ -257,6 +258,13 @@ class PEPPOL_Plugin { 'i18n_logs_resend_ko' => __('L\'envoi du document a échoué.', 'esi_peppol'), 'i18n_logs_status_lbl' => __('Statut actuel du document', 'esi_peppol'), 'i18n_logs_detail_lbl' => __('Détail retour API', 'esi_peppol'), + 'i18n_logs_general_info' => __('Informations générales', 'esi_peppol'), + 'i18n_logs_totals' => __('Totaux', 'esi_peppol'), + 'i18n_logs_vat_details' => __('Détails TVA', 'esi_peppol'), + 'i18n_logs_customer_data' => __('Données client', 'esi_peppol'), + 'i18n_logs_data_sent' => __('Données envoyées', 'esi_peppol'), + 'i18n_logs_response_data' => __('Données de réponse', 'esi_peppol'), + 'i18n_logs_error' => __('Erreur lors du chargement des détails.', 'esi_peppol'), ] ); } @@ -500,6 +508,158 @@ class PEPPOL_Plugin { wp_send_json_error($payload_response, 200); } + /** + * Handler AJAX pour récupérer les détails complets d'un log Peppol + * à partir de l'ID du log. + * + * @return void + */ + public static function ajax_get_log_details(): void { + if (!check_ajax_referer('esi_peppol_get_log_details', 'nonce', false)) { + wp_send_json_error( + [ + 'message' => __('Sécurité : nonce invalide.', 'esi_peppol'), + ], + 400 + ); + } + + if (!current_user_can('manage_woocommerce') && !current_user_can('manage_options')) { + wp_send_json_error( + [ + 'message' => __('Vous n\'avez pas les permissions nécessaires pour effectuer cette action.', 'esi_peppol'), + ], + 403 + ); + } + + $log_id = isset($_POST['log_id']) ? (int) $_POST['log_id'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing + + if ($log_id <= 0) { + wp_send_json_error( + [ + 'message' => __('Identifiant de log invalide.', 'esi_peppol'), + ], + 400 + ); + } + + $row = \ESI_PEPPOL\models\PEPPOL_Main_model::get_by_id($log_id); + + if (!$row) { + wp_send_json_error( + [ + 'message' => __('Aucun enregistrement Peppol trouvé pour cet ID.', 'esi_peppol'), + ], + 404 + ); + } + + // Préparer les données pour l'affichage + $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(), + ]; + } + } + } + + $payload_response = [ + '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' => $row->message ?? '', + '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, + ]; + + wp_send_json_success($payload_response); + } + public static function enqueue_front_assets() { } diff --git a/app/models/Main_model.php b/app/models/Main_model.php index 071f7a4..7b3814a 100644 --- a/app/models/Main_model.php +++ b/app/models/Main_model.php @@ -247,4 +247,40 @@ class PEPPOL_Main_model { return $row; } + + /** + * Récupère un enregistrement PEPPOL par ID (id). + * + * La propriété response_data est désérialisée automatiquement. + * La propriété data_sent est désérialisée automatiquement. + * + * @param int $id ID de l'enregistrement. + * @return object|null + */ + public static function get_by_id(int $id): ?object { + global $wpdb; + + $table_name = self::get_table_name(); + + $row = $wpdb->get_row( + $wpdb->prepare( + "SELECT * FROM {$table_name} WHERE id = %d LIMIT 1", + $id + ) + ); + + if (!$row) { + return null; + } + + // Désérialiser la réponse API et le payload si nécessaire + if (isset($row->response_data)) { + $row->response_data = \maybe_unserialize($row->response_data); + } + if (isset($row->data_sent)) { + $row->data_sent = \maybe_unserialize($row->data_sent); + } + + return $row; + } } \ No newline at end of file diff --git a/assets/css/admin.css b/assets/css/admin.css index 9a4b666..9440396 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -116,3 +116,148 @@ background-color: #6b7280; color: #ffffff; } + +/* Styles pour la modal de détails des logs */ +.esi-peppol-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 100000; + display: flex; + align-items: center; + justify-content: center; +} + +.esi-peppol-modal-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.7); + cursor: pointer; +} + +.esi-peppol-modal-content { + position: relative; + background: #ffffff; + border-radius: 8px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + max-width: 90%; + max-height: 90vh; + width: 800px; + display: flex; + flex-direction: column; + z-index: 1; +} + +.esi-peppol-modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 24px; + border-bottom: 1px solid #ddd; +} + +.esi-peppol-modal-header h2 { + margin: 0; + font-size: 20px; + font-weight: 600; +} + +.esi-peppol-modal-close { + background: none; + border: none; + cursor: pointer; + padding: 4px; + color: #666; + font-size: 20px; + line-height: 1; + transition: color 0.2s; +} + +.esi-peppol-modal-close:hover { + color: #000; +} + +.esi-peppol-modal-close .dashicons { + width: 20px; + height: 20px; + font-size: 20px; +} + +.esi-peppol-modal-body { + padding: 24px; + overflow-y: auto; + flex: 1; +} + +.esi-peppol-loading { + text-align: center; + padding: 40px 20px; +} + +.esi-peppol-loading .spinner { + float: none; + margin: 0 auto 10px; +} + +.esi-peppol-log-details-section { + margin-bottom: 30px; +} + +.esi-peppol-log-details-section:last-child { + margin-bottom: 0; +} + +.esi-peppol-log-details-section h3 { + margin-top: 0; + margin-bottom: 15px; + font-size: 16px; + font-weight: 600; + color: #1d2327; + border-bottom: 2px solid #2271b1; + padding-bottom: 8px; +} + +.esi-peppol-log-details-section table { + margin: 0; +} + +.esi-peppol-log-details-section table th { + background-color: #f6f7f7; + font-weight: 600; + padding: 12px; + text-align: left; + vertical-align: top; +} + +.esi-peppol-log-details-section table td { + padding: 12px; + vertical-align: top; +} + +.esi-peppol-log-json { + background-color: #f6f7f7; + border: 1px solid #ddd; + border-radius: 4px; + padding: 15px; + overflow-x: auto; + font-family: 'Courier New', Courier, monospace; + font-size: 13px; + line-height: 1.6; + max-height: 400px; + overflow-y: auto; + white-space: pre-wrap; + word-wrap: break-word; +} + +.esi-peppol-error { + color: #d63638; + padding: 15px; + background-color: #fcf0f1; + border-left: 4px solid #d63638; + margin: 0; +} diff --git a/assets/js/admin.js b/assets/js/admin.js index f9e0f2f..e0c69a5 100644 --- a/assets/js/admin.js +++ b/assets/js/admin.js @@ -271,6 +271,224 @@ $removeLogoBtn.hide(); }); } + + // Gestion de la modal de détails des logs + var $modal = $('#esi-peppol-log-details-modal'); + var $modalOverlay = $modal.find('.esi-peppol-modal-overlay'); + var $modalClose = $modal.find('.esi-peppol-modal-close'); + var $modalContent = $modal.find('.esi-peppol-modal-content'); + var $modalLoading = $('#esi-peppol-log-details-loading'); + var $modalDetailsContent = $('#esi-peppol-log-details-content'); + + // Fonction pour ouvrir la modal + function openLogDetailsModal() { + $modal.fadeIn(200); + $('body').css('overflow', 'hidden'); + } + + // Fonction pour fermer la modal + function closeLogDetailsModal() { + $modal.fadeOut(200); + $('body').css('overflow', ''); + $modalDetailsContent.hide().empty(); + $modalLoading.show(); + } + + // Fermer la modal en cliquant sur l'overlay ou le bouton de fermeture + $modalOverlay.on('click', closeLogDetailsModal); + $modalClose.on('click', closeLogDetailsModal); + + // Fermer la modal avec la touche Escape + $(document).on('keydown', function (e) { + if (e.key === 'Escape' && $modal.is(':visible')) { + closeLogDetailsModal(); + } + }); + + // Empêcher la fermeture en cliquant sur le contenu de la modal + $modalContent.on('click', function (e) { + e.stopPropagation(); + }); + + // Gestion du clic sur le bouton "Détail" + if ($logsTable.length && typeof window.esiPeppolAdmin !== 'undefined') { + $logsTable.on('click', '.esi-peppol-log-detail', function (e) { + e.preventDefault(); + + var $btn = $(this); + var logId = $btn.data('log-id'); + + if (!logId) { + return; + } + + // Ouvrir la modal + openLogDetailsModal(); + $modalLoading.show(); + $modalDetailsContent.hide().empty(); + + // Charger les détails via AJAX + $.post(window.esiPeppolAdmin.ajax_url, { + action: 'esi_peppol_get_log_details', + nonce: window.esiPeppolAdmin.logs_nonce_details, + log_id: logId + }) + .done(function (response) { + $modalLoading.hide(); + + if (response && response.success && response.data) { + var data = response.data; + var html = ''; + + // Informations générales + html += '
'; + html += '

' + (window.esiPeppolAdmin.i18n_logs_general_info || 'Informations générales') + '

'; + html += ''; + html += ''; + + if (data.order_info) { + html += ''; + html += ''; + html += ''; + } else { + html += ''; + } + + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += '
ID Log' + (data.id || '-') + '
Commande'; + html += ''; + html += '#' + data.order_info.number + ''; + if (data.order_info.billing_name) { + html += ' - ' + data.order_info.billing_name; + } + html += '
Statut commande' + data.order_info.status + '
Total' + data.order_info.total + ' €
ID Commande' + (data.id_order || '-') + '
Document ID' + (data.document_id || '-') + '
Peppol Document ID' + (data.peppol_document_id || '-') + '
Statut' + (data.status || '-') + '
Succès' + (data.success ? 'Oui' : 'Non') + '
Code HTTP' + (data.http_code || '-') + '
Message' + (data.message || '-') + '
Date ajout' + (data.date_add || '-') + '
Dernière mise à jour' + (data.date_update || '-') + '
'; + html += '
'; + + // Totaux (HTVA, TVAC, TVA) + if (data.invoice_totals) { + html += '
'; + html += '

' + (window.esiPeppolAdmin.i18n_logs_totals || 'Totaux') + '

'; + html += ''; + var totalHTVA = parseFloat(data.invoice_totals.total_amount_excluding_vat || 0); + var totalTVA = parseFloat(data.invoice_totals.total_vat_amount || 0); + var totalTVAC = parseFloat(data.invoice_totals.total_amount_including_vat || 0); + html += ''; + html += ''; + html += ''; + if (data.invoice_totals.total_payable_amount) { + var payableAmount = parseFloat(data.invoice_totals.total_payable_amount || 0); + html += ''; + } + html += '
Total HTVA' + totalHTVA.toFixed(2) + ' €
Total TVA' + totalTVA.toFixed(2) + ' €
Total TVAC' + totalTVAC.toFixed(2) + ' €
Montant à payer' + payableAmount.toFixed(2) + ' €
'; + html += '
'; + } + + // Détails TVA par taux + if (data.vat_totals && Array.isArray(data.vat_totals) && data.vat_totals.length > 0) { + html += '
'; + html += '

' + (window.esiPeppolAdmin.i18n_logs_vat_details || 'Détails TVA') + '

'; + html += ''; + html += ''; + html += ''; + data.vat_totals.forEach(function(vat) { + var vatRate = parseFloat(vat.vat_rate || 0); + var taxableAmount = parseFloat(vat.taxable_amount || 0); + var vatAmount = parseFloat(vat.vat_amount || 0); + var totalInclVat = taxableAmount + vatAmount; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + }); + html += ''; + html += '
Taux TVAMontant HTVAMontant TVAMontant TVAC
' + vatRate.toFixed(2) + ' %' + taxableAmount.toFixed(2) + ' €' + vatAmount.toFixed(2) + ' €' + totalInclVat.toFixed(2) + ' €
'; + html += '
'; + } + + // Données client + if (data.customer_data || (data.order_info && (data.order_info.billing_name || data.order_info.billing_company))) { + html += '
'; + html += '

' + (window.esiPeppolAdmin.i18n_logs_customer_data || 'Données client') + '

'; + html += ''; + + // Utiliser customer_data depuis le payload si disponible, sinon order_info + var customer = data.customer_data || {}; + var orderInfo = data.order_info || {}; + + var customerName = customer.name || orderInfo.billing_company || orderInfo.billing_name || '-'; + var customerLegalName = customer.legal_name || customer.name || orderInfo.billing_company || orderInfo.billing_name || '-'; + var customerVat = customer.vat_number || orderInfo.billing_vat_number || '-'; + var customerEmail = (customer.contact && customer.contact.contact_email) || orderInfo.billing_email || '-'; + var customerPhone = (customer.contact && customer.contact.contact_phone) || orderInfo.billing_phone || '-'; + + var address = customer.address || {}; + var addressLine1 = address.address_line_1 || orderInfo.billing_address_1 || '-'; + var addressLine2 = address.address_line_2 || orderInfo.billing_address_2 || ''; + var city = address.city || orderInfo.billing_city || '-'; + var postalCode = address.postal_code || orderInfo.billing_postcode || '-'; + var countryCode = address.country_code || orderInfo.billing_country || '-'; + + html += ''; + if (customerLegalName && customerLegalName !== customerName) { + html += ''; + } + html += ''; + html += ''; + if (customerPhone && customerPhone !== '-') { + html += ''; + } + html += ''; + html += '
Nom / Raison sociale' + customerName + '
Nom légal' + customerLegalName + '
Numéro TVA' + customerVat + '
Email' + customerEmail + '
Téléphone' + customerPhone + '
Adresse'; + html += addressLine1; + if (addressLine2) { + html += '
' + addressLine2; + } + html += '
' + postalCode + ' ' + city; + html += '
' + countryCode; + html += '
'; + html += '
'; + } + + // Données envoyées + if (data.data_sent) { + html += '
'; + html += '

' + (window.esiPeppolAdmin.i18n_logs_data_sent || 'Données envoyées') + '

'; + html += '
' + $('
').text(data.data_sent).html() + '
'; + html += '
'; + } + + // Données de réponse + if (data.response_data) { + html += '
'; + html += '

' + (window.esiPeppolAdmin.i18n_logs_response_data || 'Données de réponse') + '

'; + html += '
' + $('
').text(data.response_data).html() + '
'; + html += '
'; + } + + $modalDetailsContent.html(html).show(); + } else { + var errorMsg = (response && response.data && response.data.message) + ? response.data.message + : (window.esiPeppolAdmin.i18n_logs_error || 'Erreur lors du chargement des détails.'); + $modalDetailsContent.html('

' + errorMsg + '

').show(); + } + }) + .fail(function () { + $modalLoading.hide(); + var errorMsg = window.esiPeppolAdmin.i18n_network || 'Erreur de communication avec le serveur WordPress.'; + $modalDetailsContent.html('

' + errorMsg + '

').show(); + }); + }); + } }); })(jQuery); diff --git a/templates/admin/logs.php b/templates/admin/logs.php index 117c109..ef05be8 100644 --- a/templates/admin/logs.php +++ b/templates/admin/logs.php @@ -73,6 +73,13 @@ if (!defined('ABSPATH')) { date_add); ?> date_update); ?> + + +
+
+ +

+
+ +
+ +