Test
This commit is contained in:
parent
a18536ddc4
commit
9c56e63820
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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_vat_number_format', '');
|
||||
$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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -323,5 +323,116 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
299
exemple-timeline.html
Normal 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>
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user