Commit 0cc5b982 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Fix all column mismatches between code and live database schema

Critical SQL fixes (pages were crashing):
- GlobalSearch: remove non-existent branch_id/invoice_number, fix relationship
- RevenueWidget: payment_method → method
- FinancialReport: line_total → total_amount, balance_due → due_amount
- PaymentPlanCreate: rewrite to match actual payment_plans/installments schema

High-priority display fixes (features showing null):
- invoice_number → number (8 locations)
- balance_due → due_amount (6 locations)
- full_name_ar → full_name (7 locations, accessor doesn't exist)
- payment_method → method in print view
- subtotal → subtotal_amount
- description → notes on invoice
- line_total → total_amount on invoice items
- receipt_number → reference on payment

Medium fixes:
- Dashboard: fix format() call on string time column
- Participant card: access person fields via relationship

Low fixes:
- daily-financial-print: createdBy → creator relationship
- reports-page: payment_method key → method

Infrastructure:
- Add migration for cash_session_id on payments table
- Add cash_session_id to Payment model fillable
- Fix float → decimal:2 casts on Evaluation/EvaluationScore
- Update enum registry docs to match actual DB CHECK constraints
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 8257dec7
......@@ -40,13 +40,13 @@ DB::statement("ALTER TABLE table_name ADD CONSTRAINT table_name_column_check
## Complete Enum Registry
### InvoiceStatus
`'draft', 'sent', 'partially_paid', 'paid', 'overdue', 'cancelled', 'refunded'`
`'draft', 'pending', 'awaiting_approval', 'sent', 'paid', 'partially_paid', 'overpaid', 'overdue', 'cancelled', 'refunded', 'partially_refunded', 'written_off', 'disputed'`
### PaymentStatus
`'confirmed', 'pending', 'failed', 'refunded', 'partially_refunded'`
`'pending', 'confirmed', 'failed', 'cancelled', 'refunded'`
### PaymentMethod
`'cash', 'card', 'bank_transfer', 'wallet', 'cheque', 'other'`
`'cash', 'card', 'bank_transfer', 'wallet', 'online', 'cheque', 'other'`
### TransactionType
`'debit', 'credit'`
......
......@@ -21,6 +21,7 @@ class Payment extends Model
protected $fillable = [
'academy_id',
'branch_id',
'cash_session_id',
'invoice_id',
'reference',
'direction',
......
......@@ -39,7 +39,7 @@ class Evaluation extends Model
'evaluation_date' => 'date',
'period_from' => 'date',
'period_to' => 'date',
'overall_score' => 'float',
'overall_score' => 'decimal:2',
'approved_at' => 'datetime',
'shared_at' => 'datetime',
'metadata' => 'array',
......
......@@ -17,7 +17,7 @@ class EvaluationScore extends Model
];
protected $casts = [
'score' => 'float',
'score' => 'decimal:2',
];
public function evaluation(): BelongsTo
......
......@@ -42,9 +42,9 @@ public function render()
$byMethod = Payment::where('status', 'confirmed')
->where('created_at', '>=', $startDate)
->select('payment_method', DB::raw('SUM(amount) as total'))
->groupBy('payment_method')
->pluck('total', 'payment_method')
->select('method', DB::raw('SUM(amount) as total'))
->groupBy('method')
->pluck('total', 'method')
->toArray();
return view('livewire.dashboard.revenue-widget', [
......
......@@ -57,7 +57,7 @@ private function calculateInstallments(): void
$invoice = Invoice::find($this->invoiceId);
if (!$invoice) return;
$remaining = $invoice->balance_due - ($this->downPayment * 100);
$remaining = $invoice->due_amount - ($this->downPayment * 100);
if ($remaining <= 0 || $this->installmentCount < 1) {
$this->installments = [];
return;
......@@ -95,22 +95,20 @@ public function save(): void
$plan = PaymentPlan::create([
'academy_id' => $invoice->academy_id,
'invoice_id' => $invoice->id,
'total_amount' => $invoice->balance_due,
'down_payment' => $this->downPayment * 100,
'installment_count' => $this->installmentCount,
'total_installments' => $this->installmentCount,
'paid_installments' => 0,
'installment_amount' => $this->installments[0]['amount'] ?? 0,
'frequency' => $this->frequency,
'start_date' => $this->startDate,
'next_due_date' => $this->installments[0]['due_date'] ?? $this->startDate,
'status' => 'active',
'created_by' => auth()->id(),
]);
foreach ($this->installments as $inst) {
$plan->installments()->create([
'academy_id' => $invoice->academy_id,
'installment_number' => $inst['number'],
'sequence' => $inst['number'],
'due_date' => $inst['due_date'],
'amount' => $inst['amount'],
'paid_amount' => 0,
'status' => 'pending',
]);
}
......@@ -124,7 +122,7 @@ public function render()
{
$invoice = $this->invoiceId ? Invoice::find($this->invoiceId) : null;
$invoices = Invoice::whereIn('status', ['sent', 'partially_paid', 'overdue'])
->where('balance_due', '>', 0)
->where('due_amount', '>', 0)
->orderByDesc('created_at')
->limit(50)
->get();
......
......@@ -56,13 +56,10 @@ public function search(): void
];
}
$invoices = Invoice::with('participant.person')
->when($branchId, fn ($query) => $query->where('branch_id', $branchId))
$invoices = Invoice::with('billable')
->where(function ($query) use ($q) {
$query->where('invoice_number', 'ilike', "%{$q}%")
->orWhereHas('participant.person', function ($pq) use ($q) {
$pq->where('name_ar', 'ilike', "%{$q}%");
});
$query->where('number', 'ilike', "%{$q}%")
->orWhere('contact_name', 'ilike', "%{$q}%");
})
->limit(3)
->get();
......@@ -70,8 +67,8 @@ public function search(): void
foreach ($invoices as $inv) {
$results[] = [
'type' => 'invoice',
'label' => $inv->invoice_number,
'subtitle' => ($inv->participant?->person?->name_ar ?? '') . ' — ' . number_format($inv->total_amount / 100, 2) . ' ج.م',
'label' => $inv->number,
'subtitle' => ($inv->contact_name ?? $inv->billable?->person?->name_ar ?? '') . ' — ' . number_format($inv->total_amount / 100, 2) . ' ج.م',
'url' => route('invoices.show', $inv),
];
}
......
......@@ -162,7 +162,7 @@ public function confirm(PaymentService $service): void
], auth()->user());
$this->completed = true;
$this->receipt_number = $payment->receipt_number ?? null;
$this->receipt_number = $payment->reference ?? null;
$this->last_payment_uuid = $payment->uuid;
$this->paid_amount = $amountPiasters;
$this->currentStep = 5;
......
......@@ -64,12 +64,12 @@ public function render()
->get();
$totalRevenue = $payments->sum('amount');
$paymentsByMethod = $payments->groupBy('payment_method')
$paymentsByMethod = $payments->groupBy('method')
->map(fn ($group) => $group->sum('amount'));
$invoices = Invoice::whereBetween('created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])->get();
$totalInvoiced = $invoices->sum('total_amount');
$totalOutstanding = $invoices->whereIn('status', ['sent', 'partially_paid', 'overdue'])->sum('balance_due');
$totalOutstanding = $invoices->whereIn('status', ['sent', 'partially_paid', 'overdue'])->sum('due_amount');
$overdueCount = $invoices->where('status', 'overdue')->count();
$dailyRevenue = Payment::where('status', 'confirmed')
......@@ -85,7 +85,7 @@ public function render()
->where('invoices.status', '!=', 'cancelled')
->whereBetween('invoices.created_at', [$this->dateFrom, $this->dateTo . ' 23:59:59'])
->whereNotNull('invoice_items.itemable_type')
->select('invoice_items.description', DB::raw('SUM(invoice_items.line_total) as revenue'), DB::raw('COUNT(*) as count'))
->select('invoice_items.description', DB::raw('SUM(invoice_items.total_amount) as revenue'), DB::raw('COUNT(*) as count'))
->groupBy('invoice_items.description')
->orderByDesc('revenue')
->limit(10)
......
<?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('payments', function (Blueprint $table) {
$table->foreignId('cash_session_id')->nullable()->after('branch_id')->constrained('cash_sessions')->nullOnDelete();
$table->index('cash_session_id');
});
}
public function down(): void
{
Schema::table('payments', function (Blueprint $table) {
$table->dropConstrainedForeignId('cash_session_id');
});
}
};
# Column Mismatch Fix Plan
Audited: 2026-07-01
Source of truth: Live PostgreSQL DB at 18.192.166.221 (elcaptainsportsonly)
Scope: 58 models, 50 migrations, 70+ views/components checked against 1142 live columns
---
## CRITICAL (SQL errors — pages crash)
### C1. GlobalSearch.php — Invoice query uses non-existent columns
**File:** `app/Livewire/GlobalSearch.php`
**Lines:** 59-73
**Bugs:**
- Line 60: `->where('branch_id', $branchId)``invoices` table has NO `branch_id`
- Line 62: `->where('invoice_number', 'like', ...)` — column is `number`, not `invoice_number`
- Line 59: `Invoice::with('participant.person')` — relationship is `billable`, not `participant`
- Line 73: `$invoice->invoice_number` — should be `$invoice->number`
**Fix:**
```php
// Remove branch_id filter (invoices don't have it), fix column name, fix relationship
Invoice::with('billable')
->where('number', 'like', "%{$this->query}%")
->orWhere('contact_name', 'like', "%{$this->query}%")
```
---
### C2. RevenueWidget.php — `payment_method` doesn't exist on `payments`
**File:** `app/Livewire/Dashboard/RevenueWidget.php`
**Lines:** 45-47
**Bug:** `->select('payment_method', ...)->groupBy('payment_method')` — column is `method`
**Fix:** Replace `payment_method` with `method` in select/groupBy
---
### C3. FinancialReport.php — Raw SQL references wrong columns
**File:** `app/Livewire/Reports/FinancialReport.php`
**Bugs:**
- Line 67: `$payments->groupBy('payment_method')` — should be `->groupBy('method')`
- Line 72: `balance_due` — should be `due_amount`
- Line 88: `SUM(invoice_items.line_total)` — should be `SUM(invoice_items.total_amount)`
**Fix:** Replace all three column names
---
### C4. PaymentPlanCreate.php — queries and writes non-existent columns
**File:** `app/Livewire/Financial/PaymentPlanCreate.php`
**Bugs:**
- Line 127: `->where('balance_due', '>', 0)` — should be `->where('due_amount', '>', 0)`
- Line 98: writes `total_amount` to payment_plans — doesn't exist
- Line 99: writes `down_payment` to payment_plans — doesn't exist
- Line 100: writes `installment_count` — should be `total_installments`
- Line 104: writes `created_by` to payment_plans — doesn't exist
- Line 109: writes `academy_id` to installments — doesn't exist
- Line 110: writes `installment_number` — should be `sequence`
- Line 112: writes `paid_amount` to installments — doesn't exist
**Fix:** Rewrite the `createPlan()` method to match actual schema:
```php
// payment_plans columns: invoice_id, academy_id, total_installments, paid_installments,
// installment_amount, frequency, start_date, next_due_date, status, notes, metadata
// installments columns: payment_plan_id, payment_id, sequence, amount, due_date, status, paid_at
```
---
## HIGH (Wrong data displayed — features broken but page loads)
### H1. `$invoice->invoice_number` used in 8 locations — should be `$invoice->number`
| File | Line(s) |
|------|---------|
| `resources/views/print/invoice.blade.php` | 5, 70 |
| `resources/views/livewire/dashboard.blade.php` | 197 |
| `resources/views/livewire/financial/payment-plan-create.blade.php` | 22 |
| `resources/views/livewire/receptionist/collect-payment-wizard.blade.php` | 179, 366 |
| `resources/views/reports/daily-financial-print.blade.php` | 76 |
| `app/Livewire/GlobalSearch.php` | 73 |
**Fix:** Find-replace `->invoice_number` with `->number` in all files
---
### H2. `$invoice->balance_due` used in 6 locations — should be `$invoice->due_amount`
| File | Line(s) |
|------|---------|
| `resources/views/print/invoice.blade.php` | 158 |
| `resources/views/livewire/financial/payment-plan-create.blade.php` | 22, 31 |
| `app/Livewire/Financial/PaymentPlanCreate.php` | 60, 98 |
| `app/Livewire/Reports/FinancialReport.php` | 72 |
**Fix:** Find-replace `->balance_due` with `->due_amount` and `'balance_due'` with `'due_amount'`
---
### H3. `$participant->full_name_ar` in 7 locations — accessor doesn't exist
The `getFullNameAttribute()` already returns Arabic name. There is no `getFullNameArAttribute()`.
| File | Line(s) |
|------|---------|
| `resources/views/print/certificate.blade.php` | 39 |
| `resources/views/print/participant-card.blade.php` | 5, 42, 46 |
| `resources/views/print/group-schedule.blade.php` | 86 |
| `resources/views/print/invoice.blade.php` | 85 |
| `resources/views/livewire/participants/bulk-status-change.blade.php` | 70, 92 |
**Fix:** Replace `->full_name_ar` with `->full_name`
---
### H4. `$payment->payment_method` in print view — column is `method`
**File:** `resources/views/print/invoice.blade.php` line 179
**Fix:** Replace `$payment->payment_method` with `$payment->method`
---
### H5. `$invoice->subtotal` — should be `$invoice->subtotal_amount`
**File:** `resources/views/print/invoice.blade.php` line 127
**Fix:** Replace `->subtotal` with `->subtotal_amount`
---
### H6. `$invoice->description` — should be `$invoice->notes`
**File:** `resources/views/livewire/receptionist/collect-payment-wizard.blade.php` line 180
**Fix:** Replace `->description` with `->notes`
---
### H7. `$item->line_total` in print view — should be `$item->total_amount`
**File:** `resources/views/print/invoice.blade.php` line 116
**Fix:** Replace `$item->line_total` with `$item->total_amount`
---
### H8. Reports page — `$method['payment_method']` key doesn't exist
**File:** `resources/views/livewire/reports/reports-page.blade.php` line 92
**Fix:** Replace `$method['payment_method']` with `$method['method']`
---
### H9. `$payment->receipt_number` — doesn't exist on payments table
**File:** `app/Livewire/Receptionist/CollectPaymentWizard.php` line 165
**Fix:** Remove or use `$payment->reference` (actual column) or derive from POS transaction
---
## MEDIUM (Type errors / wrong table access)
### M1. Dashboard calls `->format('H:i')` on a plain string
**File:** `resources/views/livewire/dashboard.blade.php` line 169
**Bug:** `$session->start_time?->format('H:i')` — start_time is a string, not Carbon
**Fix:** Use `\Carbon\Carbon::parse($session->start_time)->format('H:i')` or add cast to model
---
### M2. Participant card accesses person fields directly on participant
**File:** `resources/views/print/participant-card.blade.php` lines 54, 57, 60, 63
**Bug:** `$participant->date_of_birth`, `$participant->gender` — these are on `people` table
**Fix:** Use `$participant->person->date_of_birth` and `$participant->person->gender`
---
## LOW (Silent relationship failures)
### L1. Dashboard uses non-existent `$invoice->participant` relationship
**File:** `resources/views/livewire/dashboard.blade.php` line 197
**Bug:** `$inv->participant?->person?->name_ar` — relationship is `billable`
**Fix:** Use `$inv->billable?->person?->name_ar` or `$inv->contact_name`
---
### L2. Daily report uses `$payment->createdBy` — relationship is `creator`
**File:** `resources/views/reports/daily-financial-print.blade.php` line 77
**Fix:** Replace `$payment->createdBy` with `$payment->creator`
---
## MIGRATION NEEDED
### MIG1. Add `cash_session_id` to `payments` table
**Why:** Both `Payment::cashSession()` and `CashSession::payments()` reference this FK but it doesn't exist.
```php
Schema::table('payments', function (Blueprint $table) {
$table->foreignId('cash_session_id')->nullable()->after('branch_id')->constrained('cash_sessions')->nullOnDelete();
$table->index('cash_session_id');
});
```
Also add `'cash_session_id'` to Payment model `$fillable`.
---
## MODEL FIXES
### MOD1. Evaluation + EvaluationScore — float cast should be decimal
**Files:**
- `app/Domain/Training/Models/Evaluation.php` — change `'overall_score' => 'float'` to `'decimal:2'`
- `app/Domain/Training/Models/EvaluationScore.php` — change `'score' => 'float'` to `'decimal:2'`
---
### MOD2. Remove `Payment::cashSession()` relationship until migration runs
If migration MIG1 won't run immediately, the relationship should be commented out to prevent runtime errors.
---
## NAMING CONVENTION ISSUE (Non-breaking, future consideration)
### NAM1. `training_groups.program_id` should be `training_program_id`
Per project rules in `01-migration-first.md`. This is a rename that would require:
- Migration to rename column
- Update TrainingGroup model fillable + relationship
- Update all queries/views referencing `program_id`
- Risk: breaking change across many files
**Recommendation:** Low priority. Document as tech debt. The inconsistency works; fixing it mid-development risks introducing bugs.
---
## DOCUMENTATION DRIFT (Update rule files)
### DOC1. Enum registry in `16-enums-and-checks.md` is outdated
| Enum | Documented | Actual (migration) |
|------|-----------|-------------------|
| InvoiceStatus | 7 values | 13 values (add: pending, awaiting_approval, overpaid, partially_refunded, written_off, disputed) |
| PaymentStatus | 5 values | 5 values but different (has `cancelled` instead of `partially_refunded`) |
| PaymentMethod | 6 values | 7 values (add: `online`) |
**Fix:** Update `.claude/rules/16-enums-and-checks.md` to match actual migration values.
---
## EXECUTION ORDER
1. **C1-C4** — Fix critical SQL errors (pages literally crash)
2. **H1-H9** — Fix wrong column names (features show null/empty data)
3. **M1-M2** — Fix type errors and wrong table access
4. **L1-L2** — Fix silent relationship failures
5. **MIG1** — Add missing migration + update model fillable
6. **MOD1-MOD2** — Fix model casts
7. **DOC1** — Update rule file documentation
8. **NAM1** — Consider later (tech debt)
---
## STATS
| Category | Count |
|----------|-------|
| Files to modify | ~18 |
| Critical (crashes) | 4 issues |
| High (broken features) | 9 issues |
| Medium (conditional errors) | 2 issues |
| Low (silent failures) | 2 issues |
| Migrations needed | 1 |
| Model fixes | 2 |
| Doc updates | 1 |
| **Total fixes** | **21** |
......@@ -166,7 +166,7 @@
@foreach($todaySchedule as $session)
<div class="flex items-center gap-3 p-2.5 sm:p-3 bg-gray-50 rounded-lg">
<div class="text-center min-w-[44px]">
<span class="text-xs sm:text-sm font-bold text-blue-600" dir="ltr">{{ $session->start_time?->format('H:i') }}</span>
<span class="text-xs sm:text-sm font-bold text-blue-600" dir="ltr">{{ substr($session->start_time, 0, 5) }}</span>
</div>
<div class="flex-1 min-w-0">
<p class="text-xs sm:text-sm font-medium text-gray-800 truncate">{{ $session->group?->name_ar ?? '' }}</p>
......@@ -194,7 +194,7 @@
@foreach($overdueInvoices as $inv)
<a href="{{ route('invoices.show', $inv) }}" class="flex items-center justify-between p-2.5 sm:p-3 bg-red-50 rounded-lg hover:bg-red-100 transition-colors">
<div class="min-w-0 flex-1 me-2">
<p class="text-xs sm:text-sm font-medium text-gray-800 truncate">{{ $inv->participant?->person?->name_ar ?? $inv->invoice_number }}</p>
<p class="text-xs sm:text-sm font-medium text-gray-800 truncate">{{ $inv->contact_name ?? $inv->number }}</p>
<p class="text-xs text-red-600">{{ __('استحقاق:') }} {{ $inv->due_date?->format('Y-m-d') }}</p>
</div>
<span class="text-xs sm:text-sm font-bold text-red-700 whitespace-nowrap" dir="ltr">{{ number_format(($inv->total_amount - $inv->paid_amount) / 100, 2) }} {{ __('ج.م') }}</span>
......
......@@ -19,7 +19,7 @@
<option value="">{{ __('اختر فاتورة') }}</option>
@foreach($invoices as $inv)
<option value="{{ $inv->id }}">
{{ $inv->invoice_number }} — {{ format_money($inv->balance_due) }}
{{ $inv->number }} — {{ format_money($inv->due_amount) }}
</option>
@endforeach
</select>
......@@ -28,7 +28,7 @@
@if($invoice)
<div class="p-3 bg-blue-50 rounded-lg text-sm">
<p>{{ __('إجمالي الفاتورة') }}: <strong dir="ltr">{{ format_money($invoice->total_amount) }}</strong></p>
<p>{{ __('المتبقي') }}: <strong dir="ltr">{{ format_money($invoice->balance_due) }}</strong></p>
<p>{{ __('المتبقي') }}: <strong dir="ltr">{{ format_money($invoice->due_amount) }}</strong></p>
</div>
@endif
......
......@@ -67,7 +67,7 @@ class="w-full sm:w-auto px-4 py-2.5 text-sm bg-red-600 text-white rounded-lg hov
<input type="checkbox" wire:model="selectedIds" value="{{ $p->id }}"
class="w-4 h-4 text-blue-600 rounded border-gray-300">
</td>
<td class="px-4 py-3 text-sm text-gray-800">{{ $p->full_name_ar }}</td>
<td class="px-4 py-3 text-sm text-gray-800">{{ $p->full_name }}</td>
<td class="px-4 py-3">
<span class="px-2 py-0.5 text-xs rounded-full bg-gray-100 text-gray-600">{{ __($p->status) }}</span>
</td>
......@@ -89,7 +89,7 @@ class="w-4 h-4 text-blue-600 rounded border-gray-300">
<input type="checkbox" wire:model="selectedIds" value="{{ $p->id }}"
class="w-4 h-4 text-blue-600 rounded border-gray-300 shrink-0">
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-800 truncate">{{ $p->full_name_ar }}</p>
<p class="text-sm font-medium text-gray-800 truncate">{{ $p->full_name }}</p>
<div class="flex items-center gap-2 mt-1">
<span class="px-2 py-0.5 text-xs rounded-full bg-gray-100 text-gray-600">{{ __($p->status) }}</span>
<span class="text-xs text-gray-500" dir="ltr">{{ $p->created_at?->format('Y-m-d') }}</span>
......
......@@ -176,8 +176,8 @@ class="inline-flex items-center gap-2 px-6 py-3 min-h-16 bg-amber-600 text-white
hover:border-gray-300">
<div class="flex items-center justify-between">
<div>
<p class="font-bold text-gray-800">{{ $invoice->invoice_number }}</p>
<p class="text-sm text-gray-500 mt-1">{{ $invoice->description ?? __('فاتورة اشتراك') }}</p>
<p class="font-bold text-gray-800">{{ $invoice->number }}</p>
<p class="text-sm text-gray-500 mt-1">{{ $invoice->notes ?? __('فاتورة اشتراك') }}</p>
@if($invoice->due_date)
<p class="text-xs mt-1 {{ $invoice->due_date->isPast() ? 'text-red-600 font-medium' : 'text-gray-400' }}">
{{ __('تاريخ الاستحقاق') }}: <span dir="ltr">{{ $invoice->due_date->format('Y-m-d') }}</span>
......@@ -363,7 +363,7 @@ class="inline-flex items-center gap-2 px-6 py-3 min-h-16 bg-amber-600 text-white
@if($selectedInvoice)
<div class="flex items-center justify-between">
<span class="text-gray-600">{{ __('رقم الفاتورة') }}</span>
<span class="font-medium text-gray-800" dir="ltr">{{ $selectedInvoice->invoice_number }}</span>
<span class="font-medium text-gray-800" dir="ltr">{{ $selectedInvoice->number }}</span>
</div>
@endif
<div class="flex items-center justify-between">
......
......@@ -89,7 +89,7 @@ class="w-full rounded-lg border-gray-300 shadow-sm focus:border-indigo-500 focus
<tbody class="divide-y divide-gray-200">
@foreach($reportData['payment_methods'] as $method)
<tr>
<td class="px-4 py-3 text-sm text-gray-800">{{ __($method['payment_method'] ?? '-') }}</td>
<td class="px-4 py-3 text-sm text-gray-800">{{ __($method['method'] ?? '-') }}</td>
<td class="px-4 py-3 text-sm text-gray-800" dir="ltr">{{ number_format(($method['total'] ?? 0) / 100, 2) }} {{ __('ج.م') }}</td>
<td class="px-4 py-3 text-sm text-gray-800" dir="ltr">{{ number_format($method['count'] ?? 0) }}</td>
</tr>
......
......@@ -36,7 +36,7 @@
<h1>{{ __('شهادة حضور') }}</h1>
<p class="subtitle">{{ __('تشهد الأكاديمية بأن') }}</p>
<p class="recipient">{{ $participant->full_name_ar }}</p>
<p class="recipient">{{ $participant->full_name }}</p>
<div class="details">
<p>{{ __('قد أتم بنجاح حضور برنامج') }}</p>
......
......@@ -83,7 +83,7 @@
@foreach($group->enrollments as $i => $enrollment)
<tr>
<td>{{ $i + 1 }}</td>
<td>{{ $enrollment->participant?->full_name_ar ?? '-' }}</td>
<td>{{ $enrollment->participant?->full_name ?? '-' }}</td>
<td dir="ltr">{{ $enrollment->created_at?->format('Y-m-d') }}</td>
</tr>
@endforeach
......
......@@ -2,7 +2,7 @@
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8">
<title>{{ __('فاتورة') }} - {{ $invoice->invoice_number }}</title>
<title>{{ __('فاتورة') }} - {{ $invoice->number }}</title>
@php
$branding = app(\App\Domain\Shared\Services\SettingsService::class);
$brandLogo = $branding->get('branding.logo');
......@@ -67,7 +67,7 @@
</div>
</div>
<div class="meta">
<p><strong>{{ __('رقم الفاتورة') }}:</strong> {{ $invoice->invoice_number }}</p>
<p><strong>{{ __('رقم الفاتورة') }}:</strong> {{ $invoice->number }}</p>
<p><strong>{{ __('التاريخ') }}:</strong> {{ $invoice->issue_date ?? $invoice->created_at?->format('Y-m-d') }}</p>
@if($invoice->due_date)
<p><strong>{{ __('تاريخ الاستحقاق') }}:</strong> {{ $invoice->due_date }}</p>
......@@ -82,7 +82,7 @@
<div class="party">
<h3>{{ __('العميل') }}</h3>
@if($invoice->billable)
<p><strong>{{ $invoice->billable->full_name_ar ?? $invoice->billable->name_ar ?? '-' }}</strong></p>
<p><strong>{{ $invoice->billable->full_name ?? $invoice->billable->name_ar ?? '-' }}</strong></p>
@if($invoice->billable->phone ?? null)
<p dir="ltr">{{ $invoice->billable->phone }}</p>
@endif
......@@ -113,7 +113,7 @@
<td>{{ $item->description }}</td>
<td>{{ $item->quantity }}</td>
<td dir="ltr">{{ format_money($item->unit_price) }}</td>
<td dir="ltr">{{ format_money($item->line_total) }}</td>
<td dir="ltr">{{ format_money($item->total_amount) }}</td>
</tr>
@empty
<tr><td colspan="5" style="text-align: center; color: #999;">{{ __('لا توجد بنود') }}</td></tr>
......@@ -124,7 +124,7 @@
<div class="totals">
<div class="row">
<span>{{ __('المجموع الفرعي') }}</span>
<span dir="ltr">{{ format_money($invoice->subtotal ?? $invoice->total_amount) }}</span>
<span dir="ltr">{{ format_money($invoice->subtotal_amount ?? $invoice->total_amount) }}</span>
</div>
@if($invoice->discount_amount > 0)
<div class="row">
......@@ -155,7 +155,7 @@
</div>
<div class="row" style="font-weight: bold; color: #dc2626;">
<span>{{ __('المتبقي') }}</span>
<span dir="ltr">{{ format_money($invoice->balance_due) }}</span>
<span dir="ltr">{{ format_money($invoice->due_amount) }}</span>
</div>
@endif
</div>
......@@ -176,7 +176,7 @@
@foreach($invoice->payments as $payment)
<tr>
<td dir="ltr">{{ $payment->created_at?->format('Y-m-d') }}</td>
<td>{{ __($payment->payment_method) }}</td>
<td>{{ __($payment->method) }}</td>
<td dir="ltr">{{ format_money($payment->amount) }}</td>
<td>{{ __($payment->status) }}</td>
</tr>
......
......@@ -2,7 +2,7 @@
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8">
<title>{{ __('بطاقة عضوية') }} - {{ $participant->full_name_ar }}</title>
<title>{{ __('بطاقة عضوية') }} - {{ $participant->full_name }}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Cairo', 'Noto Sans Arabic', sans-serif; direction: rtl; padding: 40px; background: #f5f5f5; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
......@@ -39,11 +39,11 @@
</div>
<div class="avatar">
{{ mb_substr($participant->full_name_ar ?? $participant->full_name ?? '?', 0, 1) }}
{{ mb_substr($participant->full_name ?? '?', 0, 1) }}
</div>
<div class="card-body">
<p class="name">{{ $participant->full_name_ar }}</p>
<p class="name">{{ $participant->full_name }}</p>
<span class="id-badge">{{ $participant->uuid ?? "#{$participant->id}" }}</span>
<div style="text-align: right; margin-top: 12px;">
......@@ -51,16 +51,16 @@
<label>{{ __('الحالة') }}</label>
<span>{{ __($participant->status) }}</span>
</div>
@if($participant->date_of_birth)
@if($participant->person?->date_of_birth)
<div class="info-row">
<label>{{ __('تاريخ الميلاد') }}</label>
<span dir="ltr">{{ $participant->date_of_birth }}</span>
<span dir="ltr">{{ $participant->person?->date_of_birth }}</span>
</div>
@endif
@if($participant->gender)
@if($participant->person?->gender)
<div class="info-row">
<label>{{ __('النوع') }}</label>
<span>{{ $participant->gender === 'male' ? __('ذكر') : __('أنثى') }}</span>
<span>{{ $participant->person?->gender === 'male' ? __('ذكر') : __('أنثى') }}</span>
</div>
@endif
</div>
......
......@@ -73,8 +73,8 @@
<td>{{ $payment->reference ?? '-' }}</td>
<td class="ltr">{{ number_format($payment->amount / 100, 2) }}</td>
<td>{{ $payment->method?->value ?? '' }}</td>
<td>{{ $payment->invoice?->invoice_number ?? '-' }}</td>
<td>{{ $payment->createdBy?->name ?? '' }}</td>
<td>{{ $payment->invoice?->number ?? '-' }}</td>
<td>{{ $payment->creator?->name ?? '' }}</td>
</tr>
@endforeach
<tr class="total-row">
......
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