Skip to content

Commit bdc60bc

Browse files
authored
Merge pull request #3133 from codeeu/dev
export script
2 parents 5d54eee + efbc3fd commit bdc60bc

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use Illuminate\Console\Command;
6+
use Illuminate\Support\Facades\DB;
7+
use Illuminate\Support\Facades\Schema;
8+
use Illuminate\Support\Facades\Storage;
9+
10+
class ExportCertificatesProof extends Command
11+
{
12+
protected $signature = 'cw:export-certificates-proof
13+
{--start= : Start datetime (YYYY-MM-DD or full Y-m-d H:i:s)}
14+
{--end= : End datetime (YYYY-MM-DD or full Y-m-d H:i:s)}
15+
{--path= : Output relative path under storage/app (default: exports/certificates_manifest_[range].csv)}';
16+
17+
protected $description = 'Export a CSV manifest of issued certificates (with PDF links) for an interval';
18+
19+
public function handle()
20+
{
21+
$start = $this->option('start') ?: now()->subYear()->startOfDay()->toDateTimeString();
22+
$end = $this->option('end') ?: now()->endOfDay()->toDateTimeString();
23+
24+
// Normalize date-only inputs
25+
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $start)) $start .= ' 00:00:00';
26+
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $end)) $end .= ' 23:59:59';
27+
28+
// --- Schema detection -------------------------------------------------
29+
$hasEventId = Schema::hasColumn('participations', 'event_id');
30+
$hasActivityId = Schema::hasColumn('participations', 'activity_id'); // common alternative
31+
$hasEventTitle = Schema::hasColumn('participations', 'event_title'); // sometimes stored directly
32+
$hasTitle = Schema::hasColumn('participations', 'title'); // generic fallback
33+
34+
$q = DB::table('participations as p')
35+
->leftJoin('users as u', 'u.id', '=', 'p.user_id')
36+
->where('p.status', 'DONE')
37+
->whereNotNull('p.participation_url')
38+
->whereBetween('p.created_at', [$start, $end])
39+
->orderBy('p.id');
40+
41+
// Join events table only if we have a FK on participations
42+
if ($hasEventId) {
43+
$q->leftJoin('events as e', 'e.id', '=', 'p.event_id');
44+
} elseif ($hasActivityId) {
45+
$q->leftJoin('events as e', 'e.id', '=', 'p.activity_id');
46+
}
47+
48+
$select = [
49+
'p.id as participation_id',
50+
'p.created_at as issued_at',
51+
'p.event_date',
52+
'u.email as owner_email',
53+
'p.participation_url as certificate_url',
54+
];
55+
56+
if ($hasEventId || $hasActivityId) {
57+
// We can read from events
58+
$select[] = 'e.id as event_id';
59+
$select[] = 'e.title as event_title';
60+
} else {
61+
// No join available; fall back to a title present on participations (or NULL)
62+
$select[] = DB::raw('NULL as event_id');
63+
if ($hasEventTitle) {
64+
$select[] = 'p.event_title as event_title';
65+
} elseif ($hasTitle) {
66+
$select[] = 'p.title as event_title';
67+
} else {
68+
$select[] = DB::raw('NULL as event_title');
69+
}
70+
}
71+
72+
$rows = $q->get($select);
73+
74+
$defaultPath = 'exports/certificates_manifest_'
75+
. str_replace([':', ' '], ['_', '_'], $start)
76+
. '_to_'
77+
. str_replace([':', ' '], ['_', '_'], $end)
78+
. '.csv';
79+
80+
$path = $this->option('path') ?: $defaultPath;
81+
82+
// Write CSV
83+
$stream = fopen('php://temp', 'w+');
84+
fputcsv($stream, ['participation_id','issued_at','event_date','owner_email','event_id','event_title','certificate_url']);
85+
foreach ($rows as $r) {
86+
// event_id may be missing if we couldn’t join events
87+
$eventId = property_exists($r, 'event_id') ? $r->event_id : null;
88+
fputcsv($stream, [
89+
$r->participation_id,
90+
$r->issued_at,
91+
$r->event_date,
92+
$r->owner_email,
93+
$eventId,
94+
$r->event_title,
95+
$r->certificate_url,
96+
]);
97+
}
98+
rewind($stream);
99+
$csv = stream_get_contents($stream);
100+
fclose($stream);
101+
102+
Storage::disk('local')->put($path, $csv);
103+
104+
$this->info("Wrote ".count($rows)." rows to storage/app/{$path}");
105+
106+
// Monthly breakdown for the audit note
107+
$monthly = DB::table('participations')
108+
->selectRaw('DATE_FORMAT(created_at, "%Y-%m") as yyyymm, COUNT(*) as cnt')
109+
->where('status','DONE')
110+
->whereNotNull('participation_url')
111+
->whereBetween('created_at', [$start,$end])
112+
->groupBy('yyyymm')
113+
->orderBy('yyyymm')
114+
->get();
115+
116+
$this->line('Breakdown:');
117+
foreach ($monthly as $m) {
118+
$this->line(" {$m->yyyymm}: {$m->cnt}");
119+
}
120+
121+
return self::SUCCESS;
122+
}
123+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
participation_id,issued_at,event_date,owner_email,event_id,event_title,certificate_url

0 commit comments

Comments
 (0)