Files
ladill-qr-plus/app/Services/Qr/QrAnalyticsService.php
T
isaaccladandCursor cd6571f199
Deploy Ladill QR Plus / deploy (push) Failing after 1s
Extract Ladill QR Plus as standalone app at qr.ladill.com.
Utility QR types only (URL, WiFi, link list, business, app download) with
SSO, Billing API integration, public /q resolver, and qr-plus:import for
platform migration. vCard and commerce types stay on the platform.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 21:31:24 +00:00

92 lines
2.7 KiB
PHP

<?php
namespace App\Services\Qr;
use App\Models\QrCode;
use App\Models\QrScanEvent;
use App\Models\QrWallet;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class QrAnalyticsService
{
/**
* @return array<string, mixed>
*/
public function summaryFor(QrCode $qrCode): array
{
$now = now();
$events = QrScanEvent::query()->where('qr_code_id', $qrCode->id);
return [
'total_scans' => (int) $qrCode->scans_total,
'unique_scans' => (int) $qrCode->unique_scans_total,
'scans_7d' => (clone $events)->where('scanned_at', '>=', $now->copy()->subDays(7))->count(),
'scans_30d' => (clone $events)->where('scanned_at', '>=', $now->copy()->subDays(30))->count(),
'last_scanned_at' => $qrCode->last_scanned_at,
];
}
/**
* @return Collection<int, object{date: string, total: int}>
*/
public function dailyScans(QrCode $qrCode, int $days = 30): Collection
{
$start = now()->subDays($days - 1)->startOfDay();
$rows = QrScanEvent::query()
->selectRaw('DATE(scanned_at) as scan_date, COUNT(*) as total')
->where('qr_code_id', $qrCode->id)
->where('scanned_at', '>=', $start)
->groupBy('scan_date')
->orderBy('scan_date')
->get()
->keyBy('scan_date');
$series = collect();
for ($i = 0; $i < $days; $i++) {
$date = $start->copy()->addDays($i)->toDateString();
$series->push((object) [
'date' => $date,
'total' => (int) ($rows->get($date)?->total ?? 0),
]);
}
return $series;
}
/**
* @return array<int, array{label: string, total: int}>
*/
public function breakdown(QrCode $qrCode, string $column, int $limit = 5): array
{
return QrScanEvent::query()
->select($column, DB::raw('COUNT(*) as total'))
->where('qr_code_id', $qrCode->id)
->whereNotNull($column)
->groupBy($column)
->orderByDesc('total')
->limit($limit)
->get()
->map(fn ($row) => [
'label' => (string) $row->{$column},
'total' => (int) $row->total,
])
->all();
}
/**
* @return \Illuminate\Database\Eloquent\Collection<int, QrScanEvent>
*/
public function recentScans(QrCode $qrCode, int $limit = 20)
{
return QrScanEvent::query()
->where('qr_code_id', $qrCode->id)
->latest('scanned_at')
->limit($limit)
->get();
}
}