$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 '
' . 'Tu cuenta aún no está vinculada a Odoo. Por favor, contáctanos para activar esta funcionalidad.' . '
'; return; } $api = woodoo_api(); if ( ! $api ) { echo '' . 'La integración con Odoo no está configurada. Contacta con soporte.' . '
'; 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'; } // ── Send Invoice by Email ───────────────────────────────────────────── /** * Ask Odoo to resend the invoice email to the customer. * Uses mail.template.send_mail() with the standard invoice email template. */ public static function ajax_send_invoice_email(): void { check_ajax_referer( 'woodoo_invoice_email', 'nonce' ); if ( ! is_user_logged_in() ) { wp_send_json_error( 'No autenticado.', 401 ); } $invoice_id = absint( $_POST['invoice_id'] ?? 0 ); if ( ! $invoice_id ) { wp_send_json_error( 'ID de factura no válido.' ); } $user_id = get_current_user_id(); $partner_id = (int) get_user_meta( $user_id, 'woodoo_odoo_partner_id', true ); if ( ! $partner_id ) { wp_send_json_error( 'Tu cuenta no está vinculada a Odoo.' ); } $api = woodoo_api(); if ( ! $api ) { wp_send_json_error( 'Integración con Odoo no configurada.' ); } // Verify invoice belongs to this customer $invoices = $api->search( 'account.move', [ [ 'id', '=', $invoice_id ], [ 'partner_id', '=', $partner_id ] ], 1 ); if ( empty( $invoices ) ) { wp_send_json_error( 'Factura no encontrada.' ); } // Find the Odoo invoice email template ID (cached 24h) $template_id = (int) get_transient( 'woodoo_invoice_tpl_id' ); if ( ! $template_id ) { $ref = $api->search_read( 'ir.model.data', [ [ 'module', '=', 'account' ], [ 'name', '=', 'email_template_edi_invoice' ], ], [ 'res_id' ], 1 ); $template_id = ! empty( $ref ) ? (int) $ref[0]['res_id'] : 0; if ( ! $template_id ) { // Fallback: search templates by model $tpl = $api->search_read( 'mail.template', [ [ 'model', '=', 'account.move' ] ], [ 'id', 'name' ], 1 ); $template_id = ! empty( $tpl ) ? (int) $tpl[0]['id'] : 0; } if ( $template_id ) { set_transient( 'woodoo_invoice_tpl_id', $template_id, DAY_IN_SECONDS ); } } if ( ! $template_id ) { wp_send_json_error( 'No se encontró la plantilla de correo de facturas en Odoo.' ); } // Call mail.template.send_mail([template_id], invoice_id, force_send=True) // First arg list [[template_id]] is the recordset selector in execute_kw, // remaining positional args are passed to the method itself. $result = $api->execute_kw( 'mail.template', 'send_mail', [ [ $template_id ], $invoice_id ], [ 'force_send' => true ] ); if ( is_wp_error( $result ) ) { wp_send_json_error( 'Error de Odoo: ' . $result->get_error_message() ); } wp_send_json_success( [ 'message' => 'La factura ha sido enviada a tu correo electrónico.', ] ); } // ── 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', }; } }