This commit is contained in:
Jean-Philippe Staelen 2026-01-23 16:32:40 +01:00
parent a18536ddc4
commit 9c56e63820
8 changed files with 607 additions and 41 deletions

View File

@ -514,19 +514,6 @@ class PEPPOL_peppol_controller {
$wpo_invoice_number = (string) $order->get_meta('_wcpdf_invoice_number', true);
if ($wpo_invoice_number !== '') {
$invoice_number = $wpo_invoice_number;
} else {
$use_backup_format = !\ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_has_wpo_invoice_numbers();
if ($use_backup_format) {
$backup_format = (string) \get_option('esi_peppol_vat_number_format', '');
if ($backup_format !== '') {
$generated = self::build_invoice_number_from_format($backup_format, $order);
if ($generated !== '') {
$invoice_number = $generated;
$order->update_meta_data('_wcpdf_invoice_number', $generated);
$order->save();
}
}
}
}
$currency_code = $order->get_currency();
@ -568,6 +555,25 @@ class PEPPOL_peppol_controller {
$order
);
$payment_data = PEPPOL_Woo_Helper::esi_get_order_payment_data($order);
$payment_means_code = $payment_data['payment_means_code'] ?? '30';
if (!empty($payment_data['payment_terms'])) {
$payment_terms = $payment_data['payment_terms'];
}
$payment_means_code = \apply_filters(
'esi_peppol_payment_means_code',
$payment_means_code,
$payment_data,
$order
);
$payment_terms = \apply_filters(
'esi_peppol_payment_terms_from_payment',
$payment_terms,
$payment_data,
$order
);
// Données vendeur (store) - basées sur les options WooCommerce
$store_name = \get_bloginfo('name');
$store_address = \get_option('woocommerce_store_address', '');
@ -1020,6 +1026,7 @@ class PEPPOL_peppol_controller {
'currency_code' => $currency_code,
'invoice_notes' => $invoice_notes,
'payment_terms' => $payment_terms,
'payment_means_code' => $payment_means_code,
],
'parties' => [
'seller' => $seller,
@ -1034,6 +1041,42 @@ class PEPPOL_peppol_controller {
return \apply_filters('esi_peppol_payload_from_order', $payload, $order);
}
/**
* Génère et sauvegarde un numéro WPO si format de secours configuré.
*/
public static function ensure_invoice_number_meta(\WC_Order $order): void {
$wpo_invoice_number = (string) $order->get_meta('_wcpdf_invoice_number', true);
if ($wpo_invoice_number !== '') {
return;
}
$use_backup_format = !\ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_has_wpo_invoice_numbers();
if (!$use_backup_format) {
return;
}
$backup_format = (string) \get_option('esi_peppol_invoice_number_format', '');
if ($backup_format === '') {
$backup_format = (string) \get_option('esi_peppol_vat_number_format', '');
}
if ($backup_format !== '') {
$generated = self::build_invoice_number_from_format($backup_format, $order);
if ($generated !== '') {
$order->update_meta_data('_wcpdf_invoice_number', $generated);
$order->save();
}
return;
}
$fallback = (string) $order->get_order_number();
if ($fallback === '') {
return;
}
$order->update_meta_data('_wcpdf_invoice_number', $fallback);
$order->save();
}
/**
* Construit un numéro de facture depuis un format de secours.
* Placeholders supportés : {YYYY}, {YY}, {MM}, {DD}, {ORDER_ID}, {ORDER_NUMBER}
@ -1044,6 +1087,8 @@ class PEPPOL_peppol_controller {
$month = $date ? $date->date('m') : \gmdate('m');
$day = $date ? $date->date('d') : \gmdate('d');
$sequence = self::get_next_invoice_sequence($format, $order, $year);
$replacements = [
'{YYYY}' => $year,
'{YY}' => substr($year, -2),
@ -1051,10 +1096,86 @@ class PEPPOL_peppol_controller {
'{DD}' => $day,
'{ORDER_ID}' => (string) $order->get_id(),
'{ORDER_NUMBER}' => (string) $order->get_order_number(),
'{number}' => $sequence,
];
$result = strtr($format, $replacements);
return trim($result);
}
private static function get_next_invoice_sequence(string $format, \WC_Order $order, string $current_year): string {
if (!function_exists('wc_get_orders')) {
return '1';
}
$orders = \wc_get_orders([
'limit' => 1,
'orderby' => 'date',
'order' => 'DESC',
'status' => 'any',
'meta_key' => '_wcpdf_invoice_number',
'meta_compare' => 'EXISTS',
'exclude' => [$order->get_id()],
'return' => 'objects',
]);
if (empty($orders)) {
return '1';
}
$last_order = $orders[0];
$last_invoice = (string) $last_order->get_meta('_wcpdf_invoice_number', true);
if ($last_invoice === '') {
return '1';
}
$matches = self::match_invoice_number_format($format, $last_invoice);
if (empty($matches['number'])) {
return '1';
}
$last_number = (int) $matches['number'];
$number_width = strlen((string) $matches['number']);
$next_number = $last_number + 1;
if (strpos($format, '{YYYY}') !== false) {
$last_year = (string) ($matches['year'] ?? '');
if ($last_year !== $current_year) {
$next_number = 1;
}
} elseif (strpos($format, '{YY}') !== false) {
$current_year2 = substr($current_year, -2);
$last_year2 = (string) ($matches['year2'] ?? '');
if ($last_year2 !== $current_year2) {
$next_number = 1;
}
}
$next_str = (string) $next_number;
if ($number_width > 1) {
$next_str = str_pad($next_str, $number_width, '0', STR_PAD_LEFT);
}
return $next_str;
}
private static function match_invoice_number_format(string $format, string $value): array {
$pattern = preg_quote($format, '/');
$pattern = str_replace('\{YYYY\}', '(?P<year>\d{4})', $pattern);
$pattern = str_replace('\{YY\}', '(?P<year2>\d{2})', $pattern);
$pattern = str_replace('\{MM\}', '(?P<month>\d{2})', $pattern);
$pattern = str_replace('\{DD\}', '(?P<day>\d{2})', $pattern);
$pattern = str_replace('\{ORDER_ID\}', '\d+', $pattern);
$pattern = str_replace('\{ORDER_NUMBER\}', '.+?', $pattern);
$pattern = str_replace('\{number\}', '(?P<number>\d+)', $pattern);
$pattern = '/^' . $pattern . '$/';
$matches = [];
if (preg_match($pattern, $value, $matches) !== 1) {
return [];
}
return $matches;
}
}

View File

@ -155,17 +155,21 @@ class PEPPOL_Plugin {
$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;
$vat_number_format = get_option('esi_peppol_vat_number_format', '');
if (isset($_POST['esi_peppol_vat_number_format'])) {
$vat_number_format = sanitize_text_field(wp_unslash($_POST['esi_peppol_vat_number_format']));
$invoice_number_format = get_option('esi_peppol_invoice_number_format', '');
if ($invoice_number_format === '') {
$invoice_number_format = get_option('esi_peppol_vat_number_format', '');
}
if (isset($_POST['esi_peppol_invoice_number_format'])) {
$invoice_number_format = sanitize_text_field(wp_unslash($_POST['esi_peppol_invoice_number_format']));
}
$invoice_number_format = self::normalize_invoice_number_format($invoice_number_format);
// 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);
update_option('esi_peppol_vat_number_format', $vat_number_format);
update_option('esi_peppol_invoice_number_format', $invoice_number_format);
if ($action === 'save') {
$notice = __('Paramètres enregistrés avec succès.', 'esi_peppol');
@ -1296,11 +1300,11 @@ class PEPPOL_Plugin {
'action_url' => admin_url('admin.php?page=esi-peppol-settings'),
'action_label' => __('Détecter le champ TVA', 'esi_peppol'),
],
'vat_number_format' => [
'invoice_number_format' => [
'completed' => false,
'value' => '',
'label' => __('Format num TVA', 'esi_peppol'),
'description' => __('Format du numéro de TVA (backup si aucun format détecté automatiquement)', 'esi_peppol'),
'label' => __('Format num facture', 'esi_peppol'),
'description' => __('Format du numéro de facture (backup si aucun format détecté automatiquement)', 'esi_peppol'),
'action_url' => admin_url('admin.php?page=esi-peppol-settings'),
'action_label' => __('Configurer le format', 'esi_peppol'),
],
@ -1350,16 +1354,19 @@ class PEPPOL_Plugin {
if (\ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_has_wpo_invoice_numbers()) {
$detected_format = \ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_get_wpo_invoice_number_format_label();
}
$backup_format = (string) get_option('esi_peppol_invoice_number_format', '');
if ($backup_format === '') {
$backup_format = (string) get_option('esi_peppol_vat_number_format', '');
}
if ($detected_format !== '') {
$status['vat_number_format']['completed'] = true;
$status['vat_number_format']['value'] = sprintf(
$status['invoice_number_format']['completed'] = true;
$status['invoice_number_format']['value'] = sprintf(
__('Format détecté : %s', 'esi_peppol'),
$detected_format
);
} elseif ($backup_format !== '') {
$status['vat_number_format']['completed'] = true;
$status['vat_number_format']['value'] = $backup_format;
$status['invoice_number_format']['completed'] = true;
$status['invoice_number_format']['value'] = $backup_format;
}
// Vérifier les identifiants API
@ -1386,6 +1393,18 @@ class PEPPOL_Plugin {
return $status;
}
private static function normalize_invoice_number_format(string $format): string {
$format = trim($format);
if ($format === '') {
return '';
}
$format = str_replace('{number}', '', $format);
$format = trim($format);
return $format . '{number}';
}
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);

View File

@ -91,6 +91,9 @@ class PEPPOL_Woocommerce_controller {
return;
}
// Générer un numéro de facture de secours si nécessaire
PEPPOL_peppol_controller::ensure_invoice_number_meta($order);
// Construire le payload JSON à partir de la commande
$payload = PEPPOL_peppol_controller::build_payload_from_order($order);

View File

@ -324,4 +324,115 @@ class PEPPOL_Woo_Helper {
return array_values($vat_fields_found);
}
public static function esi_is_wpo_wcpdf_installed(): bool {
if (!function_exists('get_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugins = get_plugins(); // [ 'dir/main.php' => headers... ]
foreach ($plugins as $file => $data) {
if ($file === 'woocommerce-pdf-invoices-packing-slips/woocommerce-pdf-invoices-packingslips.php') {
return true;
}
// Optionnel : fallback par Name (plus fragile, dépend de la traduction / headers)
if (!empty($data['Name']) && stripos($data['Name'], 'PDF Invoices') !== false) {
// pas ultra fiable, mais utile en dernier recours
}
}
return false;
}
/**
* detecte les num de facture enregistré
*/
//wpo_wcpdf_documents_settings_invoice
/*
Array
(
[enabled] => 1
[attach_to_email_ids] => Array
(
[customer_on_hold_order] => 1
[customer_processing_order] => 1
[customer_completed_order] => 1
)
[my_account_buttons] => available
[display_email] => 1
[display_customer_notes] => 1
[display_shipping_address] =>
[display_number] => invoice_number
[number_format] => Array
(
[prefix] => 2026-
[suffix] =>
[padding] =>
)
[display_date] =>
)*/
/**
* Vérifie la présence de numéros de facture WPO WCPDF.
* - Plugin installé
* - Paramètres facture activés
* - Au moins une commande avec meta _wcpdf_invoice_number
*/
public static function esi_has_wpo_invoice_numbers(): bool {
if ( ! self::esi_is_wpo_wcpdf_installed() ) {
return false;
}
if ( ! function_exists( 'wc_get_orders' ) ) {
return false;
}
$settings = get_option( 'wpo_wcpdf_documents_settings_invoice', [] );
if ( empty( $settings ) || ! is_array( $settings ) ) {
return false;
}
if ( empty( $settings['enabled'] ) ) {
return false;
}
if ( empty( $settings['display_number'] ) || $settings['display_number'] !== 'invoice_number' ) {
return false;
}
$orders = wc_get_orders( [
'limit' => 1,
'status' => 'any',
'meta_key' => '_wcpdf_invoice_number',
'meta_compare' => 'EXISTS',
'return' => 'ids',
] );
return ! empty( $orders );
}
/**
* Retourne un libellé lisible du format des numéros WPO WCPDF.
*/
public static function esi_get_wpo_invoice_number_format_label(): string {
$settings = get_option( 'wpo_wcpdf_documents_settings_invoice', [] );
if ( empty( $settings ) || ! is_array( $settings ) ) {
return '';
}
$number_format = $settings['number_format'] ?? [];
if ( ! is_array( $number_format ) ) {
return '';
}
$prefix = (string) ( $number_format['prefix'] ?? '' );
$suffix = (string) ( $number_format['suffix'] ?? '' );
$padding = (string) ( $number_format['padding'] ?? '' );
$format = $prefix . '{number}' . $suffix;
if ( $padding !== '' ) {
$format .= ' (padding: ' . $padding . ')';
}
return $format;
}
}

View File

@ -199,6 +199,7 @@
}
// Toggle affichage du mot de passe sur la page de configuration
$('.esi-peppol-password-toggle').on('click', function (e) {
e.preventDefault();
var $btn = $(this);

299
exemple-timeline.html Normal file
View File

@ -0,0 +1,299 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exemple Timeline Verticale</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 900px;
margin: 0 auto;
background: #ffffff;
border-radius: 16px;
padding: 40px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
}
h1 {
text-align: center;
color: #1f2937;
margin-bottom: 40px;
font-size: 32px;
}
/* ====================================
TIMELINE VERTICALE
==================================== */
.timeline {
max-width: 800px;
margin: 0 auto;
}
.step {
position: relative;
padding-left: 70px;
padding-bottom: 40px;
min-height: 80px;
}
/* Dernier élément sans padding-bottom */
.step:last-child {
padding-bottom: 0;
}
/* Cercle numéroté (::before) */
.step::before {
content: attr(data-step);
position: absolute;
left: 0;
top: 0;
width: 44px;
height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 18px;
z-index: 2;
/* État par défaut : cercle blanc, bord gris, numéro gris */
background-color: #ffffff;
border: 3px solid #d1d5db;
color: #9ca3af;
}
/* Ligne verticale (::after) */
.step::after {
content: '';
position: absolute;
left: 22px; /* Centre du cercle (44px / 2) */
top: 44px; /* Sous le cercle */
bottom: 0;
width: 3px;
/* État par défaut : ligne grise */
background-color: #d1d5db;
z-index: 1;
}
/* Masquer la ligne sur le dernier élément */
.step:last-child::after {
display: none;
}
/* Carte de contenu */
.step-card {
background-color: #f3f4f6;
border: 2px solid #e5e7eb;
border-radius: 8px;
padding: 20px 24px;
transition: all 0.3s ease;
}
.step-card h3 {
margin: 0 0 8px 0;
font-size: 18px;
font-weight: 600;
color: #374151;
}
.step-card p {
margin: 0 0 16px 0;
color: #6b7280;
line-height: 1.6;
}
.step-card .step-value {
display: inline-block;
background-color: #ffffff;
border: 1px solid #d1d5db;
border-radius: 4px;
padding: 8px 12px;
margin-top: 8px;
}
.step-card .step-value strong {
display: block;
margin-bottom: 4px;
font-size: 13px;
color: #6b7280;
}
.step-card .step-value code {
color: #1f2937;
font-size: 14px;
font-weight: 500;
font-family: 'Courier New', Courier, monospace;
}
.step-card .btn {
display: inline-block;
padding: 10px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
text-decoration: none;
border-radius: 6px;
font-weight: 500;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.step-card .btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
/* ========================================
ÉTAT COMPLÉTÉ : .is-done
======================================== */
.step.is-done::before {
/* Check ✓ ou numéro en bleu */
background-color: #dbeafe;
border-color: #3b82f6;
color: #2563eb;
font-weight: 700;
}
.step.is-done::after {
/* Ligne bleue */
background-color: #3b82f6;
}
.step.is-done .step-card {
/* Carte fond bleu, texte blanc */
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
border-color: #2563eb;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2);
}
.step.is-done .step-card h3 {
color: #ffffff;
}
.step.is-done .step-card p {
color: #dbeafe;
}
.step.is-done .step-card .step-value {
background-color: rgba(255, 255, 255, 0.95);
border-color: #2563eb;
}
.step.is-done .step-card .step-value strong {
color: #2563eb;
}
.step.is-done .step-card .step-value code {
color: #1e40af;
background-color: #eff6ff;
padding: 2px 6px;
border-radius: 3px;
}
/* Pour afficher un check ✓ sur les étapes complétées */
.step.is-done[data-step="✓"]::before {
font-size: 22px;
content: "✓";
}
.note {
text-align: center;
margin-top: 40px;
padding-top: 30px;
border-top: 2px solid #e5e7eb;
color: #6b7280;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h1>Timeline Verticale - Exemple</h1>
<div class="timeline">
<!-- Étape 1: Complétée -->
<div class="step is-done" data-step="✓">
<div class="step-card">
<h3>Configuration du connecteur</h3>
<p>Le numéro de TVA de votre boutique doit être renseigné dans WooCommerce > Réglages > Général</p>
<div class="step-value">
<strong>Valeur configurée :</strong>
<code>BE0431.066.713</code>
</div>
</div>
</div>
<!-- Étape 2: Complétée -->
<div class="step is-done" data-step="✓">
<div class="step-card">
<h3>Numéro de TVA de la boutique</h3>
<p>Le champ utilisé pour récupérer le numéro de TVA du client dans les commandes</p>
<div class="step-value">
<strong>Champ détecté :</strong>
<code>billing_vat_number</code>
</div>
</div>
</div>
<!-- Étape 3: Non complétée -->
<div class="step" data-step="3">
<div class="step-card">
<h3>Champ TVA client</h3>
<p>Le champ utilisé pour récupérer le numéro de TVA du client dans les commandes</p>
<p style="margin-bottom: 0; color: #ef4444; font-weight: 500;">Aucun champ détecté</p>
</div>
</div>
<!-- Étape 4: Non complétée -->
<div class="step" data-step="4">
<div class="step-card">
<h3>Identifiants API</h3>
<p>Votre clé API et mot de passe pour vous connecter à la plateforme ESI Peppol</p>
<p style="margin-bottom: 0; color: #ef4444; font-weight: 500;">Aucune clé API détectée</p>
</div>
</div>
<!-- Étape 5: Non complétée -->
<div class="step" data-step="5">
<div class="step-card">
<h3>URL Webhook</h3>
<p>URL à configurer dans votre profil d'entreprise sur la plateforme</p>
<div class="step-value">
<strong>Configurez cette URL :</strong>
<code>https://peppol.esi-web.be/webhook/callback</code>
</div>
</div>
</div>
<!-- Étape 6: Non complétée (optionnelle) -->
<div class="step" data-step="6">
<div class="step-card">
<h3>Email de notification (optionnel)</h3>
<p>Adresse email pour recevoir les notifications en cas d'erreur d'envoi des factures</p>
<a href="#" class="btn">Configurer un email</a>
</div>
</div>
</div>
<div class="note">
<p><strong>Structure CSS:</strong> .step avec ::before (cercle) et ::after (ligne)</p>
<p><strong>États:</strong> Par défaut (gris) | .is-done (bleu avec check ✓)</p>
</div>
</div>
</body>
</html>

View File

@ -64,20 +64,20 @@ $settings_status = \ESI_PEPPOL\controllers\PEPPOL_Plugin::check_settings_status(
</div>
</div>
<!-- Étape 3: Format num TVA -->
<div class="step <?php echo $settings_status['vat_number_format']['completed'] ? 'is-done' : ''; ?>"
data-step="<?php echo $settings_status['vat_number_format']['completed'] ? '✓' : '3'; ?>">
<!-- Étape 3: Format num facture -->
<div class="step <?php echo $settings_status['invoice_number_format']['completed'] ? 'is-done' : ''; ?>"
data-step="<?php echo $settings_status['invoice_number_format']['completed'] ? '✓' : '3'; ?>">
<div class="step-card">
<h3><?php echo esc_html($settings_status['vat_number_format']['label']); ?></h3>
<p><?php echo esc_html($settings_status['vat_number_format']['description']); ?></p>
<?php if ($settings_status['vat_number_format']['completed']) : ?>
<h3><?php echo esc_html($settings_status['invoice_number_format']['label']); ?></h3>
<p><?php echo esc_html($settings_status['invoice_number_format']['description']); ?></p>
<?php if ($settings_status['invoice_number_format']['completed']) : ?>
<div class="step-value">
<strong><?php esc_html_e('Valeur :', 'esi_peppol'); ?></strong>
<code><?php echo esc_html($settings_status['vat_number_format']['value']); ?></code>
<code><?php echo esc_html($settings_status['invoice_number_format']['value']); ?></code>
</div>
<?php else : ?>
<a href="<?php echo esc_url($settings_status['vat_number_format']['action_url']); ?>" class="button button-primary">
<?php echo esc_html($settings_status['vat_number_format']['action_label']); ?>
<a href="<?php echo esc_url($settings_status['invoice_number_format']['action_url']); ?>" class="button button-primary">
<?php echo esc_html($settings_status['invoice_number_format']['action_label']); ?>
</a>
<?php endif; ?>
</div>

View File

@ -195,11 +195,14 @@ if ($logo_email_id) {
<tr>
<th scope="row">
<label for="esi_peppol_vat_number_format"><?php esc_html_e('Format num TVA', 'esi_peppol'); ?></label>
<label for="esi_peppol_invoice_number_format"><?php esc_html_e('Format num facture', 'esi_peppol'); ?></label>
</th>
<td>
<?php
$backup_vat_format = (string) get_option('esi_peppol_vat_number_format', '');
$backup_invoice_format = (string) get_option('esi_peppol_invoice_number_format', '');
if ($backup_invoice_format === '') {
$backup_invoice_format = (string) get_option('esi_peppol_vat_number_format', '');
}
$has_wpo_invoices = \ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_has_wpo_invoice_numbers();
$detected_format = $has_wpo_invoices
? \ESI_PEPPOL\helpers\PEPPOL_Woo_Helper::esi_get_wpo_invoice_number_format_label()
@ -217,13 +220,22 @@ if ($logo_email_id) {
</p>
<?php else : ?>
<input type="text"
class="regular-text"
id="esi_peppol_vat_number_format"
name="esi_peppol_vat_number_format"
value="<?php echo esc_attr($backup_vat_format); ?>"
class="regular-text esi-peppol-invoice-format-input"
id="esi_peppol_invoice_number_format"
name="esi_peppol_invoice_number_format"
value="<?php echo esc_attr($backup_invoice_format); ?>"
/>
<div class="esi-peppol-placeholder-buttons" style="margin-top: 8px;">
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{YYYY}">{YYYY}</button>
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{YY}">{YY}</button>
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{MM}">{MM}</button>
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{DD}">{DD}</button>
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{ORDER_ID}">{ORDER_ID}</button>
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{ORDER_NUMBER}">{ORDER_NUMBER}</button>
<button type="button" class="button button-secondary esi-peppol-placeholder-btn" data-placeholder="{number}">{number}</button>
</div>
<p class="description">
<?php esc_html_e('Utilisé comme format de secours si aucun format n\'est détecté automatiquement. Placeholders : {YYYY}, {YY}, {MM}, {DD}, {ORDER_ID}, {ORDER_NUMBER}.', 'esi_peppol'); ?>
<?php esc_html_e('Format de secours si aucun format n\'est détecté automatiquement. Doit se terminer par {number}. Placeholders : {YYYY}, {YY}, {MM}, {DD}, {ORDER_ID}, {ORDER_NUMBER}, {number}.', 'esi_peppol'); ?>
</p>
<?php endif; ?>
</td>