Files
WooDoo/includes/class-woodoo-invoices.php
Malin d1597731c5 fix: translate My Account menu items to Spanish
- "Odoo Invoices" → "Mis Facturas"
- "Book a Meeting" → "Reservar Reunión"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 17:35:15 +02:00

230 lines
8.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* My Account Invoices tab.
* Shows the customer's Odoo invoices and handles PDF proxy-download.
*/
defined( 'ABSPATH' ) || exit;
class WooDoo_Invoices {
const ENDPOINT = 'odoo-invoices';
public static function init(): void {
add_filter( 'woocommerce_account_menu_items', [ __CLASS__, 'add_menu_item' ], 20 );
add_action( 'woocommerce_account_' . self::ENDPOINT . '_endpoint', [ __CLASS__, 'render' ] );
add_filter( 'woocommerce_get_query_vars', [ __CLASS__, 'add_query_var' ] );
// PDF download endpoint
add_action( 'wp_ajax_woodoo_invoice_pdf', [ __CLASS__, 'ajax_download_pdf' ] );
add_action( 'wp_ajax_nopriv_woodoo_invoice_pdf', [ __CLASS__, 'ajax_download_pdf' ] );
}
public static function add_query_var( array $vars ): array {
$vars[ self::ENDPOINT ] = self::ENDPOINT;
return $vars;
}
public static function add_menu_item( array $items ): array {
$new = [];
foreach ( $items as $key => $label ) {
$new[ $key ] = $label;
if ( $key === 'orders' ) {
$new[ self::ENDPOINT ] = 'Mis Facturas';
}
}
return $new;
}
// ── Render ────────────────────────────────────────────────────────────
public static function render(): void {
$user_id = get_current_user_id();
$partner_id = (int) get_user_meta( $user_id, 'woodoo_odoo_partner_id', true );
if ( ! $partner_id ) {
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;
}
$api = woodoo_api();
if ( ! $api ) {
echo '<p class="woodoo-notice woodoo-error">' .
'La integración con Odoo no está configurada. Contacta con soporte.' .
'</p>';
return;
}
// Page parameter
$paged = max( 1, (int) ( $_GET['invoice_page'] ?? 1 ) ); // phpcs:ignore
$per_page = 10;
$offset = ( $paged - 1 ) * $per_page;
$domain = [
[ 'partner_id', '=', $partner_id ],
[ 'move_type', '=', 'out_invoice' ],
[ 'state', '!=', 'cancel' ],
];
$cache_key = 'woodoo_invoices_' . $partner_id . '_' . $paged;
$invoices = get_transient( $cache_key );
if ( false === $invoices ) {
$invoices = $api->search_read(
'account.move',
$domain,
[
'id', 'name', 'invoice_date', 'invoice_date_due',
'amount_total', 'amount_residual', 'payment_state',
'currency_id', 'state',
],
$per_page,
$offset,
'invoice_date desc'
);
set_transient( $cache_key, $invoices, 60 );
}
$total = $api->search_count( 'account.move', $domain );
$num_pages = (int) ceil( $total / $per_page );
include WOODOO_DIR . 'templates/myaccount-invoices.php';
}
// ── PDF Proxy ─────────────────────────────────────────────────────────
/**
* Download an invoice PDF from Odoo and serve it to the logged-in user.
* ?action=woodoo_invoice_pdf&invoice_id=123&nonce=...
*/
public static function ajax_download_pdf(): void {
$nonce = sanitize_text_field( wp_unslash( $_GET['nonce'] ?? '' ) );
if ( ! wp_verify_nonce( $nonce, 'woodoo_invoice_pdf' ) ) {
wp_die( esc_html__( 'Security check failed.', 'woodoo' ) );
}
if ( ! is_user_logged_in() ) {
wp_die( esc_html__( 'Please log in.', 'woodoo' ) );
}
$invoice_id = absint( $_GET['invoice_id'] ?? 0 );
if ( ! $invoice_id ) wp_die( 'Invalid invoice ID.' );
// Verify the invoice belongs to this user
$user_id = get_current_user_id();
$partner_id = (int) get_user_meta( $user_id, 'woodoo_odoo_partner_id', true );
if ( ! $partner_id ) wp_die( esc_html__( 'Account not linked.', 'woodoo' ) );
$api = woodoo_api();
if ( ! $api ) wp_die( 'API not configured.' );
$invoices = $api->search(
'account.move',
[ [ 'id', '=', $invoice_id ], [ 'partner_id', '=', $partner_id ] ],
1
);
if ( empty( $invoices ) ) {
wp_die( esc_html__( 'Invoice not found.', 'woodoo' ) );
}
// Use the authenticated JSON-RPC connection to render the PDF.
// Odoo's /report/pdf/ HTTP endpoint only accepts session cookies, not API keys.
// Calling ir.actions.report.render_qweb_pdf() via execute_kw works with any
// valid authenticated user and returns the PDF content base64-encoded.
$result = $api->execute_kw(
'ir.actions.report',
'render_qweb_pdf',
[ 'account.report_invoice', [ $invoice_id ] ]
);
if ( is_wp_error( $result ) ) {
wp_die( 'Error de Odoo al generar el PDF: ' . esc_html( $result->get_error_message() ) );
}
// Result is [base64_pdf_string, 'pdf']
$b64 = is_array( $result ) ? ( $result[0] ?? '' ) : $result;
if ( empty( $b64 ) ) {
wp_die( 'Odoo devolvió una respuesta vacía al generar el PDF.' );
}
$pdf_body = base64_decode( $b64, true );
if ( $pdf_body === false || substr( $pdf_body, 0, 4 ) !== '%PDF' ) {
wp_die( 'El contenido recibido de Odoo no es un PDF válido. Comprueba que el usuario de la API tenga permisos de impresión en Odoo.' );
}
header( 'Content-Type: application/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;
}
// ── Helpers ───────────────────────────────────────────────────────────
public static function payment_state_label( string $state ): string {
$labels = [
'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',
'not_paid' => 'woodoo-badge--red',
'partial' => 'woodoo-badge--orange',
'in_payment'=> 'woodoo-badge--blue',
default => 'woodoo-badge--grey',
};
}
}