response($this->getDemoFilters()); $user = Eva::make('user'); if (!$user->canManage($request->tenant)){ return $this->response([ 'success' => false, 'error' => __eva("You cannot access.") ]); } $tenantId = $request->tenantId(); // Get distinct values for each UTM parameter $sources = $this->getDistinctValues($tenantId, 'utm_source'); $mediums = $this->getDistinctValues($tenantId, 'utm_medium'); $campaigns = $this->getDistinctValues($tenantId, 'utm_campaign'); $terms = $this->getDistinctValues($tenantId, 'utm_term'); $contents = $this->getDistinctValues($tenantId, 'utm_content'); return $this->response([ 'success' => true, 'filters' => [ 'sources' => $sources, 'mediums' => $mediums, 'campaigns' => $campaigns, 'terms' => $terms, 'contents' => $contents ] ]); } /** * Get distinct values for a field */ protected function getDistinctValues($tenantId, $field) { $trackings = BookingTracking::where('restaurant_id', $tenantId) ->whereIsNotNull($field) ->orderBy($field, 'asc') ->get() ->toArrayEachModel(); // Get unique values manually $values = []; $seen = []; //ray($trackings); foreach ($trackings as $tracking) { $value = $tracking[$field]; if ($value && !isset($seen[$value])) { $seen[$value] = true; $values[] = [ 'value' => $value, 'label' => $value ]; } } return $values; } /** * Get tracking data with filters applied */ public function data(Request $request) { // Descomentar esta línea para usar datos demo //return $this->response($this->getDemoData()); //ray($request->params); $user = Eva::make('user'); if (!$user->canManage($request->tenant)){ return $this->response([ 'success' => false, 'error' => __eva("You cannot access.") ]); } $tenantId = $request->tenantId(); // Get filter parameters $period = isset($request->params['period']) ? $request->params['period'] : null; $utm_source = isset($request->params['utm_source']) ? $request->params['utm_source'] : null; $utm_medium = isset($request->params['utm_medium']) ? $request->params['utm_medium'] : null; $utm_campaign = isset($request->params['utm_campaign']) ? $request->params['utm_campaign'] : null; $utm_term = isset($request->params['utm_term']) ? $request->params['utm_term'] : null; $utm_content = isset($request->params['utm_content']) ? $request->params['utm_content'] : null; // Build base query for trackings $query = BookingTracking::where('restaurant_id', $tenantId); // Apply date filter $dateStart = null; $dateEnd = null; if ($period && $period !== 'full_campaign') { $dateFilter = $this->parseDateFilter($period); if ($dateFilter) { if (isset($dateFilter['start']) && isset($dateFilter['end'])) { $dateStart = $dateFilter['start'] . ' 00:00:00'; $dateEnd = $dateFilter['end'] . ' 23:59:59'; $query->where('date_created', '>=', $dateStart); $query->where('date_created', '<=', $dateEnd); } else if (isset($dateFilter['month'])) { $query->where('date_created', 'like', $dateFilter['month'] . '%'); // Calcular inicio y fin del mes $dateStart = $dateFilter['month'] . '-01 00:00:00'; $dateEnd = date('Y-m-t', strtotime($dateFilter['month'] . '-01')) . ' 23:59:59'; } } } // Apply UTM filters (only if not 'all') if ($utm_source && $utm_source !== 'all') { $query->where('utm_source', $utm_source); } if ($utm_medium && $utm_medium !== 'all') { $query->where('utm_medium', $utm_medium); } if ($utm_campaign && $utm_campaign !== 'all') { $query->where('utm_campaign', $utm_campaign); } if ($utm_term && $utm_term !== 'all') { $query->where('utm_term', $utm_term); } if ($utm_content && $utm_content !== 'all') { $query->where('utm_content', $utm_content); } // Get tracking records WITHOUT booking relation $trackings = $query->orderBy('date_created', 'desc')->get()->toArrayEachModel(); // For full_campaign, get date range from filtered trackings if ($period === 'full_campaign' && count($trackings) > 0) { $dates = array_map(function($t) { return $t['date_created']; }, $trackings); // Get min and max dates $minDate = min($dates); $maxDate = max($dates); // Adjust to start of day (00:00:00) $dateStart = date('Y-m-d 00:00:00', strtotime($minDate)); // Adjust to end of day (23:59:59) $dateEnd = date('Y-m-d 23:59:59', strtotime($maxDate)); } // Get summary statistics $stats = $this->calculateStats($trackings, $tenantId, $dateStart, $dateEnd); return $this->response([ 'success' => true, 'trackings' => $trackings, 'stats' => $stats, 'filters_applied' => [ 'period' => $period, 'utm_source' => $utm_source, 'utm_medium' => $utm_medium, 'utm_campaign' => $utm_campaign, 'utm_term' => $utm_term, 'utm_content' => $utm_content ] ]); } /** * Parse date filter string * Can be: yyyy-MM (month) or yyyy-MM-dd-yyyy-MM-dd (range) or 'full_campaign' */ protected function parseDateFilter($period) { // Single month: yyyy-MM if (preg_match('#^(\d{4}-\d{2})$#', $period, $matches)) { return ['month' => $matches[1]]; } // Range dates: yyyy-MM-dd-yyyy-MM-dd if (preg_match('#^(\d{4}-\d{2}-\d{2})-(\d{4}-\d{2}-\d{2})$#', $period, $matches)) { return [ 'start' => $matches[1], 'end' => $matches[2] ]; } return null; } /** * Calculate statistics from tracking data */ protected function calculateStats($trackings, $tenantId, $dateStart, $dateEnd) { $total_trackings = count($trackings); // Count total bookings in the period with valid statuses $bookingQuery = Booking::where('restaurant_id', $tenantId) ->whereIn('status', ['confirmed', 'booked', 'seated', 'paid', 'finished']); if ($dateStart && $dateEnd) { $bookingQuery->where('date_created', '>=', $dateStart) ->where('date_created', '<=', $dateEnd); } $confirmedBookings = $bookingQuery->get()->toArrayEachModel(); $confirmed_bookings_count = count($confirmedBookings); // Calculate total party $total_party = 0; foreach ($confirmedBookings as $booking) { $total_party += intval($booking['party']); } // Group trackings by source $by_source = []; foreach ($trackings as $tracking) { $source = $tracking['utm_source'] ?: 'Direct'; if (!isset($by_source[$source])) { $by_source[$source] = 0; } $by_source[$source]++; } arsort($by_source); // Group by medium $by_medium = []; foreach ($trackings as $tracking) { $medium = $tracking['utm_medium'] ?: 'None'; if (!isset($by_medium[$medium])) { $by_medium[$medium] = 0; } $by_medium[$medium]++; } arsort($by_medium); // Group by campaign $by_campaign = []; foreach ($trackings as $tracking) { $campaign = $tracking['utm_campaign'] ?: 'None'; if (!isset($by_campaign[$campaign])) { $by_campaign[$campaign] = 0; } $by_campaign[$campaign]++; } arsort($by_campaign); $conversion_rate = $total_trackings > 0 ? round(($confirmed_bookings_count / $total_trackings) * 100, 2) : 0; $avg_party_size = $confirmed_bookings_count > 0 ? round($total_party / $confirmed_bookings_count, 1) : 0; return [ 'total_trackings' => $total_trackings, 'confirmed_bookings' => $confirmed_bookings_count, 'conversion_rate' => $conversion_rate, 'avg_party_size' => $avg_party_size, 'by_source' => $by_source, 'by_medium' => $by_medium, 'by_campaign' => $by_campaign, 'period_start' => $dateStart, 'period_end' => $dateEnd ]; } }