Viewing file: AdminController.php (12.2 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use App\Models\User; use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Role; use App\Models\AuditLog;
class AdminController extends Controller { public function getRevenueKpis(Request $request) { $period = $request->query('period', '7d'); $startDate = $this->getStartDate($period); $previousStartDate = $this->getStartDate($period, true);
// Total Revenue (Top-ups) $currentRevenue = \App\Models\Transaction::where('type', 'credit') ->where('status', 'completed') ->where('created_at', '>=', $startDate) ->sum('amount');
$previousRevenue = \App\Models\Transaction::where('type', 'credit') ->where('status', 'completed') ->whereBetween('created_at', [$previousStartDate, $startDate]) ->sum('amount');
// Net Profit (20% of Campaign Spend) $currentSpend = \App\Models\CampaignPerformance::where('date', '>=', $startDate)->sum('spend'); $previousSpend = \App\Models\CampaignPerformance::whereBetween('date', [$previousStartDate, $startDate])->sum('spend'); $currentProfit = $currentSpend * 0.20; $previousProfit = $previousSpend * 0.20;
// Markup Revenue (Same as Profit for now based on plan) $currentMarkup = $currentProfit; $previousMarkup = $previousProfit;
// Active Customers $currentActive = \App\Models\CampaignPerformance::where('date', '>=', $startDate) ->join('campaigns', 'campaign_performances.campaign_id', '=', 'campaigns.id') ->distinct('campaigns.user_id') ->count('campaigns.user_id');
$previousActive = \App\Models\CampaignPerformance::whereBetween('date', [$previousStartDate, $startDate]) ->join('campaigns', 'campaign_performances.campaign_id', '=', 'campaigns.id') ->distinct('campaigns.user_id') ->count('campaigns.user_id');
return response()->json([ 'total_revenue' => [ 'value' => '$' . number_format($currentRevenue, 2), 'change' => $this->calculateChange($currentRevenue, $previousRevenue), 'change_type' => $currentRevenue >= $previousRevenue ? 'positive' : 'negative' ], 'net_profit' => [ 'value' => '$' . number_format($currentProfit, 2), 'change' => $this->calculateChange($currentProfit, $previousProfit), 'change_type' => $currentProfit >= $previousProfit ? 'positive' : 'negative' ], 'markup_revenue' => [ 'value' => '$' . number_format($currentMarkup, 2), 'change' => $this->calculateChange($currentMarkup, $previousMarkup), 'change_type' => $currentMarkup >= $previousMarkup ? 'positive' : 'negative' ], 'active_customers' => [ 'value' => (string)$currentActive, 'change' => ($currentActive - $previousActive) . ' vs previous', 'change_type' => $currentActive >= $previousActive ? 'positive' : 'negative' ] ]); }
public function getRevenueStreams(Request $request) { $period = $request->query('period', '7d'); $startDate = $this->getStartDate($period);
$dates = \App\Models\CampaignPerformance::where('date', '>=', $startDate) ->selectRaw('DATE(date) as date') ->groupBy('date') ->orderBy('date') ->pluck('date');
// If no data, generate dates if ($dates->isEmpty()) { $dates = collect(); for ($i = 0; $i < 7; $i++) { $dates->push(now()->subDays($i)->format('Y-m-d')); } $dates = $dates->sort()->values(); }
$streams = $dates->map(function ($date) { $topup = \App\Models\Transaction::where('type', 'credit') ->where('status', 'completed') ->whereDate('created_at', $date) ->sum('amount');
$spend = \App\Models\CampaignPerformance::whereDate('date', $date)->sum('spend'); $profit = $spend * 0.20; return [ 'date' => \Carbon\Carbon::parse($date)->format('M d'), 'topup' => round($topup, 2), 'markup' => round($profit, 2), // Using profit as markup 'card_fees' => round($topup * 0.029, 2), // Approx 2.9% card fee 'service_fees' => round($spend * 0.05, 2), // Approx 5% service fee 'profit' => round($profit, 2) ]; });
return response()->json($streams); }
public function getTopCustomers(Request $request) { $period = $request->query('period', '30d'); $startDate = $this->getStartDate($period);
$customers = User::select('users.id', 'users.name', 'users.email') ->join('campaigns', 'users.id', '=', 'campaigns.user_id') ->join('campaign_performances', 'campaigns.id', '=', 'campaign_performances.campaign_id') ->where('campaign_performances.date', '>=', $startDate) ->selectRaw('SUM(campaign_performances.spend) as total_spend') ->selectRaw('COUNT(DISTINCT campaigns.id) as campaign_count') ->groupBy('users.id', 'users.name', 'users.email') ->orderByDesc('total_spend') ->limit(5) ->get() ->map(function ($customer) { return [ 'name' => $customer->name, 'email' => $customer->email, 'spend' => '$' . number_format($customer->total_spend, 2), 'profit' => '$' . number_format($customer->total_spend * 0.20, 2), 'campaigns' => $customer->campaign_count ]; });
return response()->json($customers); }
public function getTopCampaigns(Request $request) { $period = $request->query('period', '30d'); $startDate = $this->getStartDate($period);
$campaigns = \App\Models\Campaign::select('campaigns.id', 'campaigns.name', 'users.email as customer_email') ->join('users', 'campaigns.user_id', '=', 'users.id') ->join('campaign_performances', 'campaigns.id', '=', 'campaign_performances.campaign_id') ->where('campaign_performances.date', '>=', $startDate) ->selectRaw('SUM(campaign_performances.spend) as total_spend') ->groupBy('campaigns.id', 'campaigns.name', 'users.email') ->orderByDesc('total_spend') ->limit(5) ->get() ->map(function ($campaign) { return [ 'name' => $campaign->name, 'customer' => $campaign->customer_email, 'spend' => '$' . number_format($campaign->total_spend, 2), 'profit' => '$' . number_format($campaign->total_spend * 0.20, 2), 'margin' => '20%' ]; });
return response()->json($campaigns); }
public function getAnomalies() { // Simple anomaly detection: Campaigns with daily spend > 2x average $anomalies = []; $campaigns = \App\Models\Campaign::with(['user', 'performances' => function($q) { $q->latest('date')->limit(30); }])->get();
foreach ($campaigns as $campaign) { if ($campaign->performances->isEmpty()) continue;
$recent = $campaign->performances->first(); $avgSpend = $campaign->performances->avg('spend'); if ($avgSpend > 0 && $recent->spend > ($avgSpend * 2)) { $anomalies[] = [ 'type' => 'Spike', 'campaign' => $campaign->name, 'customer' => $campaign->user->email, 'amount' => '$' . number_format($recent->spend, 2), 'threshold' => '$' . number_format($avgSpend * 2, 2), 'detected' => $recent->date ]; } }
return response()->json($anomalies); }
private function getStartDate($period, $previous = false) { $now = now(); if ($previous) { // Logic for previous period start date switch ($period) { case '24h': return $now->subHours(48); case '7d': return $now->subDays(14); case '30d': return $now->subDays(60); case '90d': return $now->subDays(180); default: return $now->subDays(14); } }
switch ($period) { case '24h': return $now->subHours(24); case '7d': return $now->subDays(7); case '30d': return $now->subDays(30); case '90d': return $now->subDays(90); default: return $now->subDays(7); } }
private function calculateChange($current, $previous) { if ($previous == 0) return $current > 0 ? '+100%' : '0%'; $change = (($current - $previous) / $previous) * 100; return ($change > 0 ? '+' : '') . number_format($change, 1) . '%'; }
public function exportRevenueReport(Request $request) { $period = $request->query('period', '7d'); $streams = $this->getRevenueStreams($request)->getData();
$headers = [ "Content-type" => "text/csv", "Content-Disposition" => "attachment; filename=revenue-report-{$period}.csv", "Pragma" => "no-cache", "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", "Expires" => "0" ];
$callback = function() use ($streams) { $file = fopen('php://output', 'w'); fputcsv($file, ['Date', 'Top-up Revenue', 'Markup Revenue', 'Card Fees', 'Service Fees', 'Net Profit']);
foreach ($streams as $row) { fputcsv($file, [ $row->date, $row->topup, $row->markup, $row->card_fees, $row->service_fees, $row->profit ]); }
fclose($file); };
return response()->stream($callback, 200, $headers); }
public function createStaff(Request $request) { $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:8', ]);
$staff = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), 'role' => 'staff', ]);
AuditLog::log('Create Staff', 'user', $staff->id, ['email' => $staff->email, 'name' => $staff->name]);
return response()->json(['staff' => $staff], 201); }
public function getStaff() { $staff = User::where('role', 'staff')->get(); return response()->json(['staff' => $staff]); }
public function createPermission(Request $request) { $request->validate([ 'name' => 'required|string|unique:permissions', ]);
$permission = Permission::create(['name' => $request->name]); AuditLog::log('Create Permission', 'permission', $permission->id, ['name' => $permission->name]);
return response()->json(['permission' => $permission], 201); }
public function assignPermission(Request $request) { $request->validate([ 'user_id' => 'required|exists:users,id', 'permission' => 'required|string', ]);
$user = User::find($request->user_id); $user->givePermissionTo($request->permission);
AuditLog::log('Assign Permission', 'user', $user->id, ['permission' => $request->permission]);
return response()->json(['message' => 'Permission assigned']); }
public function getPermissions() { $permissions = Permission::all(); return response()->json(['permissions' => $permissions]); } }
|