displayPremiumPopup(); return; } $page = $args['page'] ?? 'easy-invoice-reports'; // Get report data $report_data = $this->getReportData(); // Display the reports page $this->displayReportsPage( $report_data ); } /** * Display premium popup for reports feature */ private function displayPremiumPopup() { ?>

Detailed Reports

Unlock powerful insights into your business performance

Revenue analysis and trends
Payment statistics and status tracking
Monthly revenue charts and visualizations
Invoice status distribution analysis
Top clients and revenue analysis
Export reports to CSV, Excel, and PDF

Get comprehensive insights into your business with advanced reporting features

checkCapability(); if ( is_wp_error( $error ) ) { wp_die( $error ); } // Get date range filters $start_date = isset( $_GET['start_date'] ) ? sanitize_text_field( $_GET['start_date'] ) : date( 'Y-m-d', strtotime( '-30 days' ) ); $end_date = isset( $_GET['end_date'] ) ? sanitize_text_field( $_GET['end_date'] ) : date( 'Y-m-d' ); // Get repositories $invoice_repository = InvoiceServiceProvider::getInvoiceRepository(); $client_repository = ClientServiceProvider::getClientRepository(); // Get data for reports $summary_stats = $this->getSummaryStats( $invoice_repository, $client_repository, $start_date, $end_date ); $monthly_revenue = $this->getMonthlySummary( $invoice_repository, $start_date, $end_date ); $invoice_status = $this->getInvoiceStatusSummary( $invoice_repository, $start_date, $end_date ); $top_clients = $this->getTopClients( $invoice_repository, $client_repository ); // Generate payment and invoice reports $payment_report = $this->getPaymentReport( $start_date, $end_date ); $invoice_report = $this->getInvoiceReport( $start_date, $end_date ); // Prepare data for JavaScript $reports_data = array( 'monthly_revenue' => $monthly_revenue, 'invoice_status' => $invoice_status, 'payment_report' => $payment_report, 'invoice_report' => $invoice_report, 'start_date' => $start_date, 'end_date' => $end_date, 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'easy_invoice_reports_nonce' ) ); // Localize the script with data wp_localize_script( 'easy-invoice-reports', 'easy_invoice_reports', $reports_data ); // Display the template $this->displayTemplate( EASY_INVOICE_PLUGIN_DIR . 'templates/reports-page.php', [ 'start_date' => $start_date, 'end_date' => $end_date, 'summary_stats' => $summary_stats, 'monthly_revenue' => $monthly_revenue, 'invoice_status' => $invoice_status, 'top_clients' => $top_clients, 'payment_report' => $payment_report, 'invoice_report' => $invoice_report ] ); } /** * Get report data via AJAX * * @since 1.0.0 * @return void */ public function getReportData() { // Only handle AJAX requests if ( ! wp_doing_ajax() ) { return; } // Check nonce if ( ! isset( $_POST['nonce'] ) || ! $this->handleAjaxSecurity( $_POST['nonce'] ) ) { wp_send_json_error( array( 'message' => 'Security verification failed. Please refresh the page and try again.', 'code' => 'invalid_nonce' ) ); return; } $report_type = isset( $_POST['report_type'] ) ? sanitize_text_field( $_POST['report_type'] ) : ''; $start_date = isset( $_POST['start_date'] ) ? sanitize_text_field( $_POST['start_date'] ) : date( 'Y-m-d', strtotime( '-30 days' ) ); $end_date = isset( $_POST['end_date'] ) ? sanitize_text_field( $_POST['end_date'] ) : date( 'Y-m-d' ); // Get repositories $invoice_repository = InvoiceServiceProvider::getInvoiceRepository(); $client_repository = ClientServiceProvider::getClientRepository(); $response = array(); switch ( $report_type ) { case 'monthly_revenue': $response = $this->getMonthlySummary( $invoice_repository, $start_date, $end_date ); break; case 'invoice_status': $response = $this->getInvoiceStatusSummary( $invoice_repository, $start_date, $end_date ); break; case 'top_clients': $response = $this->getTopClients( $invoice_repository, $client_repository ); break; case 'summary_stats': $response = $this->getSummaryStats( $invoice_repository, $client_repository, $start_date, $end_date ); break; case 'payment_report': $response = $this->getPaymentReport( $start_date, $end_date ); break; case 'invoice_report': $response = $this->getInvoiceReport( $start_date, $end_date ); break; default: $response = array( 'error' => 'Invalid report type' ); break; } wp_send_json_success( $response ); } /** * Get summary statistics * * @since 1.0.0 * @param object $invoice_repository Invoice repository * @param object $client_repository Client repository * @param string $start_date Start date * @param string $end_date End date * @return array Summary statistics */ private function getSummaryStats( $invoice_repository, $client_repository, $start_date = '', $end_date = '' ) { try { // Get all invoices $all_invoices = $invoice_repository->all(); $paid_invoices = $invoice_repository->findByStatus( 'paid' ); // Calculate total revenue by currency $revenue_by_currency = []; // First, get all currencies that exist in the system $all_currencies = []; foreach ($all_invoices as $invoice) { $currency_code = $invoice->getCurrencyCode(); // If currency is empty or "global", get the actual currency that was used if (empty($currency_code) || $currency_code === 'global') { // Get the actual currency from invoice meta $actual_currency = get_post_meta($invoice->getId(), '_easy_invoice_currency_code', true); $currency_code = !empty($actual_currency) ? $actual_currency : get_option('easy_invoice_currency_code', 'USD'); } // If currency is still "global", use the global setting if ($currency_code === 'global') { $currency_code = get_option('easy_invoice_currency_code', 'USD'); } // Normalize currency code to uppercase for consistent grouping $currency_code = strtoupper($currency_code); if (!empty($currency_code)) { $all_currencies[$currency_code] = \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency_code); } } // Initialize revenue for all currencies found foreach ($all_currencies as $currency_code => $currency_symbol) { $revenue_by_currency[$currency_code] = [ 'amount' => 0, 'symbol' => $currency_symbol ]; } // Sum revenue from paid invoices foreach ($paid_invoices as $invoice) { $currency_code = $invoice->getCurrencyCode(); // If currency is empty or "global", get the actual currency that was used if (empty($currency_code) || $currency_code === 'global') { // Get the actual currency from invoice meta $actual_currency = get_post_meta($invoice->getId(), '_easy_invoice_currency_code', true); $currency_code = !empty($actual_currency) ? $actual_currency : get_option('easy_invoice_currency_code', 'USD'); } // If currency is still "global", use the global setting if ($currency_code === 'global') { $currency_code = get_option('easy_invoice_currency_code', 'USD'); } // Normalize currency code to uppercase for consistent grouping $currency_code = strtoupper($currency_code); if (!empty($currency_code)) { $amount = $invoice->getTotal(); if (!isset($revenue_by_currency[$currency_code])) { $revenue_by_currency[$currency_code] = [ 'amount' => 0, 'symbol' => \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency_code) ]; } $revenue_by_currency[$currency_code]['amount'] += $amount; } } // Get other statistics $total_invoices = count($all_invoices); $active_clients = count($client_repository->all()); $avg_payment_time = 30; // Default value, could be calculated from actual payment data return [ 'total_revenue' => $revenue_by_currency, 'total_invoices' => $total_invoices, 'active_clients' => $active_clients, 'avg_payment_time' => $avg_payment_time ]; } catch ( \Exception $e ) { return [ 'total_revenue' => [], 'total_invoices' => 0, 'active_clients' => 0, 'avg_payment_time' => 0 ]; } } /** * Get monthly summary data * * @since 1.0.0 * @param object $invoice_repository Invoice repository * @param string $start_date Optional start date * @param string $end_date Optional end date * @return array Monthly revenue data */ private function getMonthlySummary( $invoice_repository, $start_date = '', $end_date = '' ) { try { // Calculate date range for the last 12 months $current_date = new \DateTime(); $start_date = clone $current_date; $start_date->modify('-11 months'); $start_date->setTime(0, 0, 0); // Initialize monthly revenue array $monthly_revenue = []; // Initialize all months in the range for ($i = 0; $i < 12; $i++) { $month_date = clone $start_date; $month_date->modify("+$i months"); $month_key = $month_date->format('M Y'); $monthly_revenue[$month_key] = []; } // Query payments for the date range $payment_query = new \WP_Query([ 'post_type' => 'easy_invoice_payment', 'post_status' => 'publish', 'meta_query' => [ [ 'key' => '_status', 'value' => ['completed', 'approved', 'paid'], 'compare' => 'IN' ], [ 'key' => '_amount', 'value' => '0', 'compare' => '>' ] ], 'date_query' => [ [ 'after' => $start_date->format('Y-m-d'), 'inclusive' => true ] ], 'posts_per_page' => -1 ]); if ($payment_query->have_posts()) { while ($payment_query->have_posts()) { $payment_query->the_post(); $payment_id = get_the_ID(); $amount = floatval(get_post_meta($payment_id, '_amount', true)); $currency = get_post_meta($payment_id, '_currency', true); $payment_date = get_the_date('Y-m-d', $payment_id); // Handle "global" currency if (empty($currency) || $currency === 'global') { $currency = get_option('easy_invoice_currency_code', 'USD'); } // Normalize currency to uppercase $currency = strtoupper($currency); if ($amount > 0 && !empty($currency)) { $date_obj = new \DateTime($payment_date); $month_key = $date_obj->format('M Y'); if (!isset($monthly_revenue[$month_key][$currency])) { $monthly_revenue[$month_key][$currency] = [ 'amount' => 0, 'symbol' => \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency) ]; } $monthly_revenue[$month_key][$currency]['amount'] += $amount; } } wp_reset_postdata(); } return $monthly_revenue; } catch ( \Exception $e ) { return []; } } /** * Get invoice status summary * * @since 1.0.0 * @param object $invoice_repository Invoice repository * @param string $start_date Optional start date * @param string $end_date Optional end date * @return array Invoice status data */ private function getInvoiceStatusSummary( $invoice_repository, $start_date = '', $end_date = '' ) { try { // Get all invoices first $invoices = $invoice_repository->all(); // Filter by date range if provided if (!empty($start_date) || !empty($end_date)) { $filtered_invoices = []; foreach ($invoices as $invoice) { $invoice_date = $invoice->getInvoiceDate(); // If invoice has a date, check if it's within the range if ($invoice_date) { $invoice_timestamp = strtotime($invoice_date); $start_timestamp = !empty($start_date) ? strtotime($start_date) : 0; $end_timestamp = !empty($end_date) ? strtotime($end_date . ' 23:59:59') : PHP_INT_MAX; if ($invoice_timestamp >= $start_timestamp && $invoice_timestamp <= $end_timestamp) { $filtered_invoices[] = $invoice; } } else { // If invoice has no date, include it in the results (don't filter out) $filtered_invoices[] = $invoice; } } $invoices = $filtered_invoices; } $status_counts = [ 'paid' => 0, 'unpaid' => 0, 'overdue' => 0, 'draft' => 0, 'canceled' => 0 ]; foreach ($invoices as $invoice) { $status = $invoice->getStatus(); if (in_array($status, ['paid', 'completed'])) { $status_counts['paid']++; } elseif ($status === 'unpaid') { // Check if overdue $due_date = $invoice->getDueDate(); if ($due_date && strtotime($due_date) < current_time('timestamp')) { $status_counts['overdue']++; } else { $status_counts['unpaid']++; } } elseif ($status === 'draft') { $status_counts['draft']++; } elseif (in_array($status, ['canceled', 'cancelled'])) { $status_counts['canceled']++; } } $total_invoices = count($invoices); $percentages = []; foreach ($status_counts as $status => $count) { $percentages[$status] = $total_invoices > 0 ? round(($count / $total_invoices) * 100) : 0; } return [ 'percentages' => $percentages, 'counts' => $status_counts ]; } catch ( \Exception $e ) { return [ 'percentages' => [], 'counts' => [] ]; } } /** * Get top clients by revenue * * @since 1.0.0 * @param object $invoice_repository Invoice repository * @param object $client_repository Client repository * @param string $start_date Optional start date * @param string $end_date Optional end date * @return array Top clients data */ private function getTopClients( $invoice_repository, $client_repository, $start_date = '', $end_date = '' ) { try { $invoices = $invoice_repository->all(); $clients = $client_repository->all(); $client_revenue = []; foreach ($clients as $client) { $client_id = $client->getId(); $client_revenue[$client_id] = [ 'id' => $client_id, 'name' => $client->getName(), 'email' => $client->getEmail(), 'total_amount' => [], 'total_invoices' => 0, 'last_invoice' => '' ]; } foreach ($invoices as $invoice) { $client_id = $invoice->getClientId(); if (isset($client_revenue[$client_id])) { $amount = $invoice->getTotal(); $currency = $invoice->getCurrencyCode(); // Handle "global" currency if (empty($currency) || $currency === 'global') { $currency = get_option('easy_invoice_currency_code', 'USD'); } // Normalize currency to uppercase $currency = strtoupper($currency); if (!isset($client_revenue[$client_id]['total_amount'][$currency])) { $client_revenue[$client_id]['total_amount'][$currency] = [ 'amount' => 0, 'symbol' => \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency) ]; } $client_revenue[$client_id]['total_amount'][$currency]['amount'] += $amount; $client_revenue[$client_id]['total_invoices']++; // Track last invoice date $issue_date = $invoice->getIssueDate(); if ($issue_date && (empty($client_revenue[$client_id]['last_invoice']) || $issue_date > $client_revenue[$client_id]['last_invoice'])) { $client_revenue[$client_id]['last_invoice'] = $issue_date; } } } // Sort by total revenue (USD first, then other currencies) uasort($client_revenue, function($a, $b) { $a_total = isset($a['total_amount']['USD']) ? $a['total_amount']['USD']['amount'] : 0; $b_total = isset($b['total_amount']['USD']) ? $b['total_amount']['USD']['amount'] : 0; return $b_total <=> $a_total; }); // Return top 10 clients return array_slice($client_revenue, 0, 10, true); } catch ( \Exception $e ) { return []; } } /** * Get payment report data * * @since 1.0.0 * @param string $start_date Start date for report * @param string $end_date End date for report * @return array Payment report data */ private function getPaymentReport( $start_date = '', $end_date = '' ) { global $wpdb; $payment_table = $wpdb->prefix . 'posts'; $payment_meta_table = $wpdb->prefix . 'postmeta'; $start = $start_date ? strtotime( $start_date ) : strtotime( '-1 year' ); $end = $end_date ? strtotime( $end_date ) : current_time( 'timestamp' ); // Format dates for SQL query $start_date_formatted = date( 'Y-m-d 00:00:00', $start ); $end_date_formatted = date( 'Y-m-d 23:59:59', $end ); // Query to get payments within date range $query = $wpdb->prepare( "SELECT p.ID, p.post_date, MAX(CASE WHEN pm.meta_key = '_invoice_id' THEN pm.meta_value ELSE NULL END) as invoice_id, MAX(CASE WHEN pm.meta_key = '_amount' THEN pm.meta_value ELSE NULL END) as amount, MAX(CASE WHEN pm.meta_key = '_payment_method' THEN pm.meta_value ELSE NULL END) as payment_method, MAX(CASE WHEN pm.meta_key = '_status' THEN pm.meta_value ELSE NULL END) as status, MAX(CASE WHEN pm.meta_key = '_transaction_id' THEN pm.meta_value ELSE NULL END) as transaction_id, MAX(CASE WHEN pm.meta_key = '_currency' THEN pm.meta_value ELSE NULL END) as currency, MAX(CASE WHEN pm.meta_key = '_currency_symbol' THEN pm.meta_value ELSE NULL END) as currency_symbol FROM $payment_table p LEFT JOIN $payment_meta_table pm ON p.ID = pm.post_id WHERE p.post_type = %s AND p.post_date BETWEEN %s AND %s GROUP BY p.ID ORDER BY p.post_date DESC LIMIT 100", 'easy_invoice_payment', $start_date_formatted, $end_date_formatted ); $payments = $wpdb->get_results( $query, ARRAY_A ); $report_data = [ 'payments' => [], 'total_amount' => 0, 'count' => 0, 'by_method' => [], 'by_status' => [] ]; if ( $payments ) { foreach ( $payments as $payment ) { $payment_method = $payment['payment_method'] ?? 'unknown'; $status = $payment['status'] ?? 'unknown'; $amount = floatval( $payment['amount'] ?? 0 ); $currency = $payment['currency'] ?? 'USD'; $currency_symbol = $payment['currency_symbol'] ?? '$'; // Normalize currency code to uppercase for consistent grouping $currency = strtoupper($currency); // Handle "global" currency by getting the actual global setting if (empty($currency) || strtolower($currency) === 'global') { $currency = get_option('easy_invoice_currency_code', 'USD'); } // Additional check: if currency is still "global" after replacement, use the global setting if (strtolower($currency) === 'global') { $currency = get_option('easy_invoice_currency_code', 'USD'); } // Get proper currency symbol $currency_symbol = \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency); // Add to total (we'll handle multi-currency totals separately) $report_data['count']++; // Track by payment method with currency breakdown if ( ! isset( $report_data['by_method'][$payment_method] ) ) { $report_data['by_method'][$payment_method] = [ 'count' => 0, 'amounts_by_currency' => [] ]; } // Initialize currency for this payment method if not exists if ( ! isset( $report_data['by_method'][$payment_method]['amounts_by_currency'][$currency] ) ) { $report_data['by_method'][$payment_method]['amounts_by_currency'][$currency] = [ 'amount' => 0, 'symbol' => $currency_symbol ]; } $report_data['by_method'][$payment_method]['amounts_by_currency'][$currency]['amount'] += $amount; $report_data['by_method'][$payment_method]['count']++; // Track by status with currency breakdown if ( ! isset( $report_data['by_status'][$status] ) ) { $report_data['by_status'][$status] = [ 'count' => 0, 'amounts_by_currency' => [] ]; } // Initialize currency for this status if not exists if ( ! isset( $report_data['by_status'][$status]['amounts_by_currency'][$currency] ) ) { $report_data['by_status'][$status]['amounts_by_currency'][$currency] = [ 'amount' => 0, 'symbol' => $currency_symbol ]; } $report_data['by_status'][$status]['amounts_by_currency'][$currency]['amount'] += $amount; $report_data['by_status'][$status]['count']++; // Get invoice number if available $invoice_number = ''; if ( ! empty( $payment['invoice_id'] ) ) { $invoice_number = get_post_meta( $payment['invoice_id'], '_invoice_number', true ); // Provide a fallback format if no invoice number is found if ( empty( $invoice_number ) ) { $invoice_number = 'INV-' . $payment['invoice_id']; } } // Format payment for report $report_data['payments'][] = [ 'id' => $payment['ID'], 'date' => $payment['post_date'], 'invoice_id' => $payment['invoice_id'], 'invoice_number' => $invoice_number ?: '#' . $payment['invoice_id'], 'amount' => $amount, 'payment_method' => $payment_method, 'status' => $status, 'transaction_id' => $payment['transaction_id'] ?? '', 'currency' => $currency, 'currency_symbol' => $currency_symbol ]; } } return $report_data; } /** * Get invoice report data * * @since 1.0.0 * @param string $start_date Start date for report * @param string $end_date End date for report * @return array Invoice report data */ private function getInvoiceReport( $start_date = '', $end_date = '' ) { global $wpdb; $invoice_table = $wpdb->prefix . 'posts'; $invoice_meta_table = $wpdb->prefix . 'postmeta'; $start = $start_date ? strtotime( $start_date ) : strtotime( '-1 year' ); $end = $end_date ? strtotime( $end_date ) : current_time( 'timestamp' ); // Format dates for SQL query $start_date_formatted = date( 'Y-m-d 00:00:00', $start ); $end_date_formatted = date( 'Y-m-d 23:59:59', $end ); try { // Query to get invoices within date range - using the correct post type "easy_invoice" // First, let's get all invoices without date filtering to see if there are any $query = $wpdb->prepare( "SELECT p.ID, p.post_date, p.post_status, p.post_title, MAX(CASE WHEN pm.meta_key = '_easy_invoice_number' THEN pm.meta_value ELSE NULL END) as invoice_number, MAX(CASE WHEN pm.meta_key = '_easy_invoice_total' THEN pm.meta_value ELSE NULL END) as total, MAX(CASE WHEN pm.meta_key = '_invoice_total' THEN pm.meta_value ELSE NULL END) as invoice_total, MAX(CASE WHEN pm.meta_key = '_payment_status' THEN pm.meta_value ELSE NULL END) as payment_status, MAX(CASE WHEN pm.meta_key = '_easy_invoice_client_id' THEN pm.meta_value ELSE NULL END) as client_id, MAX(CASE WHEN pm.meta_key = '_easy_invoice_issue_date' THEN pm.meta_value ELSE NULL END) as issue_date, MAX(CASE WHEN pm.meta_key = '_easy_invoice_due_date' THEN pm.meta_value ELSE NULL END) as due_date, MAX(CASE WHEN pm.meta_key = '_easy_invoice_currency_code' THEN pm.meta_value ELSE NULL END) as currency_code, MAX(CASE WHEN pm.meta_key = '_currency_code' THEN pm.meta_value ELSE NULL END) as currency_code_alt, MAX(CASE WHEN pm.meta_key = '_easy_invoice_customer_name' THEN pm.meta_value ELSE NULL END) as customer_name, MAX(CASE WHEN pm.meta_key = 'customer_name' THEN pm.meta_value ELSE NULL END) as customer_name_alt, MAX(CASE WHEN pm.meta_key = '_easy_invoice_client_name' THEN pm.meta_value ELSE NULL END) as client_name, MAX(CASE WHEN pm.meta_key = 'client_name' THEN pm.meta_value ELSE NULL END) as client_name_alt FROM $invoice_table p LEFT JOIN $invoice_meta_table pm ON p.ID = pm.post_id WHERE p.post_type = %s GROUP BY p.ID ORDER BY p.post_date DESC LIMIT 100", 'easy_invoice' ); $invoices = $wpdb->get_results( $query, ARRAY_A ); } catch ( \Exception $e ) { $invoices = array(); } $report_data = [ 'invoices' => [], 'count' => 0, 'total_amounts_by_currency' => [], // Track totals by currency 'by_status' => [ 'paid' => ['count' => 0, 'amounts_by_currency' => []], 'unpaid' => ['count' => 0, 'amounts_by_currency' => []], 'overdue' => ['count' => 0, 'amounts_by_currency' => []], 'draft' => ['count' => 0, 'amounts_by_currency' => []], 'canceled' => ['count' => 0, 'amounts_by_currency' => []], 'other' => ['count' => 0, 'amounts_by_currency' => []] ] ]; if ( $invoices ) { foreach ( $invoices as $invoice ) { $payment_status = $invoice['payment_status'] ?? 'unpaid'; // Check multiple possible total fields $total = 0; if ( ! empty( $invoice['total'] ) ) { $total = floatval( $invoice['total'] ); } elseif ( ! empty( $invoice['invoice_total'] ) ) { $total = floatval( $invoice['invoice_total'] ); } // Get currency information $currency_code = $invoice['currency_code'] ?? $invoice['currency_code_alt'] ?? 'USD'; $currency_code = strtoupper($currency_code); // Handle "global" currency by getting the actual global setting if (empty($currency_code) || strtolower($currency_code) === 'global') { $currency_code = get_option('easy_invoice_currency_code', 'USD'); } // Additional check: if currency is still "global" after replacement, use the global setting if (strtolower($currency_code) === 'global') { $currency_code = get_option('easy_invoice_currency_code', 'USD'); } $currency_symbol = \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency_code); // Add to count $report_data['count']++; // Map payment statuses to standard categories for report $status_key = 'other'; if ( in_array( $payment_status, ['paid', 'completed'] ) ) { $status_key = 'paid'; } elseif ( $payment_status === 'unpaid' ) { $status_key = 'unpaid'; // Check if overdue if ( ! empty( $invoice['due_date'] ) ) { $due_date = strtotime( $invoice['due_date'] ); if ( $due_date && $due_date < current_time( 'timestamp' ) ) { $status_key = 'overdue'; $payment_status = 'overdue'; } } } elseif ( $invoice['post_status'] === 'draft' ) { $status_key = 'draft'; $payment_status = 'draft'; } elseif ( $payment_status === 'canceled' || $invoice['post_status'] === 'trash' ) { $status_key = 'canceled'; $payment_status = 'canceled'; } // Track by status with currency breakdown if ( ! isset( $report_data['by_status'][$status_key]['amounts_by_currency'][$currency_code] ) ) { $report_data['by_status'][$status_key]['amounts_by_currency'][$currency_code] = [ 'amount' => 0, 'symbol' => $currency_symbol ]; } $report_data['by_status'][$status_key]['amounts_by_currency'][$currency_code]['amount'] += $total; $report_data['by_status'][$status_key]['count']++; // Track overall totals by currency if (!isset($report_data['total_amounts_by_currency'][$currency_code])) { $report_data['total_amounts_by_currency'][$currency_code] = [ 'amount' => 0, 'symbol' => $currency_symbol ]; } $report_data['total_amounts_by_currency'][$currency_code]['amount'] += $total; // Get client name if available - try multiple sources $client_name = ''; // First try the customer_name fields from the query if ( ! empty( $invoice['customer_name'] ) ) { $client_name = $invoice['customer_name']; } elseif ( ! empty( $invoice['customer_name_alt'] ) ) { $client_name = $invoice['customer_name_alt']; } elseif ( ! empty( $invoice['client_name'] ) ) { $client_name = $invoice['client_name']; } elseif ( ! empty( $invoice['client_name_alt'] ) ) { $client_name = $invoice['client_name_alt']; } elseif ( ! empty( $invoice['client_id'] ) ) { // Try to get client from post $client = get_post( $invoice['client_id'] ); if ( $client && $client->post_type === 'easy_invoice_client' ) { $client_name = $client->post_title; } else { // Try to get client name from meta if direct post lookup fails $client_name = get_post_meta( $invoice['client_id'], '_client_name', true ); if ( empty( $client_name ) ) { // Try alternative meta key $client_name = get_post_meta( $invoice['client_id'], 'client_name', true ); } if ( empty( $client_name ) ) { // Try to get client name from invoice meta $client_name = get_post_meta( $invoice['ID'], '_client_name', true ); } if ( empty( $client_name ) ) { // Try customer_name from invoice meta $client_name = get_post_meta( $invoice['ID'], '_easy_invoice_customer_name', true ); } if ( empty( $client_name ) ) { // Try alternative customer name meta keys $client_name = get_post_meta( $invoice['ID'], 'customer_name', true ); } if ( empty( $client_name ) ) { // Try client name from invoice meta $client_name = get_post_meta( $invoice['ID'], '_easy_invoice_client_name', true ); } if ( empty( $client_name ) ) { // Try client name from invoice meta (alternative) $client_name = get_post_meta( $invoice['ID'], 'client_name', true ); } } } // If still no client name, try to get it from the invoice post title or other sources if ( empty( $client_name ) ) { // Try to get from invoice post title if it contains client info $invoice_post = get_post( $invoice['ID'] ); if ( $invoice_post && ! empty( $invoice_post->post_title ) ) { $client_name = $invoice_post->post_title; } } // Format invoice number with fallback $invoice_number = ! empty( $invoice['invoice_number'] ) ? $invoice['invoice_number'] : 'INV-' . $invoice['ID']; // Format invoice for report $report_data['invoices'][] = [ 'id' => $invoice['ID'], 'date' => $invoice['post_date'], 'issue_date' => $invoice['issue_date'] ?? $invoice['post_date'], 'due_date' => $invoice['due_date'] ?? '', 'invoice_number' => $invoice_number, 'total' => $total, 'currency' => $currency_code, 'currency_symbol' => $currency_symbol, 'status' => $payment_status, 'client_id' => $invoice['client_id'] ?? '', 'client_name' => $client_name ]; } } return $report_data; } }