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:
Malin
2026-04-01 17:30:10 +02:00
parent 38d1352e9a
commit 02c8fee174
5 changed files with 169 additions and 153 deletions

View File

@@ -1,11 +1,6 @@
<?php
/**
* Template: My Account Book a Meeting
*
* Variables available:
* $upcoming array Upcoming booked meetings from Odoo
* $partner_id int Odoo partner ID (0 if unlinked)
* $user WP_User Current user
* Template: Mi cuenta Reservar una reunión
*/
defined( 'ABSPATH' ) || exit;
@@ -16,51 +11,54 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
'nonce' => wp_create_nonce( 'woodoo_calendar' ),
'ajax_url' => admin_url( 'admin-ajax.php' ),
'i18n' => [
'loading' => __( 'Loading…', 'woodoo' ),
'no_slots' => __( 'No available slots for this day.', 'woodoo' ),
'select_slot' => __( 'Select a time slot', 'woodoo' ),
'booking' => __( 'Booking…', 'woodoo' ),
'book_btn' => __( 'Book this slot', 'woodoo' ),
'cancel_confirm' => __( 'Cancel this meeting?', 'woodoo' ),
'cancelling' => __( 'Cancelling…', 'woodoo' ),
'cancelled' => __( 'Meeting cancelled.', 'woodoo' ),
'error' => __( 'Something went wrong. Please try again.', 'woodoo' ),
'loading' => 'Cargando',
'no_slots' => 'No hay horarios disponibles para este día.',
'select_slot' => 'Selecciona un horario',
'booking' => 'Reservando',
'book_btn' => 'Confirmar reserva',
'cancel_confirm' => '¿Cancelar esta reunión?',
'cancelling' => 'Cancelando',
'cancelled' => 'Reunión cancelada.',
'error' => 'Ha ocurrido un error. Inténtalo de nuevo.',
],
] );
$duration_mins = (int) get_option( 'woodoo_meeting_duration', 30 );
?>
<div class="woodoo-calendar-wrap">
<!-- ── Upcoming Meetings ─────────────────────────────────────────── -->
<!-- ── Próximas reuniones ─────────────────────────────────────────── -->
<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">
<?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 : ?>
<div class="woodoo-meetings-grid">
<?php foreach ( $upcoming as $event ) :
$start_ts = strtotime( $event['start'] );
$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__date">
<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 class="woodoo-meeting-card__info">
<strong><?php echo esc_html( $event['name'] ); ?></strong>
<span class="woodoo-meeting-card__time">
<?php printf(
'%s %s',
esc_html( gmdate( 'H:i', $start_ts ) ),
esc_html( gmdate( 'H:i', $end_ts ) )
); ?>
<?php echo esc_html( gmdate( 'H:i', $start_ts ) . ' ' . gmdate( 'H:i', $end_ts ) ); ?>
</span>
<?php if ( ! empty( $event['videocall_location'] ) ) : ?>
<a href="<?php echo esc_url( $event['videocall_location'] ); ?>"
target="_blank" rel="noopener" class="woodoo-meeting-card__video">
<?php esc_html_e( 'Join Video Call', 'woodoo' ); ?>
target="_blank" rel="noopener"
class="woodoo-meeting-card__video">
Unirse a la videollamada
</a>
<?php elseif ( ! empty( $event['location'] ) ) : ?>
<span class="woodoo-meeting-card__loc">
@@ -71,7 +69,7 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
<div class="woodoo-meeting-card__actions">
<button class="woodoo-cancel-meeting woodoo-btn woodoo-btn--sm woodoo-btn--outline"
data-event-id="<?php echo esc_attr( $event['id'] ); ?>">
<?php esc_html_e( 'Cancel', 'woodoo' ); ?>
Cancelar
</button>
</div>
</div>
@@ -81,23 +79,18 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
</div>
</div>
<!-- ── Book New Meeting ───────────────────────────────────────────── -->
<!-- ── Reservar nueva reunión ─────────────────────────────────────── -->
<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">
<?php printf(
esc_html__( 'Slots are %d minutes. Pick a date to see availability.', 'woodoo' ),
(int) get_option( 'woodoo_meeting_duration', 30 )
); ?>
Las reuniones tienen una duración de <?php echo esc_html( $duration_mins ); ?> minutos.
Selecciona una fecha para ver la disponibilidad.
</p>
<div class="woodoo-booking-form">
<!-- Date picker -->
<div class="woodoo-field">
<label for="woodoo-booking-date">
<?php esc_html_e( 'Select Date', 'woodoo' ); ?>
</label>
<label for="woodoo-booking-date">Selecciona una fecha</label>
<input type="date"
id="woodoo-booking-date"
name="booking_date"
@@ -105,41 +98,32 @@ wp_localize_script( 'woodoo-frontend', 'WooDooCalendar', [
max="<?php echo esc_attr( gmdate( 'Y-m-d', strtotime( '+60 days' ) ) ); ?>">
</div>
<!-- Slot list (populated via JS) -->
<div id="woodoo-slots-wrap" style="display:none;">
<div class="woodoo-field">
<label><?php esc_html_e( 'Available Slots', 'woodoo' ); ?></label>
<div id="woodoo-slots-grid" class="woodoo-slots-grid">
<!-- Slots injected by JS -->
</div>
<label>Horarios disponibles</label>
<div id="woodoo-slots-grid" class="woodoo-slots-grid"></div>
</div>
</div>
<!-- Booking confirmation -->
<div id="woodoo-booking-confirm" style="display:none;">
<div class="woodoo-field">
<label for="woodoo-booking-notes">
<?php esc_html_e( 'Notes (optional)', 'woodoo' ); ?>
</label>
<label for="woodoo-booking-notes">Notas (opcional)</label>
<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 class="woodoo-selected-slot-display">
<strong><?php esc_html_e( 'Selected:', 'woodoo' ); ?></strong>
<strong>Seleccionado:</strong>
<span id="woodoo-selected-slot-label"></span>
</div>
<button id="woodoo-book-btn" class="woodoo-btn woodoo-btn--primary" disabled>
<?php esc_html_e( 'Confirm Booking', 'woodoo' ); ?>
Confirmar reserva
</button>
</div>
<!-- Success message -->
<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>