EsiPeppol-Woocommerce/app/controllers/Plugin.php
2025-12-16 14:57:01 +01:00

875 lines
33 KiB
PHP

<?php
namespace ESI_PEPPOL\controllers;
use ESI_PEPPOL\models\PEPPOL_Main_model;
class PEPPOL_Plugin {
public function init() {
$this->load_actions();
}
/**
* Méthode appelée lors de l'activation du plugin.
*
* Elle délègue au modèle principal la création de la table
* `esi_peppol_invoices`.
*
* @return void
*/
public static function activate(): void {
// Création / mise à jour de la table principale des factures
PEPPOL_Main_model::create_table();
}
public function desactivate() {
}
public static function register_routes() {
}
public function load_actions() {
// Enregistrement des hooks WooCommerce
if (class_exists(\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::class)) {
\ESI_PEPPOL\controllers\PEPPOL_Woocommerce_controller::register_hooks();
}
}
/**
* Enregistre le menu et les sous-menus dans l'admin WordPress.
*
* @return void
*/
public static function add_admin_menu(): void {
// Page principale du plugin
add_menu_page(
__('ESI Peppol', 'esi_peppol'),
__('ESI Peppol', 'esi_peppol'),
'manage_options',
'esi-peppol',
[self::class, 'render_dashboard_page'],
'dashicons-migrate',
56
);
// Sous-menus (cibles des boutons de la page d'accueil)
add_submenu_page(
'esi-peppol',
__('Configuration', 'esi_peppol'),
__('Configuration', 'esi_peppol'),
'manage_options',
'esi-peppol-settings',
[self::class, 'render_settings_page']
);
add_submenu_page(
'esi-peppol',
__('Journal', 'esi_peppol'),
__('Journal', 'esi_peppol'),
'manage_options',
'esi-peppol-logs',
[self::class, 'render_logs_page']
);
}
public static function load_filters() {
}
public function load_shortcodes() {
}
public function load_frontend_assets() {
self::enqueue_admin_assets();
self::enqueue_front_assets();
}
public function load_admin_assets() {
}
/**
* Page d'accueil du plugin (dashboard interne ESI Peppol).
*
* Contient un texte explicatif et deux boutons vers les sous-menus.
*
* @return void
*/
public static function render_dashboard_page(): void {
if (!current_user_can('manage_options')) {
wp_die(esc_html__('Vous n\'avez pas les permissions nécessaires pour accéder à cette page.', 'esi_peppol'));
}
$settings_url = admin_url('admin.php?page=esi-peppol-settings');
$logs_url = admin_url('admin.php?page=esi-peppol-logs');
$template = ESI_PEPPOL_DIR . 'templates/admin/dashboard.php';
if (file_exists($template)) {
/** @noinspection PhpIncludeInspection */
include $template;
}
}
/**
* Page de configuration (stub pour l'instant).
*
* @return void
*/
public static function render_settings_page(): void {
if (!current_user_can('manage_options')) {
wp_die(esc_html__('Vous n\'avez pas les permissions nécessaires pour accéder à cette page.', 'esi_peppol'));
}
$notice = null;
$error = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = isset($_POST['esi_peppol_action'])
? sanitize_text_field(wp_unslash($_POST['esi_peppol_action']))
: '';
if (!isset($_POST['esi_peppol_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['esi_peppol_nonce'])), 'esi_peppol_save_settings')) {
$error = __('Sécurité : nonce invalide.', 'esi_peppol');
} else {
$api_key = isset($_POST['esi_peppol_api_key']) ? sanitize_text_field(wp_unslash($_POST['esi_peppol_api_key'])) : '';
$password = isset($_POST['esi_peppol_password']) ? sanitize_text_field(wp_unslash($_POST['esi_peppol_password'])) : '';
$email = isset($_POST['esi_peppol_email']) ? sanitize_email(wp_unslash($_POST['esi_peppol_email'])) : '';
$logo_email_id = isset($_POST['esi_peppol_logo_email_id']) ? absint(wp_unslash($_POST['esi_peppol_logo_email_id'])) : 0;
// Sauvegarde systématique des options
update_option('esi_peppol_api_key', $api_key);
update_option('esi_peppol_password', $password);
update_option('esi_peppol_email', $email);
update_option('esi_peppol_logo_email_id', $logo_email_id);
if ($action === 'save') {
$notice = __('Paramètres enregistrés avec succès.', 'esi_peppol');
} elseif ($action === 'test') {
// Ici on pourrait appeler un endpoint de "ping" de l\'API ESIPeppol.
// Pour l\'instant : simple message de succès basé sur la présence des credentials.
if ($api_key && $password) {
$notice = __('Test de connexion simulé : les identifiants semblent corrects (vérification API réelle à implémenter).', 'esi_peppol');
} else {
$error = __('Veuillez renseigner l\'API Key et le Password avant de tester la connexion.', 'esi_peppol');
}
}
}
}
$template = ESI_PEPPOL_DIR . 'templates/admin/settings.php';
if (file_exists($template)) {
/** @noinspection PhpIncludeInspection */
include $template;
}
}
/**
* Page de journal / logs (stub pour l'instant).
*
* @return void
*/
public static function render_logs_page(): void {
if (!current_user_can('manage_options')) {
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);
$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
$is_peppol_page = isset($_GET['page']) && strpos((string) $_GET['page'], 'esi-peppol') === 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if (!$is_peppol_page && $screen && strpos((string) $screen->base, 'esi-peppol') === false) {
return;
}
$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
// Styles admin généraux
wp_enqueue_style(
'esi-peppol-admin',
ESI_PEPPOL_URL . 'assets/css/admin.css',
[],
ESI_PEPPOL_VERSION
);
// DataTables (utilisé pour le tableau du journal des échanges)
// Utiliser le CDN DataTables pour une meilleure compatibilité avec WordPress
wp_enqueue_style(
'esi-peppol-datatables',
'https://cdn.datatables.net/1.13.8/css/jquery.dataTables.min.css',
['esi-peppol-admin'],
'1.13.8'
);
// S'assurer que jQuery est chargé en premier
wp_enqueue_script('jquery');
// Utiliser le CDN DataTables au lieu du fichier local pour éviter les problèmes de compatibilité
wp_enqueue_script(
'esi-peppol-datatables',
'https://cdn.datatables.net/1.13.8/js/jquery.dataTables.min.js',
['jquery'],
'1.13.8',
true
);
// Enqueue wp.media pour la gestion de la médiathèque (logo email)
wp_enqueue_media();
// Script admin principal, dépendant de DataTables
wp_enqueue_script(
'esi-peppol-admin',
ESI_PEPPOL_URL . 'assets/js/admin.js',
['jquery', 'esi-peppol-datatables'],
ESI_PEPPOL_VERSION,
true
);
wp_localize_script(
'esi-peppol-admin',
'esiPeppolAdmin',
[
'ajax_url' => admin_url('admin-ajax.php'),
'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'),
'i18n_network' => __('Erreur de communication avec le serveur WordPress.', 'esi_peppol'),
'i18n_logs_ok_title' => __('OK', 'esi_peppol'),
'i18n_logs_ko_title' => __('Pas OK', 'esi_peppol'),
'i18n_logs_resend_ok' => __('Document renvoyé avec succès à l\'API ESIPeppol.', 'esi_peppol'),
'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'),
]
);
}
/**
* Handler AJAX pour le test de connexion à l'API ESIPeppol.
*
* @return void
*/
public static function ajax_test_connection(): void {
if (!check_ajax_referer('esi_peppol_test_connection', 'nonce', false)) {
wp_send_json_error(
[
'message' => __('Sécurité : nonce invalide.', 'esi_peppol'),
],
400
);
}
if (!current_user_can('manage_options')) {
wp_send_json_error(
[
'message' => __('Vous n\'avez pas les permissions nécessaires pour effectuer ce test.', 'esi_peppol'),
],
403
);
}
$api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
$password = isset($_POST['password']) ? sanitize_text_field(wp_unslash($_POST['password'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
if ($api_key === '' || $password === '') {
wp_send_json_error(
[
'message' => __('Veuillez renseigner l\'API Key et le Password avant de tester la connexion.', 'esi_peppol'),
],
400
);
}
$result = \ESI_PEPPOL\controllers\PEPPOL_peppol_controller::status_with_credentials($api_key, $password);
if (!empty($result['success'])) {
$company = '';
if (is_array($result['data'] ?? null) && isset($result['data']['company'])) {
$company = (string) $result['data']['company'];
}
$message = $company
? sprintf(__('Connexion réussie. Entreprise: %s', 'esi_peppol'), $company)
: __('Connexion réussie à l\'API ESIPeppol.', 'esi_peppol');
wp_send_json_success(
[
'message' => $message,
'http_code' => $result['http_code'] ?? 200,
]
);
}
$error_message = $result['message'] ?? '';
if ($error_message === '' && is_array($result['data'] ?? null) && isset($result['data']['message'])) {
$error_message = (string) $result['data']['message'];
}
if ($error_message === '') {
$error_message = __('La connexion a échoué. Veuillez vérifier vos identifiants.', 'esi_peppol');
}
wp_send_json_error(
[
'message' => $error_message,
'http_code' => $result['http_code'] ?? 0,
]
);
}
/**
* Handler AJAX pour renvoyer un document/facture vers l'API ESIPeppol
* à partir d'un ID de commande WooCommerce.
*
* @return void
*/
public static function ajax_resend_invoice(): void {
if (!check_ajax_referer('esi_peppol_resend_invoice', '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
);
}
$order_id = isset($_POST['order_id']) ? (int) $_POST['order_id'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing
if ($order_id <= 0) {
wp_send_json_error(
[
'message' => __('Identifiant de commande invalide.', 'esi_peppol'),
],
400
);
}
$order = wc_get_order($order_id);
if (!$order instanceof \WC_Order) {
wp_send_json_error(
[
'message' => __('Commande introuvable.', 'esi_peppol'),
],
404
);
}
// Reconstruire le payload et renvoyer le document via l'API ESIPeppol
$payload = \ESI_PEPPOL\controllers\PEPPOL_peppol_controller::build_payload_from_order($order);
$result = \ESI_PEPPOL\controllers\PEPPOL_peppol_controller::upload_json($payload, $order_id);
// Mettre à jour quelques métadonnées sur la commande pour le suivi
$order->update_meta_data('_esi_peppol_last_manual_action', 'resend');
$order->update_meta_data('_esi_peppol_last_peppol_status', !empty($result['success']) ? 'success' : 'error');
$order->update_meta_data('_esi_peppol_last_http_code', $result['http_code'] ?? 0);
$order->update_meta_data('_esi_peppol_last_message', $result['message'] ?? '');
$order->save();
$detail_message = '';
if (is_array($result['data'] ?? null) && isset($result['data']['message'])) {
$detail_message = (string) $result['data']['message'];
}
if ($detail_message === '' && isset($result['message'])) {
$detail_message = (string) $result['message'];
}
$payload_response = [
'success' => !empty($result['success']),
'message' => !empty($result['success'])
? __('Document renvoyé avec succès à l\'API ESIPeppol.', 'esi_peppol')
: __('L\'envoi du document a échoué.', 'esi_peppol'),
'detail' => $detail_message,
'http_code' => $result['http_code'] ?? 0,
];
if (!empty($result['success'])) {
wp_send_json_success($payload_response);
}
wp_send_json_error($payload_response, $result['http_code'] ?? 400);
}
/**
* Handler AJAX pour consulter le statut courant d'un document Peppol
* à partir de l'ID de commande (lecture depuis la table custom).
*
* @return void
*/
public static function ajax_check_invoice_status(): void {
if (!check_ajax_referer('esi_peppol_check_invoice_status', '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
);
}
$order_id = isset($_POST['order_id']) ? (int) $_POST['order_id'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing
if ($order_id <= 0) {
wp_send_json_error(
[
'message' => __('Identifiant de commande invalide.', 'esi_peppol'),
],
400
);
}
$row = \ESI_PEPPOL\models\PEPPOL_Main_model::get_by_order_id($order_id);
if (!$row) {
wp_send_json_error(
[
'message' => __('Aucun enregistrement Peppol trouvé pour cette commande.', 'esi_peppol'),
],
404
);
}
$detail_message = '';
if (isset($row->response_data)) {
$data = $row->response_data;
if (is_array($data) && isset($data['message'])) {
$detail_message = (string) $data['message'];
} elseif (is_string($data) && $data !== '') {
$detail_message = $data;
}
}
if ($detail_message === '' && isset($row->message)) {
$detail_message = (string) $row->message;
}
$payload_response = [
'success' => !empty($row->success),
'status' => isset($row->status) ? (string) $row->status : '',
'message' => sprintf(
/* translators: %s: statut Peppol actuel */
__('Statut actuel du document : %s', 'esi_peppol'),
isset($row->status) ? (string) $row->status : __('inconnu', 'esi_peppol')
),
'detail' => $detail_message,
'http_code' => isset($row->http_code) ? (int) $row->http_code : 0,
];
if (!empty($row->success)) {
wp_send_json_success($payload_response);
}
// On renvoie tout de même une réponse structurée même en cas d'échec métier
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() {
}
/**
* Ajoute un champ "Numéro de TVA de la boutique" dans les réglages
* WooCommerce > Général, juste après le code postal du magasin.
*
* @param array $settings
* @return array
*/
public static function filter_woocommerce_general_settings(array $settings): array {
$new_settings = [];
foreach ($settings as $setting) {
$new_settings[] = $setting;
if (isset($setting['id']) && $setting['id'] === 'woocommerce_store_postcode') {
$new_settings[] = [
'title' => __('Numéro de TVA de la boutique', 'esi_peppol'),
'desc' => __('Utilisé pour les factures Peppol (champ vendeur).', 'esi_peppol'),
'id' => 'woocommerce_store_vat_number',
'type' => 'text',
'default' => '',
'desc_tip' => true,
];
}
}
return $new_settings;
}
/**
* Retourne un message d'avertissement à propos du numéro de TVA
* de la boutique si celui-ci n'est pas encore renseigné dans
* les réglages WooCommerce.
*
* - Message d'invitation initial : aucune configuration ESI Peppol
* n'a encore été saisie.
* - Message de rappel : les identifiants ESI Peppol sont déjà
* enregistrés mais la TVA reste vide.
*
* @return string|null
*/
public static function get_vat_notice_message(): ?string {
$vat_number = (string) get_option('woocommerce_store_vat_number', '');
if ($vat_number !== '') {
return null;
}
$api_key = (string) get_option('esi_peppol_api_key', '');
$password = (string) get_option('esi_peppol_password', '');
if ($api_key === '' && $password === '') {
// Invitation initiale
return __(
'Pour finaliser la mise en place de Peppol, pensez à renseigner le numéro de TVA de la boutique dans WooCommerce > Réglages > Général.',
'esi_peppol'
);
}
// Rappel après configuration du connecteur
return __(
'Votre connecteur ESI Peppol est configuré, mais le numéro de TVA de la boutique n\'est pas encore renseigné dans WooCommerce > Réglages > Général. Sans ce numéro, les factures Peppol risquent d\'être incomplètes.',
'esi_peppol'
);
}
public static function write_log($message, $level = 'INFO') {
$message = self::format_message_for_log($message);
$log_entry = sprintf("[%s] [%s] %s\n", date('Y-m-d H:i:s'), $level, $message);
error_log($log_entry);
}
/**
* Écrit un message dans un fichier debug.txt sous le dossier uploads
* Chemin: wp-content/uploads/crvi-debug.txt
*/
public static function write_debug_file($message, $level = 'INFO') {
$message = self::format_message_for_log($message);
$log_entry = sprintf("[%s] [%s] %s\n", date('Y-m-d H:i:s'), $level, $message);
$upload_dir = wp_upload_dir();
$file_path = trailingslashit($upload_dir['basedir']) . 'crvi-debug.txt';
// Tente d'écrire le log. En cas d'échec, fallback sur error_log
@file_put_contents($file_path, $log_entry, FILE_APPEND);
// Écrire également dans le log PHP (wp-content/debug.log si WP_DEBUG_LOG actif, sinon error_log du serveur)
error_log($log_entry);
}
private static function format_message_for_log($message) {
if (is_array($message)) {
return print_r($message, true);
} elseif (is_object($message)) {
return print_r($message, true);
} elseif (is_bool($message)) {
return $message ? 'TRUE' : 'FALSE';
} elseif (is_numeric($message)) {
return (string) $message;
} elseif (is_null($message)) {
return 'NULL';
} else {
return var_export($message, true);
}
}
/**
* Envoie un email de notification en cas d'erreur API Peppol.
*
* @param int $order_id ID de la commande WooCommerce.
* @param array $api_result Résultat de l'appel API (success, http_code, message, data).
* @param array $payload Payload envoyé à l'API (optionnel, pour debug).
*
* @return bool True si l'email a été envoyé avec succès, false sinon.
*/
public static function send_api_error_email(int $order_id, array $api_result, array $payload = []): bool {
// Vérifier si l'email est configuré
$email = \get_option('esi_peppol_email', '');
if (empty($email) || !\is_email($email)) {
return false;
}
// Récupérer la commande
$order = \wc_get_order($order_id);
if (!$order instanceof \WC_Order) {
return false;
}
// Préparer les variables pour le template
$order_number = $order->get_order_number();
$http_code = isset($api_result['http_code']) ? (int) $api_result['http_code'] : 0;
$error_message = isset($api_result['message']) && $api_result['message'] !== ''
? (string) $api_result['message']
: \__('Erreur inconnue lors de l\'envoi vers l\'API Peppol.', 'esi_peppol');
// Extraire les données d'erreur supplémentaires
$error_data = [];
if (isset($api_result['data']) && is_array($api_result['data'])) {
$error_data = $api_result['data'];
}
// Si la structure error existe directement dans api_result, l'inclure aussi
if (isset($api_result['error']) && is_array($api_result['error'])) {
$error_data['error'] = $api_result['error'];
// Si le message d'erreur n'est pas défini, utiliser celui de error.message
if (empty($error_message) && isset($api_result['error']['message'])) {
$error_message = (string) $api_result['error']['message'];
}
}
// Récupérer le template email
$template_path = ESI_PEPPOL_DIR . 'templates/email/api-error.php';
if (!file_exists($template_path)) {
return false;
}
// Capturer le contenu du template
ob_start();
include $template_path;
$email_body = ob_get_clean();
// Préparer les en-têtes de l'email
$site_name = \get_bloginfo('name');
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: ' . $site_name . ' <' . \get_option('admin_email') . '>',
];
// Sujet de l'email
$subject = \sprintf(
/* translators: %1$s: site name, %2$s: order number */
\__('[%1$s] Erreur API Peppol - Commande %2$s', 'esi_peppol'),
$site_name,
$order_number
);
// Envoyer l'email
$sent = \wp_mail($email, $subject, $email_body, $headers);
// Log de l'envoi
if ($sent) {
self::write_debug_file(
[
'event' => 'api_error_email_sent',
'order_id' => $order_id,
'email' => $email,
'http_code' => $http_code,
'error_message' => $error_message,
],
'INFO'
);
} else {
self::write_debug_file(
[
'event' => 'api_error_email_failed',
'order_id' => $order_id,
'email' => $email,
'error' => 'wp_mail returned false',
],
'ERROR'
);
}
return $sent;
}
}