147 lines
4.5 KiB
PHP
147 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Mail\MemberActivationMail;
|
|
use App\Models\Member;
|
|
use App\Models\User;
|
|
use App\Support\AuditLogger;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Facades\Password;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ImportMembers extends Command
|
|
{
|
|
protected $signature = 'members:import {path : CSV file path}';
|
|
|
|
protected $description = 'Import members from a CSV file';
|
|
|
|
public function handle(): int
|
|
{
|
|
$path = $this->argument('path');
|
|
|
|
if (! is_file($path)) {
|
|
$this->error("File not found: {$path}");
|
|
|
|
return static::FAILURE;
|
|
}
|
|
|
|
$handle = fopen($path, 'r');
|
|
|
|
if (! $handle) {
|
|
$this->error("Unable to open file: {$path}");
|
|
|
|
return static::FAILURE;
|
|
}
|
|
|
|
$header = fgetcsv($handle);
|
|
|
|
if (! $header) {
|
|
$this->error('CSV file is empty.');
|
|
fclose($handle);
|
|
|
|
return static::FAILURE;
|
|
}
|
|
|
|
$header = array_map('trim', $header);
|
|
|
|
$expected = [
|
|
'full_name',
|
|
'email',
|
|
'phone',
|
|
'address_line_1',
|
|
'address_line_2',
|
|
'city',
|
|
'postal_code',
|
|
'emergency_contact_name',
|
|
'emergency_contact_phone',
|
|
'membership_started_at',
|
|
'membership_expires_at',
|
|
];
|
|
|
|
foreach ($expected as $column) {
|
|
if (! in_array($column, $header, true)) {
|
|
$this->error("Missing required column: {$column}");
|
|
fclose($handle);
|
|
|
|
return static::FAILURE;
|
|
}
|
|
}
|
|
|
|
$indexes = array_flip($header);
|
|
|
|
$createdUsers = 0;
|
|
$updatedMembers = 0;
|
|
|
|
while (($row = fgetcsv($handle)) !== false) {
|
|
$email = trim($row[$indexes['email']] ?? '');
|
|
|
|
if ($email === '') {
|
|
continue;
|
|
}
|
|
|
|
$fullName = trim($row[$indexes['full_name']] ?? '');
|
|
$nationalId = trim($row[$indexes['national_id']] ?? '');
|
|
$phone = trim($row[$indexes['phone']] ?? '');
|
|
$started = trim($row[$indexes['membership_started_at']] ?? '');
|
|
$expires = trim($row[$indexes['membership_expires_at']] ?? '');
|
|
$address1 = trim($row[$indexes['address_line_1']] ?? '');
|
|
$address2 = trim($row[$indexes['address_line_2']] ?? '');
|
|
$city = trim($row[$indexes['city']] ?? '');
|
|
$postal = trim($row[$indexes['postal_code']] ?? '');
|
|
$emergencyName = trim($row[$indexes['emergency_contact_name']] ?? '');
|
|
$emergencyPhone = trim($row[$indexes['emergency_contact_phone']] ?? '');
|
|
|
|
$user = User::where('email', $email)->first();
|
|
$isNewUser = false;
|
|
|
|
if (! $user) {
|
|
$user = User::create([
|
|
'name' => $fullName !== '' ? $fullName : $email,
|
|
'email' => $email,
|
|
'password' => Str::random(32),
|
|
]);
|
|
$isNewUser = true;
|
|
$createdUsers++;
|
|
}
|
|
|
|
$member = Member::updateOrCreate(
|
|
['user_id' => $user->id],
|
|
[
|
|
'full_name' => $fullName !== '' ? $fullName : $user->name,
|
|
'email' => $email,
|
|
'national_id' => $nationalId !== '' ? $nationalId : null,
|
|
'phone' => $phone !== '' ? $phone : null,
|
|
'address_line_1' => $address1 ?: null,
|
|
'address_line_2' => $address2 ?: null,
|
|
'city' => $city ?: null,
|
|
'postal_code' => $postal ?: null,
|
|
'emergency_contact_name' => $emergencyName ?: null,
|
|
'emergency_contact_phone' => $emergencyPhone ?: null,
|
|
'membership_started_at' => $started !== '' ? $started : null,
|
|
'membership_expires_at' => $expires !== '' ? $expires : null,
|
|
],
|
|
);
|
|
|
|
$updatedMembers++;
|
|
|
|
if ($isNewUser) {
|
|
$token = Password::createToken($user);
|
|
|
|
Mail::to($user)->queue(new MemberActivationMail($user, $token));
|
|
AuditLogger::log('user.activation_link_sent', $user, [
|
|
'email' => $user->email,
|
|
]);
|
|
}
|
|
}
|
|
|
|
fclose($handle);
|
|
|
|
$this->info("Users created: {$createdUsers}");
|
|
$this->info("Members imported/updated: {$updatedMembers}");
|
|
|
|
return static::SUCCESS;
|
|
}
|
|
}
|