query() ->from('fct_orders as o') ->join('fct_order_transactions as ot', 'o.id', '=', 'ot.order_id') ->selectRaw("COUNT(DISTINCT ot.order_id) as total_refunded, SUM(ot.total) / 100 as total_refunded_amount, (SUM(ot.total) / COUNT(DISTINCT ot.order_id)) / 100 as average_refunded_amount") ->whereIn('ot.status', ['refunded', 'partially_refunded']) ->where('o.total_refund', '>', 0); $query = $this->applyFilters($query, $params); if ($groupKey === 'payment_method') { $query = $query->selectRaw("COALESCE(NULLIF(o.{$groupKey}, ''), 'Uncategorized') as group_key")->groupBy("o.{$groupKey}"); } else { $type = $groupKey === 'billing_country' ? 'billing' : 'shipping'; $query = $query->join('fct_order_addresses as a', 'o.id', '=', 'a.order_id') ->selectRaw("COALESCE(a.country, 'Uncategorized') as group_key") ->where('a.type', $type) ->whereNotNull('a.country') ->groupBy('a.country'); } $results = $query->get()->toArray(); $formattedResults = array_map(function ($row) use ($groupKey) { return [ $groupKey => $row->group_key, 'totalRefunded' => (int) $row->total_refunded, 'totalRefundedAmount' => [ 'total' => (float) $row->total_refunded_amount, 'average' => (float) $row->average_refunded_amount, ], ]; }, $results); return $formattedResults; } public function getRefundData($params = []): array { $group = ReportHelper::processGroup( $params['startDate'], $params['endDate'], $params['groupKey'] ); $orderSubQuery = App::db()->query() ->from('fct_orders as o') ->selectRaw("{$group['field']}, o.total_refund, o.total_paid"); $orderSubQuery = $this->applyFilters($orderSubQuery, $params); $refundData = App::db()->query() ->fromSub($orderSubQuery, 'subq') ->selectRaw("COALESCE(`group`, 'TOTAL') as `group`, COUNT( CASE WHEN total_refund > 0 THEN 1 END ) as refund_count, SUM(total_refund) / 100 as refunded_amount, CASE WHEN COUNT(total_refund) > 0 THEN SUM(total_refund) / COUNT(total_refund) / 100 ELSE 0 END as average_refunded_amount, CASE WHEN SUM(total_paid) > 0 THEN (SUM(total_refund) / SUM(total_paid)) * 100 ELSE 0 END as refund_rate") ->groupByRaw("`group` WITH ROLLUP") ->get() ->toArray(); $summary = [ 'refund_rate' => 0, 'refund_count' => 0, 'refunded_amount' => 0, 'average_refunded_amount' => 0, ]; if (!empty($refundData)) { $summary = (array) array_pop($refundData); } return [ 'summary' => $summary, 'grouped' => $refundData, ]; } public function calculateFluctuations($currentMetrics, $previousMetrics) { $metrics = ['refund_count', 'refunded_amount', 'average_refunded_amount', 'refund_rate']; $result = []; foreach ($metrics as $metric) { if ($previousMetrics[$metric] != 0) { $result[$metric] = (($currentMetrics[$metric] - $previousMetrics[$metric]) / $previousMetrics[$metric]) * 100; } else { $result[$metric] = $currentMetrics[$metric] > 0 ? 100 : 0; } } return $result; } public function weeksBetweenRefund($params = []): array { $startDate = $params['startDate']; $endDate = $params['endDate']; $subquery = App::db()->table('fct_order_transactions') ->selectRaw(' order_id, MIN(created_at) AS refund_date ') ->whereIn('status', ['refunded', 'partially_refunded']) ->whereBetween('created_at', [$startDate, $endDate]) ->groupBy('order_id'); $orderQuery = $this->applyFilters( App::db()->table('fct_orders as o'), $params ); return $orderQuery ->selectRaw(' COUNT(*) AS occurrence, IFNULL(((GREATEST(TIMESTAMPDIFF(DAY, o.created_at, r.refund_date), 1) + 6) DIV 7), 1) AS weekBetween ') ->joinSub($subquery, 'r', fn ($join) => $join->on('o.id', '=', 'r.order_id')) ->groupBy('weekBetween') ->orderBy('weekBetween') ->get() ->toArray(); } }