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:
@@ -41,7 +41,7 @@ class WooDoo_Calendar {
|
||||
$api = woodoo_api();
|
||||
if ( ! $api ) {
|
||||
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>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ class WooDoo_Invoices {
|
||||
$partner_id = (int) get_user_meta( $user_id, 'woodoo_odoo_partner_id', true );
|
||||
|
||||
if ( ! $partner_id ) {
|
||||
echo '<p class="woodoo-notice">' .
|
||||
esc_html__( 'Your account is not yet linked to Odoo. Please contact us.', 'woodoo' ) .
|
||||
echo '<p class="woodoo-notice woodoo-error">' .
|
||||
'Tu cuenta aún no está vinculada a Odoo. Por favor, contáctanos para activar esta funcionalidad.' .
|
||||
'</p>';
|
||||
return;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ class WooDoo_Invoices {
|
||||
$api = woodoo_api();
|
||||
if ( ! $api ) {
|
||||
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>';
|
||||
return;
|
||||
}
|
||||
@@ -131,82 +131,95 @@ class WooDoo_Invoices {
|
||||
wp_die( esc_html__( 'Invoice not found.', 'woodoo' ) );
|
||||
}
|
||||
|
||||
// Fetch the PDF report from Odoo
|
||||
$odoo_url = rtrim( get_option( 'woodoo_odoo_url', '' ), '/' );
|
||||
$pdf_url = $odoo_url . '/report/pdf/account.report_invoice/' . $invoice_id;
|
||||
|
||||
// Build auth cookie by first doing session authenticate
|
||||
$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 ),
|
||||
]
|
||||
// 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', '' ), '/' );
|
||||
$pdf_url = $odoo_url . '/report/pdf/account.report_invoice/' . $invoice_id;
|
||||
$basic_auth = 'Basic ' . base64_encode(
|
||||
get_option( 'woodoo_odoo_username', '' ) . ':' . get_option( 'woodoo_odoo_api_key', '' )
|
||||
);
|
||||
|
||||
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_url,
|
||||
[
|
||||
'headers' => $session_cookie ? [ 'Cookie' => $session_cookie ] : [],
|
||||
'timeout' => 60,
|
||||
'headers' => [ 'Authorization' => $basic_auth ],
|
||||
'timeout' => 90,
|
||||
'sslverify' => apply_filters( 'woodoo_ssl_verify', true ),
|
||||
]
|
||||
);
|
||||
|
||||
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() ) );
|
||||
}
|
||||
|
||||
$pdf_body = wp_remote_retrieve_body( $pdf_response );
|
||||
$http_code = wp_remote_retrieve_response_code( $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-Disposition: attachment; filename="invoice-' . $invoice_id . '.pdf"' );
|
||||
header( 'Content-Disposition: attachment; filename="factura-' . $invoice_id . '.pdf"' );
|
||||
header( 'Content-Length: ' . strlen( $pdf_body ) );
|
||||
header( 'Cache-Control: private' );
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $pdf_body;
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── Helper ────────────────────────────────────────────────────────────
|
||||
// ── Helpers ───────────────────────────────────────────────────────────
|
||||
|
||||
public static function payment_state_label( string $state ): string {
|
||||
$labels = [
|
||||
'not_paid' => __( 'Unpaid', 'woodoo' ),
|
||||
'partial' => __( 'Partial', 'woodoo' ),
|
||||
'in_payment'=> __( 'In Payment', 'woodoo' ),
|
||||
'paid' => __( 'Paid', 'woodoo' ),
|
||||
'reversed' => __( 'Reversed', 'woodoo' ),
|
||||
'not_paid' => 'Pendiente',
|
||||
'partial' => 'Parcial',
|
||||
'in_payment' => 'En cobro',
|
||||
'paid' => 'Pagado',
|
||||
'reversed' => 'Anulado',
|
||||
];
|
||||
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 {
|
||||
return match ( $state ) {
|
||||
'paid' => 'woodoo-badge--green',
|
||||
|
||||
Reference in New Issue
Block a user