Commit 977f178d authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add branch_id to participants/payments and fix error page copy button

Participants and payments are now branch-scoped: migration adds nullable
branch_id FK to both tables, all creation paths (ParticipantForm,
receptionist wizards, InvoiceShow, POSService) pass branch_id through.

Error page copy button rewritten to use a hidden textarea rendered
server-side — eliminates JS string escaping issues with multi-line
error messages and special characters.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 596c3ee3
......@@ -20,6 +20,7 @@ class Payment extends Model
protected $fillable = [
'academy_id',
'branch_id',
'invoice_id',
'reference',
'direction',
......
......@@ -244,6 +244,7 @@ private function recordSinglePayment($invoice, string $method, int $amount, User
$this->paymentService->recordPayment([
'academy_id' => $invoice->academy_id,
'branch_id' => $invoice->branch_id,
'invoice_id' => $invoice->id,
'amount' => $amount,
'method' => $method,
......
......@@ -25,6 +25,7 @@ class Participant extends Model
protected $fillable = [
'academy_id',
'branch_id',
'person_id',
'participant_number',
'registration_date',
......
......@@ -54,6 +54,7 @@ public function register(array $data, User $actor): Participant
$participant = Participant::create([
'person_id' => $person->id,
'branch_id' => $data['branch_id'] ?? null,
'participant_number' => $number,
'registration_date' => $data['registration_date'] ?? now()->toDateString(),
'registration_source' => $data['registration_source'] ?? 'walk_in',
......
......@@ -55,6 +55,7 @@ public function recordPayment(PaymentService $service): void
try {
$service->recordPayment([
'academy_id' => $this->invoice->academy_id,
'branch_id' => auth()->user()->branch_id ?? $this->invoice->branch_id ?? null,
'invoice_id' => $this->invoice->id,
'reference' => 'PAY-' . now()->format('YmdHis') . '-' . rand(100, 999),
'direction' => 'inbound',
......
......@@ -30,6 +30,7 @@ class ParticipantForm extends Component
public string $email = '';
// Participant fields
public ?int $branch_id = null;
public string $registration_source = 'walk_in';
public ?int $primary_activity_id = null;
public ?int $primary_guardian_id = null;
......@@ -56,6 +57,7 @@ public function mount(?Participant $participant = null): void
$this->name_ar = $participant->person->name_ar ?? '';
$this->name = $participant->person->name ?? '';
$this->branch_id = $participant->branch_id;
$this->registration_source = $participant->registration_source->value ?? $participant->registration_source;
$this->primary_activity_id = $participant->primary_activity_id;
$this->primary_guardian_id = $participant->primary_guardian_id;
......@@ -158,6 +160,7 @@ public function save(ParticipantService $service): void
session()->flash('success', __('تم تحديث بيانات المشترك بنجاح'));
} else {
$data = [
'branch_id' => $this->branch_id ?? auth()->user()->branch_id ?? null,
'registration_source' => $this->registration_source,
'primary_activity_id' => $this->primary_activity_id,
'primary_guardian_id' => $this->primary_guardian_id,
......
......@@ -152,8 +152,12 @@ public function confirm(PaymentService $service): void
$payment = $service->recordPayment([
'invoice_id' => $this->selected_invoice_id,
'branch_id' => $this->branchId,
'amount' => $amountPiasters,
'method' => $this->payment_method,
'direction' => 'inbound',
'currency' => 'EGP',
'payment_date' => now()->toDateString(),
'notes' => $this->payment_notes ?: null,
], auth()->user());
......
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('participants', function (Blueprint $table) {
$table->foreignId('branch_id')->nullable()->after('academy_id')->constrained('branches');
$table->index(['academy_id', 'branch_id']);
});
Schema::table('payments', function (Blueprint $table) {
$table->foreignId('branch_id')->nullable()->after('academy_id')->constrained('branches');
$table->index(['academy_id', 'branch_id']);
});
}
public function down(): void
{
Schema::table('participants', function (Blueprint $table) {
$table->dropConstrainedForeignId('branch_id');
});
Schema::table('payments', function (Blueprint $table) {
$table->dropConstrainedForeignId('branch_id');
});
}
};
......@@ -187,50 +187,55 @@ class="w-full sm:w-auto inline-flex items-center justify-center gap-3 px-8 py-4
</div>
</div>
</div>
<textarea id="errorReportData" class="hidden">
=== ERROR REPORT ===
Time: {{ now()->format('Y-m-d H:i:s') }}
Error ID: {{ $errorId ?? 'N/A' }}
--- Exception ---
Class: {{ $exceptionClass ?? 'Unknown' }}
Message: {{ $message ?? 'Unknown error' }}
File: {{ $file ?? 'N/A' }}:{{ $line ?? '?' }}
--- Request ---
URL: {{ $url ?? 'N/A' }}
Method: {{ $method ?? 'N/A' }}
Route: {{ $routeName ?? 'N/A' }}
User: {{ $userName ?? 'Guest' }} (ID: {{ $userId ?? '-' }})
IP: {{ $ip ?? 'N/A' }}
@if(!empty($trace))
--- Stack Trace ---
@foreach($trace as $i => $frame)
#{{ $i }} {{ $frame['file'] ?? '(internal)' }}:{{ $frame['line'] ?? '?' }} {{ ($frame['class'] ?? '') . ($frame['type'] ?? '') . ($frame['function'] ?? '') }}()
@endforeach
@endif
@if(!empty($inputData))
--- Input Data ---
{{ $inputData }}
@endif
@if(!empty($queries))
--- SQL Queries ---
@foreach($queries as $query)
{{ $query['query'] ?? '' }} ({{ $query['time'] ?? '?' }}ms)
@endforeach
@endif
@if(!empty($headers))
--- Headers ---
{{ $headers }}
@endif
@if(!empty($sessionData))
--- Session ---
{{ $sessionData }}
@endif
</textarea>
<script>
function copyErrorReport() {
const lines = [];
lines.push('=== ERROR REPORT ===');
lines.push('Time: {{ now()->format("Y-m-d H:i:s") }}');
lines.push('Error ID: {{ $errorId ?? "N/A" }}');
lines.push('');
lines.push('--- Exception ---');
lines.push('Class: {{ $exceptionClass ?? "Unknown" }}');
lines.push('Message: {{ addslashes($message ?? "Unknown error") }}');
lines.push('File: {{ $file ?? "N/A" }}:{{ $line ?? "?" }}');
lines.push('');
lines.push('--- Request ---');
lines.push('URL: {{ $url ?? "N/A" }}');
lines.push('Method: {{ $method ?? "N/A" }}');
lines.push('Route: {{ $routeName ?? "N/A" }}');
lines.push('User: {{ $userName ?? "Guest" }} (ID: {{ $userId ?? "-" }})');
lines.push('IP: {{ $ip ?? "N/A" }}');
lines.push('');
@if(!empty($trace))
lines.push('--- Stack Trace ---');
@foreach($trace as $i => $frame)
lines.push('#{{ $i }} {{ addslashes($frame["file"] ?? "(internal)") }}:{{ $frame["line"] ?? "?" }} {{ addslashes(($frame["class"] ?? "") . ($frame["type"] ?? "") . ($frame["function"] ?? "")) }}()');
@endforeach
lines.push('');
@endif
@if(!empty($inputData))
lines.push('--- Input Data ---');
lines.push({!! json_encode($inputData) !!});
lines.push('');
@endif
@if(!empty($queries))
lines.push('--- SQL Queries ---');
@foreach($queries as $query)
lines.push('{{ addslashes($query["query"] ?? "") }} ({{ $query["time"] ?? "?" }}ms)');
@endforeach
lines.push('');
@endif
@if(!empty($sessionData))
lines.push('--- Session ---');
lines.push({!! json_encode($sessionData) !!});
@endif
const text = lines.join('\n');
const text = document.getElementById('errorReportData').value.trim();
navigator.clipboard.writeText(text).then(() => {
document.getElementById('copyIcon').classList.add('hidden');
document.getElementById('checkIcon').classList.remove('hidden');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment