fix: Spanish frontend, wider columns, currency symbols, PDF download
PDF fix: - Replace session-cookie auth with HTTP Basic Auth (username:api_key) which is natively supported by Odoo 17+ report endpoints - Validate response is actually a PDF (%PDF header check) before serving - Return a descriptive Spanish error if HTTP code != 200 or body is not PDF Frontend → Spanish: - All invoice template text in Spanish (Nº Factura, Vencimiento, etc.) - All calendar/booking template text in Spanish - Payment state labels: Pendiente / Parcial / En cobro / Pagado / Anulado - "Vencida" badge for overdue invoices - Error/notice messages in Spanish across both pages Currency symbols: - Add currency_symbol() helper mapping ISO codes to symbols - EUR → €, USD → $, GBP → £, etc. (25 currencies mapped) Column widths: - Switch invoice table to table-layout:fixed with explicit column widths - col-number: 180px nowrap so reference never wraps across lines - Date/due/amount/status columns all fixed-width and nowrap - Add .woodoo-nowrap utility class Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,18 +56,35 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
|
table-layout: fixed; /* fixed layout so column widths are respected */
|
||||||
}
|
}
|
||||||
.woodoo-table th,
|
.woodoo-table th,
|
||||||
.woodoo-table td {
|
.woodoo-table td {
|
||||||
padding: 10px 12px;
|
padding: 10px 14px;
|
||||||
border-bottom: 1px solid #e5e7eb;
|
border-bottom: 1px solid #e5e7eb;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.woodoo-table th { background: #f9fafb; font-weight: 600; }
|
.woodoo-table th { background: #f9fafb; font-weight: 600; }
|
||||||
.woodoo-table tr:last-child td { border-bottom: none; }
|
.woodoo-table tr:last-child td { border-bottom: none; }
|
||||||
.woodoo-table .woodoo-amount { text-align: right; font-variant-numeric: tabular-nums; }
|
.woodoo-table .woodoo-amount {
|
||||||
.woodoo-table .woodoo-inv-number { font-weight: 600; }
|
text-align: right;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
/* Invoice-specific column widths */
|
||||||
|
.woodoo-invoices-table .col-number { width: 180px; white-space: nowrap; font-weight: 600; }
|
||||||
|
.woodoo-invoices-table .col-date { width: 100px; white-space: nowrap; }
|
||||||
|
.woodoo-invoices-table .col-due { width: 130px; }
|
||||||
|
.woodoo-invoices-table .col-amount { width: 110px; text-align: right; }
|
||||||
|
.woodoo-invoices-table .col-balance { width: 130px; text-align: right; }
|
||||||
|
.woodoo-invoices-table .col-status { width: 100px; white-space: nowrap; }
|
||||||
|
.woodoo-invoices-table .col-download{ width: 70px; text-align: center; }
|
||||||
|
|
||||||
|
/* Utility: never wrap content in a cell */
|
||||||
|
.woodoo-nowrap { white-space: nowrap; }
|
||||||
|
|
||||||
.woodoo-overdue { color: #dc2626; font-weight: 600; }
|
.woodoo-overdue { color: #dc2626; font-weight: 600; }
|
||||||
|
|
||||||
/* ── Pagination ──────────────────────────────────────────── */
|
/* ── Pagination ──────────────────────────────────────────── */
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class WooDoo_Calendar {
|
|||||||
$api = woodoo_api();
|
$api = woodoo_api();
|
||||||
if ( ! $api ) {
|
if ( ! $api ) {
|
||||||
echo '<p class="woodoo-notice woodoo-error">' .
|
echo '<p class="woodoo-notice woodoo-error">' .
|
||||||
esc_html__( 'Booking is not available right now. Please contact support.', 'woodoo' ) .
|
'Las reservas no están disponibles en este momento. Por favor, contacta con soporte.' .
|
||||||
'</p>';
|
'</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ class WooDoo_Invoices {
|
|||||||
$partner_id = (int) get_user_meta( $user_id, 'woodoo_odoo_partner_id', true );
|
$partner_id = (int) get_user_meta( $user_id, 'woodoo_odoo_partner_id', true );
|
||||||
|
|
||||||
if ( ! $partner_id ) {
|
if ( ! $partner_id ) {
|
||||||
echo '<p class="woodoo-notice">' .
|
echo '<p class="woodoo-notice woodoo-error">' .
|
||||||
esc_html__( 'Your account is not yet linked to Odoo. Please contact us.', 'woodoo' ) .
|
'Tu cuenta aún no está vinculada a Odoo. Por favor, contáctanos para activar esta funcionalidad.' .
|
||||||
'</p>';
|
'</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ class WooDoo_Invoices {
|
|||||||
$api = woodoo_api();
|
$api = woodoo_api();
|
||||||
if ( ! $api ) {
|
if ( ! $api ) {
|
||||||
echo '<p class="woodoo-notice woodoo-error">' .
|
echo '<p class="woodoo-notice woodoo-error">' .
|
||||||
esc_html__( 'Odoo integration is not configured. Please contact support.', 'woodoo' ) .
|
'La integración con Odoo no está configurada. Contacta con soporte.' .
|
||||||
'</p>';
|
'</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -131,82 +131,95 @@ class WooDoo_Invoices {
|
|||||||
wp_die( esc_html__( 'Invoice not found.', 'woodoo' ) );
|
wp_die( esc_html__( 'Invoice not found.', 'woodoo' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the PDF report from Odoo
|
// Fetch the PDF via HTTP Basic Auth (API key as password – supported in Odoo 17+).
|
||||||
|
// This avoids the fragile session-cookie approach entirely.
|
||||||
$odoo_url = rtrim( get_option( 'woodoo_odoo_url', '' ), '/' );
|
$odoo_url = rtrim( get_option( 'woodoo_odoo_url', '' ), '/' );
|
||||||
$pdf_url = $odoo_url . '/report/pdf/account.report_invoice/' . $invoice_id;
|
$pdf_url = $odoo_url . '/report/pdf/account.report_invoice/' . $invoice_id;
|
||||||
|
$basic_auth = 'Basic ' . base64_encode(
|
||||||
// Build auth cookie by first doing session authenticate
|
get_option( 'woodoo_odoo_username', '' ) . ':' . get_option( 'woodoo_odoo_api_key', '' )
|
||||||
$auth_response = wp_remote_post(
|
|
||||||
$odoo_url . '/web/session/authenticate',
|
|
||||||
[
|
|
||||||
'headers' => [ 'Content-Type' => 'application/json' ],
|
|
||||||
'body' => wp_json_encode( [
|
|
||||||
'jsonrpc' => '2.0',
|
|
||||||
'method' => 'call',
|
|
||||||
'id' => 1,
|
|
||||||
'params' => [
|
|
||||||
'db' => get_option( 'woodoo_odoo_db' ),
|
|
||||||
'login' => get_option( 'woodoo_odoo_username' ),
|
|
||||||
'password' => get_option( 'woodoo_odoo_api_key' ),
|
|
||||||
],
|
|
||||||
] ),
|
|
||||||
'timeout' => 20,
|
|
||||||
'sslverify' => apply_filters( 'woodoo_ssl_verify', true ),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( is_wp_error( $auth_response ) ) {
|
|
||||||
wp_die( esc_html__( 'Could not authenticate with Odoo.', 'woodoo' ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract session cookie
|
|
||||||
$raw_headers = wp_remote_retrieve_headers( $auth_response );
|
|
||||||
$session_cookie = '';
|
|
||||||
if ( isset( $raw_headers['set-cookie'] ) ) {
|
|
||||||
$cookie_header = is_array( $raw_headers['set-cookie'] )
|
|
||||||
? $raw_headers['set-cookie'][0]
|
|
||||||
: $raw_headers['set-cookie'];
|
|
||||||
preg_match( '/session_id=([^;]+)/', $cookie_header, $m );
|
|
||||||
if ( isset( $m[1] ) ) $session_cookie = 'session_id=' . $m[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
$pdf_response = wp_remote_get(
|
$pdf_response = wp_remote_get(
|
||||||
$pdf_url,
|
$pdf_url,
|
||||||
[
|
[
|
||||||
'headers' => $session_cookie ? [ 'Cookie' => $session_cookie ] : [],
|
'headers' => [ 'Authorization' => $basic_auth ],
|
||||||
'timeout' => 60,
|
'timeout' => 90,
|
||||||
'sslverify' => apply_filters( 'woodoo_ssl_verify', true ),
|
'sslverify' => apply_filters( 'woodoo_ssl_verify', true ),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( is_wp_error( $pdf_response ) ) {
|
if ( is_wp_error( $pdf_response ) ) {
|
||||||
wp_die( esc_html__( 'Could not retrieve invoice PDF.', 'woodoo' ) );
|
wp_die( 'No se pudo obtener el PDF de la factura: ' . esc_html( $pdf_response->get_error_message() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$http_code = wp_remote_retrieve_response_code( $pdf_response );
|
||||||
$pdf_body = wp_remote_retrieve_body( $pdf_response );
|
$pdf_body = wp_remote_retrieve_body( $pdf_response );
|
||||||
|
|
||||||
|
// Guard: Odoo may return a JSON error or HTML login page instead of a PDF
|
||||||
|
if ( $http_code !== 200 || substr( $pdf_body, 0, 4 ) !== '%PDF' ) {
|
||||||
|
wp_die( 'No se pudo generar el PDF. Código HTTP: ' . esc_html( $http_code ) . '. Comprueba los permisos del usuario de la API en Odoo.' );
|
||||||
|
}
|
||||||
|
|
||||||
header( 'Content-Type: application/pdf' );
|
header( 'Content-Type: application/pdf' );
|
||||||
header( 'Content-Disposition: attachment; filename="invoice-' . $invoice_id . '.pdf"' );
|
header( 'Content-Disposition: attachment; filename="factura-' . $invoice_id . '.pdf"' );
|
||||||
header( 'Content-Length: ' . strlen( $pdf_body ) );
|
header( 'Content-Length: ' . strlen( $pdf_body ) );
|
||||||
|
header( 'Cache-Control: private' );
|
||||||
|
|
||||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
echo $pdf_body;
|
echo $pdf_body;
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Helper ────────────────────────────────────────────────────────────
|
// ── Helpers ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
public static function payment_state_label( string $state ): string {
|
public static function payment_state_label( string $state ): string {
|
||||||
$labels = [
|
$labels = [
|
||||||
'not_paid' => __( 'Unpaid', 'woodoo' ),
|
'not_paid' => 'Pendiente',
|
||||||
'partial' => __( 'Partial', 'woodoo' ),
|
'partial' => 'Parcial',
|
||||||
'in_payment'=> __( 'In Payment', 'woodoo' ),
|
'in_payment' => 'En cobro',
|
||||||
'paid' => __( 'Paid', 'woodoo' ),
|
'paid' => 'Pagado',
|
||||||
'reversed' => __( 'Reversed', 'woodoo' ),
|
'reversed' => 'Anulado',
|
||||||
];
|
];
|
||||||
return $labels[ $state ] ?? ucfirst( $state );
|
return $labels[ $state ] ?? ucfirst( $state );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an Odoo currency name (e.g. "EUR") to its symbol ("€").
|
||||||
|
* Falls back to the original string if not in the map.
|
||||||
|
*/
|
||||||
|
public static function currency_symbol( string $currency_name ): string {
|
||||||
|
$map = [
|
||||||
|
'EUR' => '€',
|
||||||
|
'USD' => '$',
|
||||||
|
'GBP' => '£',
|
||||||
|
'JPY' => '¥',
|
||||||
|
'CHF' => 'Fr',
|
||||||
|
'MXN' => '$',
|
||||||
|
'BRL' => 'R$',
|
||||||
|
'ARS' => '$',
|
||||||
|
'CLP' => '$',
|
||||||
|
'COP' => '$',
|
||||||
|
'PEN' => 'S/',
|
||||||
|
'DKK' => 'kr',
|
||||||
|
'SEK' => 'kr',
|
||||||
|
'NOK' => 'kr',
|
||||||
|
'PLN' => 'zł',
|
||||||
|
'CZK' => 'Kč',
|
||||||
|
'HUF' => 'Ft',
|
||||||
|
'RON' => 'lei',
|
||||||
|
'BGN' => 'лв',
|
||||||
|
'HRK' => 'kn',
|
||||||
|
'RUB' => '₽',
|
||||||
|
'TRY' => '₺',
|
||||||
|
'CNY' => '¥',
|
||||||
|
'KRW' => '₩',
|
||||||
|
'INR' => '₹',
|
||||||
|
'AED' => 'د.إ',
|
||||||
|
'MAD' => 'MAD',
|
||||||
|
];
|
||||||
|
return $map[ strtoupper( $currency_name ) ] ?? $currency_name;
|
||||||
|
}
|
||||||
|
|
||||||
public static function payment_state_class( string $state ): string {
|
public static function payment_state_class( string $state ): string {
|
||||||
return match ( $state ) {
|
return match ( $state ) {
|
||||||
'paid' => 'woodoo-badge--green',
|
'paid' => 'woodoo-badge--green',
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Template: My Account – Book a Meeting
|
* Template: Mi cuenta – Reservar una reunión
|
||||||
*
|
|
||||||
* Variables available:
|
|
||||||
* $upcoming array Upcoming booked meetings from Odoo
|
|
||||||
* $partner_id int Odoo partner ID (0 if unlinked)
|
|
||||||
* $user WP_User Current user
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
@@ -16,51 +11,54 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
|
|||||||
'nonce' => wp_create_nonce( 'woodoo_calendar' ),
|
'nonce' => wp_create_nonce( 'woodoo_calendar' ),
|
||||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||||
'i18n' => [
|
'i18n' => [
|
||||||
'loading' => __( 'Loading…', 'woodoo' ),
|
'loading' => 'Cargando…',
|
||||||
'no_slots' => __( 'No available slots for this day.', 'woodoo' ),
|
'no_slots' => 'No hay horarios disponibles para este día.',
|
||||||
'select_slot' => __( 'Select a time slot', 'woodoo' ),
|
'select_slot' => 'Selecciona un horario',
|
||||||
'booking' => __( 'Booking…', 'woodoo' ),
|
'booking' => 'Reservando…',
|
||||||
'book_btn' => __( 'Book this slot', 'woodoo' ),
|
'book_btn' => 'Confirmar reserva',
|
||||||
'cancel_confirm' => __( 'Cancel this meeting?', 'woodoo' ),
|
'cancel_confirm' => '¿Cancelar esta reunión?',
|
||||||
'cancelling' => __( 'Cancelling…', 'woodoo' ),
|
'cancelling' => 'Cancelando…',
|
||||||
'cancelled' => __( 'Meeting cancelled.', 'woodoo' ),
|
'cancelled' => 'Reunión cancelada.',
|
||||||
'error' => __( 'Something went wrong. Please try again.', 'woodoo' ),
|
'error' => 'Ha ocurrido un error. Inténtalo de nuevo.',
|
||||||
],
|
],
|
||||||
] );
|
] );
|
||||||
|
|
||||||
|
$duration_mins = (int) get_option( 'woodoo_meeting_duration', 30 );
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="woodoo-calendar-wrap">
|
<div class="woodoo-calendar-wrap">
|
||||||
|
|
||||||
<!-- ── Upcoming Meetings ──────────────────────────────────────────── -->
|
<!-- ── Próximas reuniones ─────────────────────────────────────────── -->
|
||||||
<div class="woodoo-section">
|
<div class="woodoo-section">
|
||||||
<h3><?php esc_html_e( 'Your Upcoming Meetings', 'woodoo' ); ?></h3>
|
<h3>Tus próximas reuniones</h3>
|
||||||
<div id="woodoo-meetings-list">
|
<div id="woodoo-meetings-list">
|
||||||
<?php if ( empty( $upcoming ) ) : ?>
|
<?php if ( empty( $upcoming ) ) : ?>
|
||||||
<p class="woodoo-empty"><?php esc_html_e( 'No upcoming meetings scheduled.', 'woodoo' ); ?></p>
|
<p class="woodoo-empty">No tienes reuniones programadas.</p>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<div class="woodoo-meetings-grid">
|
<div class="woodoo-meetings-grid">
|
||||||
<?php foreach ( $upcoming as $event ) :
|
<?php foreach ( $upcoming as $event ) :
|
||||||
$start_ts = strtotime( $event['start'] );
|
$start_ts = strtotime( $event['start'] );
|
||||||
$end_ts = strtotime( $event['stop'] );
|
$end_ts = strtotime( $event['stop'] );
|
||||||
|
|
||||||
|
$meses = [ '', 'ene', 'feb', 'mar', 'abr', 'may', 'jun',
|
||||||
|
'jul', 'ago', 'sep', 'oct', 'nov', 'dic' ];
|
||||||
|
$mes = $meses[ (int) gmdate( 'n', $start_ts ) ];
|
||||||
?>
|
?>
|
||||||
<div class="woodoo-meeting-card" data-event-id="<?php echo esc_attr( $event['id'] ); ?>">
|
<div class="woodoo-meeting-card" data-event-id="<?php echo esc_attr( $event['id'] ); ?>">
|
||||||
<div class="woodoo-meeting-card__date">
|
<div class="woodoo-meeting-card__date">
|
||||||
<span class="woodoo-meeting-card__day"><?php echo esc_html( gmdate( 'd', $start_ts ) ); ?></span>
|
<span class="woodoo-meeting-card__day"><?php echo esc_html( gmdate( 'd', $start_ts ) ); ?></span>
|
||||||
<span class="woodoo-meeting-card__month"><?php echo esc_html( gmdate( 'M', $start_ts ) ); ?></span>
|
<span class="woodoo-meeting-card__month"><?php echo esc_html( $mes ); ?></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="woodoo-meeting-card__info">
|
<div class="woodoo-meeting-card__info">
|
||||||
<strong><?php echo esc_html( $event['name'] ); ?></strong>
|
<strong><?php echo esc_html( $event['name'] ); ?></strong>
|
||||||
<span class="woodoo-meeting-card__time">
|
<span class="woodoo-meeting-card__time">
|
||||||
<?php printf(
|
<?php echo esc_html( gmdate( 'H:i', $start_ts ) . ' – ' . gmdate( 'H:i', $end_ts ) ); ?>
|
||||||
'%s – %s',
|
|
||||||
esc_html( gmdate( 'H:i', $start_ts ) ),
|
|
||||||
esc_html( gmdate( 'H:i', $end_ts ) )
|
|
||||||
); ?>
|
|
||||||
</span>
|
</span>
|
||||||
<?php if ( ! empty( $event['videocall_location'] ) ) : ?>
|
<?php if ( ! empty( $event['videocall_location'] ) ) : ?>
|
||||||
<a href="<?php echo esc_url( $event['videocall_location'] ); ?>"
|
<a href="<?php echo esc_url( $event['videocall_location'] ); ?>"
|
||||||
target="_blank" rel="noopener" class="woodoo-meeting-card__video">
|
target="_blank" rel="noopener"
|
||||||
<?php esc_html_e( 'Join Video Call', 'woodoo' ); ?>
|
class="woodoo-meeting-card__video">
|
||||||
|
Unirse a la videollamada
|
||||||
</a>
|
</a>
|
||||||
<?php elseif ( ! empty( $event['location'] ) ) : ?>
|
<?php elseif ( ! empty( $event['location'] ) ) : ?>
|
||||||
<span class="woodoo-meeting-card__loc">
|
<span class="woodoo-meeting-card__loc">
|
||||||
@@ -71,7 +69,7 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
|
|||||||
<div class="woodoo-meeting-card__actions">
|
<div class="woodoo-meeting-card__actions">
|
||||||
<button class="woodoo-cancel-meeting woodoo-btn woodoo-btn--sm woodoo-btn--outline"
|
<button class="woodoo-cancel-meeting woodoo-btn woodoo-btn--sm woodoo-btn--outline"
|
||||||
data-event-id="<?php echo esc_attr( $event['id'] ); ?>">
|
data-event-id="<?php echo esc_attr( $event['id'] ); ?>">
|
||||||
<?php esc_html_e( 'Cancel', 'woodoo' ); ?>
|
Cancelar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -81,23 +79,18 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ── Book New Meeting ───────────────────────────────────────────── -->
|
<!-- ── Reservar nueva reunión ─────────────────────────────────────── -->
|
||||||
<div class="woodoo-section">
|
<div class="woodoo-section">
|
||||||
<h3><?php esc_html_e( 'Book a New Meeting', 'woodoo' ); ?></h3>
|
<h3>Reservar una nueva reunión</h3>
|
||||||
<p class="woodoo-desc">
|
<p class="woodoo-desc">
|
||||||
<?php printf(
|
Las reuniones tienen una duración de <?php echo esc_html( $duration_mins ); ?> minutos.
|
||||||
esc_html__( 'Slots are %d minutes. Pick a date to see availability.', 'woodoo' ),
|
Selecciona una fecha para ver la disponibilidad.
|
||||||
(int) get_option( 'woodoo_meeting_duration', 30 )
|
|
||||||
); ?>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="woodoo-booking-form">
|
<div class="woodoo-booking-form">
|
||||||
|
|
||||||
<!-- Date picker -->
|
|
||||||
<div class="woodoo-field">
|
<div class="woodoo-field">
|
||||||
<label for="woodoo-booking-date">
|
<label for="woodoo-booking-date">Selecciona una fecha</label>
|
||||||
<?php esc_html_e( 'Select Date', 'woodoo' ); ?>
|
|
||||||
</label>
|
|
||||||
<input type="date"
|
<input type="date"
|
||||||
id="woodoo-booking-date"
|
id="woodoo-booking-date"
|
||||||
name="booking_date"
|
name="booking_date"
|
||||||
@@ -105,40 +98,31 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
|
|||||||
max="<?php echo esc_attr( gmdate( 'Y-m-d', strtotime( '+60 days' ) ) ); ?>">
|
max="<?php echo esc_attr( gmdate( 'Y-m-d', strtotime( '+60 days' ) ) ); ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Slot list (populated via JS) -->
|
|
||||||
<div id="woodoo-slots-wrap" style="display:none;">
|
<div id="woodoo-slots-wrap" style="display:none;">
|
||||||
<div class="woodoo-field">
|
<div class="woodoo-field">
|
||||||
<label><?php esc_html_e( 'Available Slots', 'woodoo' ); ?></label>
|
<label>Horarios disponibles</label>
|
||||||
<div id="woodoo-slots-grid" class="woodoo-slots-grid">
|
<div id="woodoo-slots-grid" class="woodoo-slots-grid"></div>
|
||||||
<!-- Slots injected by JS -->
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Booking confirmation -->
|
|
||||||
<div id="woodoo-booking-confirm" style="display:none;">
|
<div id="woodoo-booking-confirm" style="display:none;">
|
||||||
<div class="woodoo-field">
|
<div class="woodoo-field">
|
||||||
<label for="woodoo-booking-notes">
|
<label for="woodoo-booking-notes">Notas (opcional)</label>
|
||||||
<?php esc_html_e( 'Notes (optional)', 'woodoo' ); ?>
|
|
||||||
</label>
|
|
||||||
<textarea id="woodoo-booking-notes" name="notes" rows="3"
|
<textarea id="woodoo-booking-notes" name="notes" rows="3"
|
||||||
placeholder="<?php esc_attr_e( 'What would you like to discuss?', 'woodoo' ); ?>"></textarea>
|
placeholder="¿De qué te gustaría hablar?"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="woodoo-selected-slot-display">
|
<div class="woodoo-selected-slot-display">
|
||||||
<strong><?php esc_html_e( 'Selected:', 'woodoo' ); ?></strong>
|
<strong>Seleccionado:</strong>
|
||||||
<span id="woodoo-selected-slot-label"></span>
|
<span id="woodoo-selected-slot-label"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="woodoo-book-btn" class="woodoo-btn woodoo-btn--primary" disabled>
|
<button id="woodoo-book-btn" class="woodoo-btn woodoo-btn--primary" disabled>
|
||||||
<?php esc_html_e( 'Confirm Booking', 'woodoo' ); ?>
|
Confirmar reserva
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Success message -->
|
|
||||||
<div id="woodoo-booking-success" class="woodoo-notice woodoo-success" style="display:none;"></div>
|
<div id="woodoo-booking-success" class="woodoo-notice woodoo-success" style="display:none;"></div>
|
||||||
|
|
||||||
<!-- Error message -->
|
|
||||||
<div id="woodoo-booking-error" class="woodoo-notice woodoo-error" style="display:none;"></div>
|
<div id="woodoo-booking-error" class="woodoo-notice woodoo-error" style="display:none;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,46 +1,45 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Template: My Account – Odoo Invoices
|
* Template: Mi cuenta – Facturas de Odoo
|
||||||
*
|
*
|
||||||
* Variables available:
|
* Variables disponibles:
|
||||||
* $invoices array List of invoice records from Odoo
|
* $invoices array Lista de facturas desde Odoo
|
||||||
* $total int Total invoice count
|
* $total int Total de facturas
|
||||||
* $paged int Current page
|
* $paged int Página actual
|
||||||
* $num_pages int Total pages
|
* $num_pages int Total de páginas
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
|
||||||
// Enqueue frontend assets
|
|
||||||
wp_enqueue_style( 'woodoo-frontend' );
|
wp_enqueue_style( 'woodoo-frontend' );
|
||||||
wp_enqueue_script( 'woodoo-frontend' );
|
wp_enqueue_script( 'woodoo-frontend' );
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="woodoo-invoices">
|
<div class="woodoo-invoices">
|
||||||
<h3><?php esc_html_e( 'Your Invoices', 'woodoo' ); ?></h3>
|
<h3>Tus Facturas</h3>
|
||||||
|
|
||||||
<?php if ( empty( $invoices ) ) : ?>
|
<?php if ( empty( $invoices ) ) : ?>
|
||||||
<p class="woodoo-empty">
|
<p class="woodoo-empty">No se han encontrado facturas.</p>
|
||||||
<?php esc_html_e( 'No invoices found.', 'woodoo' ); ?>
|
|
||||||
</p>
|
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
|
|
||||||
<div class="woodoo-table-wrap">
|
<div class="woodoo-table-wrap">
|
||||||
<table class="woodoo-table">
|
<table class="woodoo-table woodoo-invoices-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><?php esc_html_e( 'Invoice #', 'woodoo' ); ?></th>
|
<th class="col-number">Nº Factura</th>
|
||||||
<th><?php esc_html_e( 'Date', 'woodoo' ); ?></th>
|
<th class="col-date">Fecha</th>
|
||||||
<th><?php esc_html_e( 'Due Date', 'woodoo' ); ?></th>
|
<th class="col-due">Vencimiento</th>
|
||||||
<th><?php esc_html_e( 'Total', 'woodoo' ); ?></th>
|
<th class="col-amount">Total</th>
|
||||||
<th><?php esc_html_e( 'Balance Due', 'woodoo' ); ?></th>
|
<th class="col-balance">Saldo pendiente</th>
|
||||||
<th><?php esc_html_e( 'Status', 'woodoo' ); ?></th>
|
<th class="col-status">Estado</th>
|
||||||
<th><?php esc_html_e( 'Download', 'woodoo' ); ?></th>
|
<th class="col-download">PDF</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ( $invoices as $inv ) :
|
<?php foreach ( $invoices as $inv ) :
|
||||||
$currency = is_array( $inv['currency_id'] ) ? $inv['currency_id'][1] : '';
|
$currency_name = is_array( $inv['currency_id'] ) ? $inv['currency_id'][1] : '';
|
||||||
|
$currency = WooDoo_Invoices::currency_symbol( $currency_name );
|
||||||
$pay_state = $inv['payment_state'] ?? 'not_paid';
|
$pay_state = $inv['payment_state'] ?? 'not_paid';
|
||||||
$badge_class = WooDoo_Invoices::payment_state_class( $pay_state );
|
$badge_class = WooDoo_Invoices::payment_state_class( $pay_state );
|
||||||
$badge_label = WooDoo_Invoices::payment_state_label( $pay_state );
|
$badge_label = WooDoo_Invoices::payment_state_label( $pay_state );
|
||||||
@@ -51,46 +50,49 @@ wp_enqueue_script( 'woodoo-frontend' );
|
|||||||
], admin_url( 'admin-ajax.php' ) );
|
], admin_url( 'admin-ajax.php' ) );
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="woodoo-inv-number">
|
<td class="col-number woodoo-inv-number">
|
||||||
<?php echo esc_html( $inv['name'] ?: "INV-{$inv['id']}" ); ?>
|
<?php echo esc_html( $inv['name'] ?: 'FAC-' . $inv['id'] ); ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="col-date woodoo-nowrap">
|
||||||
<?php echo $inv['invoice_date']
|
<?php echo $inv['invoice_date']
|
||||||
? esc_html( date_i18n( get_option( 'date_format' ), strtotime( $inv['invoice_date'] ) ) )
|
? esc_html( date_i18n( 'd/m/Y', strtotime( $inv['invoice_date'] ) ) )
|
||||||
: '—'; ?>
|
: '—'; ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="col-due woodoo-nowrap">
|
||||||
<?php
|
<?php
|
||||||
if ( $inv['invoice_date_due'] ) {
|
if ( $inv['invoice_date_due'] ) {
|
||||||
$due_ts = strtotime( $inv['invoice_date_due'] );
|
$due_ts = strtotime( $inv['invoice_date_due'] );
|
||||||
$overdue = $pay_state === 'not_paid' && $due_ts < time();
|
$overdue = ( $pay_state === 'not_paid' || $pay_state === 'partial' ) && $due_ts < time();
|
||||||
$class = $overdue ? ' class="woodoo-overdue"' : '';
|
if ( $overdue ) {
|
||||||
echo '<span' . $class . '>' . // phpcs:ignore WordPress.Security.EscapeOutput
|
echo '<span class="woodoo-overdue">';
|
||||||
esc_html( date_i18n( get_option( 'date_format' ), $due_ts ) ) .
|
echo esc_html( date_i18n( 'd/m/Y', $due_ts ) );
|
||||||
'</span>';
|
echo '</span> <span class="woodoo-badge woodoo-badge--red">Vencida</span>';
|
||||||
if ( $overdue ) echo ' <span class="woodoo-badge woodoo-badge--red">' . esc_html__( 'Overdue', 'woodoo' ) . '</span>';
|
} else {
|
||||||
|
echo esc_html( date_i18n( 'd/m/Y', $due_ts ) );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
echo '—';
|
echo '—';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</td>
|
</td>
|
||||||
<td class="woodoo-amount">
|
<td class="col-amount woodoo-amount woodoo-nowrap">
|
||||||
<?php echo esc_html( number_format_i18n( $inv['amount_total'], 2 ) . ' ' . $currency ); ?>
|
<?php echo esc_html( number_format( (float) $inv['amount_total'], 2, ',', '.' ) . ' ' . $currency ); ?>
|
||||||
</td>
|
</td>
|
||||||
<td class="woodoo-amount">
|
<td class="col-balance woodoo-amount woodoo-nowrap">
|
||||||
<?php echo esc_html( number_format_i18n( $inv['amount_residual'], 2 ) . ' ' . $currency ); ?>
|
<?php echo esc_html( number_format( (float) $inv['amount_residual'], 2, ',', '.' ) . ' ' . $currency ); ?>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="col-status woodoo-nowrap">
|
||||||
<span class="woodoo-badge <?php echo esc_attr( $badge_class ); ?>">
|
<span class="woodoo-badge <?php echo esc_attr( $badge_class ); ?>">
|
||||||
<?php echo esc_html( $badge_label ); ?>
|
<?php echo esc_html( $badge_label ); ?>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="col-download">
|
||||||
<a href="<?php echo esc_url( $pdf_url ); ?>"
|
<a href="<?php echo esc_url( $pdf_url ); ?>"
|
||||||
class="woodoo-btn woodoo-btn--sm"
|
class="woodoo-btn woodoo-btn--sm"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener">
|
rel="noopener"
|
||||||
<?php esc_html_e( 'PDF', 'woodoo' ); ?>
|
title="Descargar factura en PDF">
|
||||||
|
↓ PDF
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -102,7 +104,7 @@ wp_enqueue_script( 'woodoo-frontend' );
|
|||||||
<?php if ( $num_pages > 1 ) :
|
<?php if ( $num_pages > 1 ) :
|
||||||
$base_url = wc_get_account_endpoint_url( WooDoo_Invoices::ENDPOINT );
|
$base_url = wc_get_account_endpoint_url( WooDoo_Invoices::ENDPOINT );
|
||||||
?>
|
?>
|
||||||
<nav class="woodoo-pagination">
|
<nav class="woodoo-pagination" aria-label="Paginación de facturas">
|
||||||
<?php for ( $p = 1; $p <= $num_pages; $p++ ) : ?>
|
<?php for ( $p = 1; $p <= $num_pages; $p++ ) : ?>
|
||||||
<?php if ( $p === $paged ) : ?>
|
<?php if ( $p === $paged ) : ?>
|
||||||
<span class="woodoo-page-current"><?php echo esc_html( $p ); ?></span>
|
<span class="woodoo-page-current"><?php echo esc_html( $p ); ?></span>
|
||||||
|
|||||||
Reference in New Issue
Block a user