Changeset View
Changeset View
Standalone View
Standalone View
src/app/Http/Controllers/API/V4/Admin/StatsController.php
<?php | <?php | ||||
namespace App\Http\Controllers\API\V4\Admin; | namespace App\Http\Controllers\API\V4\Admin; | ||||
use App\Providers\PaymentProvider; | |||||
use App\User; | use App\User; | ||||
use Carbon\Carbon; | use Carbon\Carbon; | ||||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
use Illuminate\Support\Facades\DB; | use Illuminate\Support\Facades\DB; | ||||
class StatsController extends \App\Http\Controllers\Controller | class StatsController extends \App\Http\Controllers\Controller | ||||
{ | { | ||||
public const COLOR_GREEN = '#48d368'; // '#28a745' | public const COLOR_GREEN = '#48d368'; // '#28a745' | ||||
public const COLOR_GREEN_DARK = '#19692c'; | public const COLOR_GREEN_DARK = '#19692c'; | ||||
public const COLOR_RED = '#e77681'; // '#dc3545' | public const COLOR_RED = '#e77681'; // '#dc3545' | ||||
public const COLOR_RED_DARK = '#a71d2a'; | public const COLOR_RED_DARK = '#a71d2a'; | ||||
public const COLOR_BLUE = '#4da3ff'; // '#007bff' | public const COLOR_BLUE = '#4da3ff'; // '#007bff' | ||||
public const COLOR_BLUE_DARK = '#0056b3'; | public const COLOR_BLUE_DARK = '#0056b3'; | ||||
public const COLOR_ORANGE = '#f1a539'; | |||||
/** | /** | ||||
* Fetch chart data | * Fetch chart data | ||||
* | * | ||||
* @param string $chart Name of the chart | * @param string $chart Name of the chart | ||||
* | * | ||||
* @return \Illuminate\Http\JsonResponse | * @return \Illuminate\Http\JsonResponse | ||||
*/ | */ | ||||
Show All 10 Lines | public function chart($chart) | ||||
} | } | ||||
$result = $this->{$method}(); | $result = $this->{$method}(); | ||||
return response()->json($result); | return response()->json($result); | ||||
} | } | ||||
/** | /** | ||||
* Get discounts chart | |||||
*/ | |||||
protected function chartDiscounts(): array | |||||
{ | |||||
// TODO: Exclude deleted account wallets | |||||
$discounts = DB::table('wallets') | |||||
->join('discounts', 'discounts.id', '=', 'wallets.discount_id') | |||||
->selectRaw("discount, count(discount_id) as cnt") | |||||
->groupBy('discounts.discount') | |||||
->get() | |||||
->pluck('cnt', 'discount') | |||||
->all(); | |||||
$labels = array_keys($discounts); | |||||
$discounts = array_values($discounts); | |||||
// $labels = [10, 25, 30, 100]; | |||||
// $discounts = [100, 120, 30, 50]; | |||||
$labels = array_map(function ($item) { | |||||
return $item . '%'; | |||||
}, $labels); | |||||
// See https://frappe.io/charts/docs for format/options description | |||||
return [ | |||||
'title' => 'Discounts', | |||||
'type' => 'donut', | |||||
'colors' => [ | |||||
self::COLOR_BLUE, | |||||
self::COLOR_BLUE_DARK, | |||||
self::COLOR_GREEN, | |||||
self::COLOR_GREEN_DARK, | |||||
self::COLOR_ORANGE, | |||||
self::COLOR_RED, | |||||
self::COLOR_RED_DARK | |||||
], | |||||
'maxSlices' => 8, | |||||
'tooltipOptions' => [], // does not work without it (https://github.com/frappe/charts/issues/314) | |||||
'data' => [ | |||||
'labels' => $labels, | |||||
'datasets' => [ | |||||
[ | |||||
'values' => $discounts | |||||
] | |||||
] | |||||
] | |||||
]; | |||||
} | |||||
/** | |||||
* Get income chart | |||||
*/ | |||||
protected function chartIncome(): array | |||||
{ | |||||
$weeks = 8; | |||||
$start = Carbon::now(); | |||||
$labels = []; | |||||
while ($weeks > 0) { | |||||
$labels[] = $start->format('Y-W'); | |||||
$start->subWeeks(1); | |||||
$weeks--; | |||||
} | |||||
$labels = array_reverse($labels); | |||||
$start->startOfWeek(Carbon::MONDAY); | |||||
$payments = DB::table('payments') | |||||
->selectRaw("concat(year(updated_at), '-', week(updated_at, 3)) as period, sum(amount) as amount") | |||||
->where('updated_at', '>=', $start->toDateString()) | |||||
->where('status', PaymentProvider::STATUS_PAID) | |||||
->whereIn('type', [PaymentProvider::TYPE_ONEOFF, PaymentProvider::TYPE_RECURRING]) | |||||
->groupByRaw('1') | |||||
->get() | |||||
->pluck('amount', 'period') | |||||
->map(function ($amount) { | |||||
return $amount / 100; | |||||
}); | |||||
// TODO: exclude refunds/chargebacks | |||||
$empty = array_fill_keys($labels, 0); | |||||
$payments = array_values(array_merge($empty, $payments->all())); | |||||
// $payments = [1000, 1200.25, 3000, 1897.50, 2000, 1900, 2134, 3330]; | |||||
// See https://frappe.io/charts/docs for format/options description | |||||
return [ | |||||
'title' => 'Income in CHF - last 8 weeks', | |||||
'type' => 'bar', | |||||
'colors' => [self::COLOR_BLUE], | |||||
'axisOptions' => [ | |||||
'xIsSeries' => true, | |||||
], | |||||
'data' => [ | |||||
'labels' => $labels, | |||||
'datasets' => [ | |||||
[ | |||||
// 'name' => 'Payments', | |||||
'values' => $payments | |||||
] | |||||
], | |||||
'yMarkers' => [ | |||||
[ | |||||
'label' => 'average', | |||||
'value' => collect($payments)->avg(), | |||||
'options' => [ 'labelPos' => 'left' ] // default: 'right' | |||||
] | |||||
] | |||||
] | |||||
]; | |||||
} | |||||
/** | |||||
* Get created/deleted users chart | * Get created/deleted users chart | ||||
*/ | */ | ||||
protected function chartUsers(): array | protected function chartUsers(): array | ||||
{ | { | ||||
$weeks = 8; | $weeks = 8; | ||||
$start = Carbon::now(); | $start = Carbon::now(); | ||||
$labels = []; | $labels = []; | ||||
Show All 14 Lines | protected function chartUsers(): array | ||||
$deleted = DB::table('users') | $deleted = DB::table('users') | ||||
->selectRaw("concat(year(deleted_at), '-', week(deleted_at, 3)) as period, count(*) as cnt") | ->selectRaw("concat(year(deleted_at), '-', week(deleted_at, 3)) as period, count(*) as cnt") | ||||
->where('deleted_at', '>=', $start->toDateString()) | ->where('deleted_at', '>=', $start->toDateString()) | ||||
->groupByRaw('1') | ->groupByRaw('1') | ||||
->get(); | ->get(); | ||||
$empty = array_fill_keys($labels, 0); | $empty = array_fill_keys($labels, 0); | ||||
$created = array_merge($empty, $created->pluck('cnt', 'period')->all()); | $created = array_values(array_merge($empty, $created->pluck('cnt', 'period')->all())); | ||||
$deleted = array_merge($empty, $deleted->pluck('cnt', 'period')->all()); | $deleted = array_values(array_merge($empty, $deleted->pluck('cnt', 'period')->all())); | ||||
//$created = [5, 2, 4, 2, 0, 5, 2, 4]; | // $created = [5, 2, 4, 2, 0, 5, 2, 4]; | ||||
//$deleted = [1, 2, 3, 1, 2, 1, 2, 3]; | // $deleted = [1, 2, 3, 1, 2, 1, 2, 3]; | ||||
// See https://frappe.io/charts/docs for format/options description | // See https://frappe.io/charts/docs for format/options description | ||||
return [ | return [ | ||||
'title' => 'Users - last 8 weeks', | 'title' => 'Users - last 8 weeks', | ||||
// 'type' => 'axis-mixed', | // 'type' => 'axis-mixed', | ||||
'colors' => [self::COLOR_GREEN, self::COLOR_RED], | 'colors' => [self::COLOR_GREEN, self::COLOR_RED], | ||||
'axisOptions' => [ | |||||
'xIsSeries' => true, | |||||
], | |||||
'data' => [ | 'data' => [ | ||||
'labels' => $labels, | 'labels' => $labels, | ||||
'datasets' => [ | 'datasets' => [ | ||||
[ | [ | ||||
'name' => 'Created', | 'name' => 'Created', | ||||
'chartType' => 'bar', | 'chartType' => 'bar', | ||||
'values' => $created | 'values' => $created | ||||
], | ], | ||||
[ | [ | ||||
'name' => 'Deleted', | 'name' => 'Deleted', | ||||
'chartType' => 'line', | 'chartType' => 'line', | ||||
'values' => $deleted | 'values' => $deleted | ||||
] | ] | ||||
], | |||||
'yMarkers' => [ | |||||
[ | |||||
'label' => 'average', | |||||
'value' => collect($created)->avg(), | |||||
'options' => [ 'labelPos' => 'left' ] // default: 'right' | |||||
] | |||||
] | |||||
] | |||||
]; | |||||
} | |||||
/** | |||||
* Get all users chart | |||||
*/ | |||||
protected function chartUsersAll(): array | |||||
{ | |||||
$weeks = 54; | |||||
$start = Carbon::now(); | |||||
$labels = []; | |||||
while ($weeks > 0) { | |||||
$labels[] = $start->format('Y-W'); | |||||
$start->subWeeks(1); | |||||
$weeks--; | |||||
} | |||||
$labels = array_reverse($labels); | |||||
$start->startOfWeek(Carbon::MONDAY); | |||||
$created = DB::table('users') | |||||
->selectRaw("concat(year(created_at), '-', week(created_at, 3)) as period, count(*) as cnt") | |||||
->where('created_at', '>=', $start->toDateString()) | |||||
->groupByRaw('1') | |||||
->get(); | |||||
$deleted = DB::table('users') | |||||
->selectRaw("concat(year(deleted_at), '-', week(deleted_at, 3)) as period, count(*) as cnt") | |||||
->where('deleted_at', '>=', $start->toDateString()) | |||||
->groupByRaw('1') | |||||
->get(); | |||||
$count = DB::table('users')->whereNull('deleted_at')->count(); | |||||
$empty = array_fill_keys($labels, 0); | |||||
$created = array_merge($empty, $created->pluck('cnt', 'period')->all()); | |||||
$deleted = array_merge($empty, $deleted->pluck('cnt', 'period')->all()); | |||||
$all = []; | |||||
foreach (array_reverse($labels) as $label) { | |||||
$diff = $created[$label] - $deleted[$label]; | |||||
$all[] = $count - $created[$label]; | |||||
$count -= $diff; | |||||
} | |||||
$all = array_reverse($all); | |||||
// $start = 3000; | |||||
// for ($i = 0; $i < count($labels); $i++) { | |||||
// $all[$i] = $start + $i * 15; | |||||
// } | |||||
// See https://frappe.io/charts/docs for format/options description | |||||
return [ | |||||
'title' => 'All Users - last year', | |||||
'type' => 'line', | |||||
'colors' => [self::COLOR_GREEN], | |||||
'axisOptions' => [ | |||||
'xIsSeries' => true, | |||||
'xAxisMode' => 'tick', | |||||
], | |||||
'lineOptions' => [ | |||||
'hideDots' => true, | |||||
'regionFill' => true, | |||||
], | |||||
'data' => [ | |||||
'labels' => $labels, | |||||
'datasets' => [ | |||||
[ | |||||
// 'name' => 'Existing', | |||||
'values' => $all | |||||
] | |||||
] | ] | ||||
] | ] | ||||
]; | ]; | ||||
} | } | ||||
} | } |