Intégration webhook
This commit is contained in:
parent
f350b5ff10
commit
67d6f66f59
@ -84,6 +84,9 @@ spl_autoload_register(function ($class) {
|
|||||||
case 'controllers\\PEPPOL_peppol_controller':
|
case 'controllers\\PEPPOL_peppol_controller':
|
||||||
$file = $base_dir . 'controllers/Peppol_controller.php';
|
$file = $base_dir . 'controllers/Peppol_controller.php';
|
||||||
break;
|
break;
|
||||||
|
case 'controllers\\PEPPOL_Webhook_controller':
|
||||||
|
$file = $base_dir . 'controllers/Webhook_controller.php';
|
||||||
|
break;
|
||||||
case 'models\\PEPPOL_Main_model':
|
case 'models\\PEPPOL_Main_model':
|
||||||
$file = $base_dir . 'models/Main_model.php';
|
$file = $base_dir . 'models/Main_model.php';
|
||||||
break;
|
break;
|
||||||
@ -163,4 +166,10 @@ add_action(
|
|||||||
$plugin->init();
|
$plugin->init();
|
||||||
},
|
},
|
||||||
20
|
20
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enregistrement des routes REST API pour les webhooks
|
||||||
|
add_action(
|
||||||
|
'rest_api_init',
|
||||||
|
[\ESI_PEPPOL\controllers\PEPPOL_Webhook_controller::class, 'register_routes']
|
||||||
);
|
);
|
||||||
306
app/controllers/Webhook_controller.php
Normal file
306
app/controllers/Webhook_controller.php
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace ESI_PEPPOL\controllers;
|
||||||
|
|
||||||
|
use ESI_PEPPOL\models\PEPPOL_Main_model;
|
||||||
|
use WP_REST_Request;
|
||||||
|
use WP_REST_Response;
|
||||||
|
use WP_Error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contrôleur pour gérer la réception des webhooks depuis l'API ESI Peppol.
|
||||||
|
*
|
||||||
|
* Les webhooks permettent de recevoir des notifications automatiques
|
||||||
|
* lorsque le statut d'un document change.
|
||||||
|
*/
|
||||||
|
class PEPPOL_Webhook_controller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enregistre les routes REST API pour les webhooks.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function register_routes(): void {
|
||||||
|
register_rest_route(
|
||||||
|
'esi-peppol/v1',
|
||||||
|
'/webhook',
|
||||||
|
[
|
||||||
|
'methods' => 'POST',
|
||||||
|
'callback' => [self::class, 'handle_webhook'],
|
||||||
|
'permission_callback' => [self::class, 'permission_check'],
|
||||||
|
'args' => [
|
||||||
|
'event' => [
|
||||||
|
'required' => true,
|
||||||
|
'type' => 'string',
|
||||||
|
'validate_callback' => [self::class, 'validate_event'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie les permissions pour accéder à l'endpoint webhook.
|
||||||
|
*
|
||||||
|
* Les webhooks sont authentifiés via les headers personnalisés
|
||||||
|
* X-ESIPeppol-Event, X-ESIPeppol-Document-ID, X-ESIPeppol-Company-ID.
|
||||||
|
*
|
||||||
|
* @param WP_REST_Request $request Requête REST.
|
||||||
|
* @return bool|WP_Error
|
||||||
|
*/
|
||||||
|
public static function permission_check(WP_REST_Request $request) {
|
||||||
|
// Vérifier la présence des headers requis
|
||||||
|
$event_header = $request->get_header('X-ESIPeppol-Event');
|
||||||
|
$document_id_header = $request->get_header('X-ESIPeppol-Document-ID');
|
||||||
|
$company_id_header = $request->get_header('X-ESIPeppol-Company-ID');
|
||||||
|
|
||||||
|
if (empty($event_header) || empty($document_id_header) || empty($company_id_header)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'missing_headers',
|
||||||
|
__('Headers webhook manquants.', 'esi_peppol'),
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionnel : vérifier que le Company-ID correspond à celui configuré
|
||||||
|
// Pour l'instant, on accepte tous les webhooks avec les headers requis
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valide le type d'événement webhook.
|
||||||
|
*
|
||||||
|
* @param string $value Valeur à valider.
|
||||||
|
* @param WP_REST_Request $request Requête REST.
|
||||||
|
* @param string $param Nom du paramètre.
|
||||||
|
* @return bool|WP_Error
|
||||||
|
*/
|
||||||
|
public static function validate_event($value, WP_REST_Request $request, string $param) {
|
||||||
|
$allowed_events = ['document.sent', 'document.error', 'document.completed'];
|
||||||
|
|
||||||
|
if (!in_array($value, $allowed_events, true)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'invalid_event',
|
||||||
|
sprintf(
|
||||||
|
/* translators: %s: liste des événements autorisés */
|
||||||
|
__('Type d\'événement invalide. Événements autorisés : %s', 'esi_peppol'),
|
||||||
|
implode(', ', $allowed_events)
|
||||||
|
),
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traite la réception d'un webhook.
|
||||||
|
*
|
||||||
|
* @param WP_REST_Request $request Requête REST contenant les données du webhook.
|
||||||
|
* @return WP_REST_Response|WP_Error
|
||||||
|
*/
|
||||||
|
public static function handle_webhook(WP_REST_Request $request) {
|
||||||
|
// Récupérer les headers
|
||||||
|
$event = $request->get_header('X-ESIPeppol-Event');
|
||||||
|
$document_id = $request->get_header('X-ESIPeppol-Document-ID');
|
||||||
|
$company_id = $request->get_header('X-ESIPeppol-Company-ID');
|
||||||
|
|
||||||
|
// Récupérer le body JSON
|
||||||
|
$body = $request->get_json_params();
|
||||||
|
|
||||||
|
if (empty($body)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'invalid_body',
|
||||||
|
__('Corps de la requête invalide ou vide.', 'esi_peppol'),
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valider la structure du payload
|
||||||
|
if (!isset($body['event']) || !isset($body['document'])) {
|
||||||
|
return new WP_Error(
|
||||||
|
'invalid_payload',
|
||||||
|
__('Structure du payload invalide. Champs requis : event, document.', 'esi_peppol'),
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier la cohérence entre le header et le body
|
||||||
|
if ($body['event'] !== $event) {
|
||||||
|
return new WP_Error(
|
||||||
|
'event_mismatch',
|
||||||
|
__('Le type d\'événement dans le header ne correspond pas à celui du body.', 'esi_peppol'),
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extraire les données du document
|
||||||
|
$document_data = $body['document'];
|
||||||
|
|
||||||
|
// Le document_id peut être dans document.document_id (UUID) ou document.id (entier)
|
||||||
|
// On privilégie document_id (UUID) car c'est celui stocké dans notre base
|
||||||
|
$document_id_from_body = '';
|
||||||
|
if (isset($document_data['document_id']) && !empty($document_data['document_id'])) {
|
||||||
|
$document_id_from_body = (string) $document_data['document_id'];
|
||||||
|
} elseif (isset($document_data['id'])) {
|
||||||
|
// Fallback sur l'ID numérique si document_id n'est pas disponible
|
||||||
|
$document_id_from_body = (string) $document_data['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utiliser le document_id du body si disponible, sinon celui du header
|
||||||
|
$final_document_id = !empty($document_id_from_body) ? $document_id_from_body : $document_id;
|
||||||
|
|
||||||
|
// Log de réception du webhook
|
||||||
|
if (class_exists(PEPPOL_Plugin::class)) {
|
||||||
|
PEPPOL_Plugin::write_debug_file(
|
||||||
|
[
|
||||||
|
'event' => 'webhook_received',
|
||||||
|
'event_type' => $event,
|
||||||
|
'document_id' => $final_document_id,
|
||||||
|
'company_id' => $company_id,
|
||||||
|
'payload' => $body,
|
||||||
|
],
|
||||||
|
'INFO'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traiter selon le type d'événement
|
||||||
|
$result = self::process_webhook_event($event, $final_document_id, $body);
|
||||||
|
|
||||||
|
if (is_wp_error($result)) {
|
||||||
|
// Log de l'erreur
|
||||||
|
if (class_exists(PEPPOL_Plugin::class)) {
|
||||||
|
PEPPOL_Plugin::write_debug_file(
|
||||||
|
[
|
||||||
|
'event' => 'webhook_error',
|
||||||
|
'event_type' => $event,
|
||||||
|
'document_id' => $final_document_id,
|
||||||
|
'error' => $result->get_error_message(),
|
||||||
|
'error_code' => $result->get_error_code(),
|
||||||
|
],
|
||||||
|
'ERROR'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Réponse de succès (code 200-299 requis par la documentation)
|
||||||
|
return new WP_REST_Response(
|
||||||
|
[
|
||||||
|
'success' => true,
|
||||||
|
'message' => __('Webhook traité avec succès.', 'esi_peppol'),
|
||||||
|
],
|
||||||
|
200
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traite un événement webhook spécifique.
|
||||||
|
*
|
||||||
|
* @param string $event Type d'événement (document.sent, document.error, document.completed).
|
||||||
|
* @param string $document_id ID du document.
|
||||||
|
* @param array $payload Données complètes du webhook.
|
||||||
|
* @return bool|WP_Error
|
||||||
|
*/
|
||||||
|
private static function process_webhook_event(string $event, string $document_id, array $payload): bool|WP_Error {
|
||||||
|
$document_data = $payload['document'] ?? [];
|
||||||
|
|
||||||
|
// Déterminer le nouveau statut selon l'événement
|
||||||
|
$new_status = match ($event) {
|
||||||
|
'document.sent' => 'sent',
|
||||||
|
'document.error' => 'error',
|
||||||
|
'document.completed' => 'completed',
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($new_status === null) {
|
||||||
|
return new WP_Error(
|
||||||
|
'unknown_event',
|
||||||
|
sprintf(
|
||||||
|
/* translators: %s: type d'événement */
|
||||||
|
__('Type d\'événement inconnu : %s', 'esi_peppol'),
|
||||||
|
$event
|
||||||
|
),
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extraire le peppol_document_id si disponible
|
||||||
|
$peppol_document_id = isset($document_data['peppol_document_id'])
|
||||||
|
? (string) $document_data['peppol_document_id']
|
||||||
|
: '';
|
||||||
|
|
||||||
|
// Extraire le message d'erreur si présent
|
||||||
|
$message = '';
|
||||||
|
if ($event === 'document.error' && isset($payload['error']['message'])) {
|
||||||
|
$message = (string) $payload['error']['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour le document dans la base de données
|
||||||
|
$updated = PEPPOL_Main_model::update_by_document_id(
|
||||||
|
$document_id,
|
||||||
|
$new_status,
|
||||||
|
$peppol_document_id,
|
||||||
|
$message,
|
||||||
|
$payload
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$updated) {
|
||||||
|
// Document non trouvé - ce n'est pas forcément une erreur critique
|
||||||
|
// (le document pourrait avoir été créé manuellement dans l'interface ESI Peppol)
|
||||||
|
if (class_exists(PEPPOL_Plugin::class)) {
|
||||||
|
PEPPOL_Plugin::write_debug_file(
|
||||||
|
[
|
||||||
|
'event' => 'webhook_document_not_found',
|
||||||
|
'document_id' => $document_id,
|
||||||
|
'status' => $new_status,
|
||||||
|
'message' => __('Document non trouvé dans la base de données WordPress. Il a peut-être été créé manuellement dans l\'interface ESI Peppol.', 'esi_peppol'),
|
||||||
|
],
|
||||||
|
'WARNING'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On retourne quand même true car le webhook a été reçu et traité
|
||||||
|
// (même si le document n'existe pas dans notre base)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log de succès
|
||||||
|
if (class_exists(PEPPOL_Plugin::class)) {
|
||||||
|
PEPPOL_Plugin::write_debug_file(
|
||||||
|
[
|
||||||
|
'event' => 'webhook_processed',
|
||||||
|
'event_type' => $event,
|
||||||
|
'document_id' => $document_id,
|
||||||
|
'new_status' => $new_status,
|
||||||
|
'peppol_document_id' => $peppol_document_id,
|
||||||
|
],
|
||||||
|
'INFO'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne l'URL complète de l'endpoint webhook.
|
||||||
|
*
|
||||||
|
* Cette URL doit être configurée dans l'interface d'administration Filament
|
||||||
|
* de l'API ESI Peppol.
|
||||||
|
*
|
||||||
|
* @return string URL du webhook.
|
||||||
|
*/
|
||||||
|
public static function get_webhook_url(): string {
|
||||||
|
$rest_url = rest_url('esi-peppol/v1/webhook');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filtre pour modifier l'URL du webhook.
|
||||||
|
*
|
||||||
|
* @param string $rest_url URL REST par défaut.
|
||||||
|
*/
|
||||||
|
return (string) apply_filters('esi_peppol_webhook_url', $rest_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -283,4 +283,106 @@ class PEPPOL_Main_model {
|
|||||||
|
|
||||||
return $row;
|
return $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère un enregistrement PEPPOL par document_id (UUID retourné par l'API ESI Peppol).
|
||||||
|
*
|
||||||
|
* @param string $document_id Document ID (UUID).
|
||||||
|
* @return object|null
|
||||||
|
*/
|
||||||
|
public static function get_by_document_id(string $document_id): ?object {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$table_name = self::get_table_name();
|
||||||
|
|
||||||
|
$row = $wpdb->get_row(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT * FROM {$table_name} WHERE document_id = %s LIMIT 1",
|
||||||
|
$document_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour le statut d'un document par son document_id (UUID).
|
||||||
|
*
|
||||||
|
* Utilisé lors de la réception des webhooks pour mettre à jour
|
||||||
|
* le statut d'un document sans connaître l'ID de commande.
|
||||||
|
*
|
||||||
|
* @param string $document_id Document ID (UUID).
|
||||||
|
* @param string $status Nouveau statut (sent, error, completed).
|
||||||
|
* @param string $peppol_document_id Peppol document ID (optionnel).
|
||||||
|
* @param string $message Message d'information / d'erreur (optionnel).
|
||||||
|
* @param array|null $webhook_payload Payload complet du webhook pour stockage (optionnel).
|
||||||
|
*
|
||||||
|
* @return bool True si la mise à jour a réussi, false sinon.
|
||||||
|
*/
|
||||||
|
public static function update_by_document_id(
|
||||||
|
string $document_id,
|
||||||
|
string $status,
|
||||||
|
string $peppol_document_id = '',
|
||||||
|
string $message = '',
|
||||||
|
?array $webhook_payload = null
|
||||||
|
): bool {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$table_name = self::get_table_name();
|
||||||
|
$now = \current_time('mysql');
|
||||||
|
|
||||||
|
// Déterminer le success selon le statut
|
||||||
|
$success = in_array($status, ['sent', 'completed'], true) ? 1 : 0;
|
||||||
|
|
||||||
|
// Préparer les données de mise à jour
|
||||||
|
$update_data = [
|
||||||
|
'status' => $status,
|
||||||
|
'success' => $success,
|
||||||
|
'date_update' => $now,
|
||||||
|
];
|
||||||
|
|
||||||
|
$format = ['%s', '%d', '%s'];
|
||||||
|
|
||||||
|
// Mettre à jour peppol_document_id si fourni
|
||||||
|
if ($peppol_document_id !== '') {
|
||||||
|
$update_data['peppol_document_id'] = $peppol_document_id;
|
||||||
|
$format[] = '%s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour le message si fourni
|
||||||
|
if ($message !== '') {
|
||||||
|
$update_data['message'] = $message;
|
||||||
|
$format[] = '%s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour response_data avec le payload du webhook si fourni
|
||||||
|
if ($webhook_payload !== null) {
|
||||||
|
$serialized_payload = \maybe_serialize($webhook_payload);
|
||||||
|
$update_data['response_data'] = $serialized_payload;
|
||||||
|
$format[] = '%s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effectuer la mise à jour
|
||||||
|
$updated = $wpdb->update(
|
||||||
|
$table_name,
|
||||||
|
$update_data,
|
||||||
|
['document_id' => $document_id],
|
||||||
|
$format,
|
||||||
|
['%s']
|
||||||
|
);
|
||||||
|
|
||||||
|
return $updated !== false && $updated > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -35,6 +35,22 @@
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.esi-peppol-webhook-url-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esi-peppol-webhook-url-wrapper .regular-text {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
background-color: #f6f7f7;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.esi-peppol-webhook-url-wrapper .regular-text:focus {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
#esi-peppol-test-result {
|
#esi-peppol-test-result {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -457,6 +457,44 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bouton pour copier l'URL du webhook
|
||||||
|
var $copyWebhookBtn = $('.esi-peppol-copy-webhook-url');
|
||||||
|
if ($copyWebhookBtn.length) {
|
||||||
|
$copyWebhookBtn.on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $target = $($(this).data('target'));
|
||||||
|
if ($target.length) {
|
||||||
|
$target.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
var $btn = $(this);
|
||||||
|
var originalText = $btn.text();
|
||||||
|
$btn.text('✓ Copié').prop('disabled', true);
|
||||||
|
setTimeout(function () {
|
||||||
|
$btn.text(originalText).prop('disabled', false);
|
||||||
|
}, 2000);
|
||||||
|
} catch (err) {
|
||||||
|
// Fallback pour les navigateurs qui ne supportent pas execCommand
|
||||||
|
console.error('Erreur lors de la copie:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle afficher/masquer mot de passe
|
||||||
|
var $passwordToggle = $('.esi-peppol-password-toggle');
|
||||||
|
if ($passwordToggle.length) {
|
||||||
|
$passwordToggle.on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var $target = $($(this).data('target'));
|
||||||
|
if ($target.length) {
|
||||||
|
var type = $target.attr('type') === 'password' ? 'text' : 'password';
|
||||||
|
$target.attr('type', type);
|
||||||
|
$(this).text(type === 'password' ? 'Afficher' : 'Masquer');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
|||||||
@ -120,6 +120,43 @@ if ($logo_email_id) {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label><?php esc_html_e('URL Webhook', 'esi_peppol'); ?></label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
$webhook_url = \ESI_PEPPOL\controllers\PEPPOL_Webhook_controller::get_webhook_url();
|
||||||
|
?>
|
||||||
|
<div class="esi-peppol-webhook-url-wrapper">
|
||||||
|
<input type="text"
|
||||||
|
class="regular-text"
|
||||||
|
id="esi_peppol_webhook_url"
|
||||||
|
value="<?php echo esc_attr($webhook_url); ?>"
|
||||||
|
readonly
|
||||||
|
onclick="this.select();"
|
||||||
|
/>
|
||||||
|
<button type="button"
|
||||||
|
class="button button-small esi-peppol-copy-webhook-url"
|
||||||
|
data-target="#esi_peppol_webhook_url"
|
||||||
|
aria-label="<?php esc_attr_e('Copier l\'URL du webhook', 'esi_peppol'); ?>">
|
||||||
|
<?php esc_html_e('Copier', 'esi_peppol'); ?>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p class="description">
|
||||||
|
<?php
|
||||||
|
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. <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')
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<!-- <tr>
|
<!-- <tr>
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
<label for="esi_peppol_logo_email"><?php esc_html_e('Logo Email', 'esi_peppol'); ?></label>
|
<label for="esi_peppol_logo_email"><?php esc_html_e('Logo Email', 'esi_peppol'); ?></label>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user