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

Fix Livewire 4 computed properties: replace get*Property with #[Computed]

Livewire 4 dropped support for the legacy get*Property() magic accessor.
Migrated all 6 affected components to use the #[Computed] attribute:
- NewRegistrationWizard (hotbuyResults, hotbuyTotal, selectedProgram, etc.)
- WeeklySchedule (weekDays, timeSlots)
- InvoiceCreate (subtotal, total)
- InvoiceShow (canCancel, canRecordPayment)
- SystemSettings (activeSchema)
- NotificationTemplateForm (availableVariables)
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent cd3314dd
......@@ -4,6 +4,7 @@
use App\Domain\Shared\Models\SystemSetting;
use App\Domain\Shared\Services\SettingsService;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
......@@ -201,7 +202,8 @@ public function save(SettingsService $service): void
session()->flash('success', __('تم حفظ الإعدادات بنجاح'));
}
public function getActiveSchemaProperty(): array
#[Computed]
public function activeSchema(): array
{
return $this->settingsSchema[$this->activeTab] ?? [];
}
......
......@@ -5,6 +5,7 @@
use App\Domain\Financial\Services\InvoiceService;
use App\Domain\Participant\Models\Participant;
use App\Domain\Shared\Exceptions\DomainException;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
......@@ -127,12 +128,14 @@ public function save(InvoiceService $service): void
}
}
public function getSubtotalProperty(): float
#[Computed]
public function subtotal(): float
{
return collect($this->items)->sum(fn ($item) => ($item['quantity'] ?? 0) * ($item['unit_price'] ?? 0));
}
public function getTotalProperty(): float
#[Computed]
public function total(): float
{
return $this->subtotal - $this->discount_amount + $this->tax_amount;
}
......
......@@ -8,6 +8,7 @@
use App\Domain\Financial\Services\InvoiceService;
use App\Domain\Financial\Services\PaymentService;
use App\Domain\Shared\Exceptions\DomainException;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
......@@ -95,13 +96,15 @@ public function cancelInvoice(InvoiceService $service): void
}
}
public function getCanCancelProperty(): bool
#[Computed]
public function canCancel(): bool
{
return in_array($this->invoice->status, [InvoiceStatus::Draft, InvoiceStatus::Sent])
&& $this->invoice->paid_amount === 0;
}
public function getCanRecordPaymentProperty(): bool
#[Computed]
public function canRecordPayment(): bool
{
return $this->invoice->due_amount > 0
&& !in_array($this->invoice->status, [InvoiceStatus::Cancelled, InvoiceStatus::Refunded]);
......
......@@ -4,6 +4,7 @@
use App\Domain\Notification\Enums\NotificationChannel;
use App\Domain\Notification\Models\NotificationTemplate;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
......@@ -133,7 +134,8 @@ public function save(): void
$this->redirect(route('notifications.templates'), navigate: true);
}
public function getAvailableVariablesProperty(): array
#[Computed]
public function availableVariables(): array
{
return $this->eventVariables[$this->event_type] ?? [];
}
......
......@@ -9,6 +9,8 @@
use App\Domain\Identity\Models\Guardian;
use App\Domain\Identity\Models\Person;
use App\Domain\Identity\Services\PersonService;
use App\Domain\Inventory\Models\Kit;
use App\Domain\Inventory\Models\Product;
use App\Domain\Participant\Models\Participant;
use App\Domain\Participant\Services\DuplicateDetectionService;
use App\Domain\Participant\Services\ParticipantService;
......@@ -20,6 +22,7 @@
use App\Domain\Training\Models\TrainingProgram;
use App\Domain\Training\Services\EnrollmentService;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
......@@ -77,6 +80,10 @@ class NewRegistrationWizard extends Component
public ?string $invoice_uuid = null;
public bool $payment_recorded = false;
// Hot-buy items (optional products/kits sold alongside registration)
public string $hotbuy_search = '';
public array $hotbuyCart = [];
// Pre-flight errors — blocks wizard from starting
public array $systemErrors = [];
......@@ -278,6 +285,100 @@ public function updatedSelectedActivityId(): void
$this->selected_program_id = null;
}
// --- Hot-buy methods ---
#[Computed]
public function hotbuyResults(): array
{
if (strlen($this->hotbuy_search) < 2) {
return [];
}
$search = $this->hotbuy_search;
$products = Product::where('is_active', true)
->where(fn ($q) => $q->where('name_ar', 'ilike', "%{$search}%")
->orWhere('name', 'ilike', "%{$search}%")
->orWhere('sku', 'ilike', "%{$search}%")
->orWhere('barcode', $search))
->limit(5)
->get()
->map(fn ($p) => [
'id' => $p->id,
'type' => 'product',
'name_ar' => $p->name_ar,
'name' => $p->name,
'sku' => $p->sku,
'price' => $p->selling_price,
])->toArray();
$kits = Kit::where('is_active', true)
->where(fn ($q) => $q->where('name_ar', 'ilike', "%{$search}%")
->orWhere('name', 'ilike', "%{$search}%")
->orWhere('sku', 'ilike', "%{$search}%"))
->limit(5)
->get()
->map(fn ($k) => [
'id' => $k->id,
'type' => 'kit',
'name_ar' => $k->name_ar,
'name' => $k->name,
'sku' => $k->sku,
'price' => $k->selling_price,
])->toArray();
return array_merge($products, $kits);
}
public function addHotbuyItem(int $id, string $type): void
{
$key = "{$type}_{$id}";
if (isset($this->hotbuyCart[$key])) {
$this->hotbuyCart[$key]['quantity']++;
} else {
$item = $type === 'product'
? Product::find($id)
: Kit::find($id);
if (!$item) {
return;
}
$this->hotbuyCart[$key] = [
'id' => $item->id,
'type' => $type,
'name_ar' => $item->name_ar,
'price' => $item->selling_price,
'quantity' => 1,
];
}
$this->hotbuy_search = '';
}
public function removeHotbuyItem(string $key): void
{
unset($this->hotbuyCart[$key]);
}
public function updateHotbuyQuantity(string $key, int $quantity): void
{
if ($quantity <= 0) {
unset($this->hotbuyCart[$key]);
return;
}
if (isset($this->hotbuyCart[$key])) {
$this->hotbuyCart[$key]['quantity'] = $quantity;
}
}
#[Computed]
public function hotbuyTotal(): int
{
return collect($this->hotbuyCart)->sum(fn ($item) => $item['price'] * $item['quantity']);
}
public function confirm(): void
{
try {
......@@ -356,15 +457,40 @@ public function confirm(): void
$actor
);
// 7. Look up the price for this program + calculate platform fee
// 7. Look up the price for this program + calculate platform fee + hot-buy
$feeAmount = $this->resolveProgramFee($program);
$hotbuyTotal = $this->hotbuyTotal;
$subtotal = $feeAmount + $hotbuyTotal;
$platformFeeService = app(PlatformFeeService::class);
$serviceFee = $platformFeeService->calculate($feeAmount);
$totalWithFee = $feeAmount + $serviceFee;
$customerPays = $platformFeeService->customerPays();
$serviceFee = $customerPays ? $platformFeeService->calculate($subtotal) : 0;
$totalWithFee = $subtotal + $serviceFee;
// 8. Create invoice if there's a fee
// 8. Create invoice if there's a fee or hot-buy items
$invoice = null;
if ($feeAmount > 0) {
if ($subtotal > 0) {
$invoiceItems = [];
if ($feeAmount > 0) {
$invoiceItems[] = [
'description' => $program->name_ar,
'quantity' => 1,
'unit_price' => $feeAmount,
'discount_amount' => 0,
'tax_amount' => 0,
];
}
foreach ($this->hotbuyCart as $cartItem) {
$invoiceItems[] = [
'description' => $cartItem['name_ar'],
'quantity' => $cartItem['quantity'],
'unit_price' => $cartItem['price'],
'discount_amount' => 0,
'tax_amount' => 0,
];
}
$invoice = $invoiceService->create([
'academy_id' => app('current_academy')->id,
'number' => $invoiceService->generateNumber(app('current_academy')->id),
......@@ -373,7 +499,7 @@ public function confirm(): void
'billable_id' => $participant->id,
'contact_name' => $this->guardian_name_ar,
'contact_phone' => $this->guardian_phone,
'subtotal_amount' => $feeAmount,
'subtotal_amount' => $subtotal,
'discount_amount' => 0,
'tax_amount' => 0,
'service_fee_amount' => $serviceFee,
......@@ -382,15 +508,7 @@ public function confirm(): void
'issue_date' => now()->toDateString(),
'due_date' => now()->addDays(7)->toDateString(),
'notes' => 'اشتراك: ' . $program->name_ar,
], [
[
'description' => $program->name_ar,
'quantity' => 1,
'unit_price' => $feeAmount,
'discount_amount' => 0,
'tax_amount' => 0,
],
], $actor);
], $invoiceItems, $actor);
// Send the invoice (mark as sent)
$invoice->update(['status' => 'sent']);
......@@ -474,7 +592,8 @@ private function resolveProgramFee(TrainingProgram $program): int
return $genericPrice?->amount ?? 0;
}
public function getSelectedProgramProperty(): ?TrainingProgram
#[Computed]
public function selectedProgram(): ?TrainingProgram
{
if (!$this->selected_program_id) {
return null;
......@@ -483,7 +602,8 @@ public function getSelectedProgramProperty(): ?TrainingProgram
return TrainingProgram::with('activity')->find($this->selected_program_id);
}
public function getSelectedProgramFeeProperty(): int
#[Computed]
public function selectedProgramFee(): int
{
if (!$this->selected_program_id) {
return 0;
......@@ -493,17 +613,25 @@ public function getSelectedProgramFeeProperty(): int
return $program ? $this->resolveProgramFee($program) : 0;
}
public function getPlatformFeeProperty(): int
#[Computed]
public function platformFee(): int
{
return app(PlatformFeeService::class)->calculate($this->selectedProgramFee);
$service = app(PlatformFeeService::class);
if (!$service->customerPays()) {
return 0;
}
$subtotal = $this->selectedProgramFee + $this->hotbuyTotal;
return $service->calculate($subtotal);
}
public function getTotalWithFeeProperty(): int
#[Computed]
public function totalWithFee(): int
{
return $this->selectedProgramFee + $this->platformFee;
return $this->selectedProgramFee + $this->hotbuyTotal + $this->platformFee;
}
public function getInvoiceForPrintProperty(): ?Invoice
#[Computed]
public function invoiceForPrint(): ?Invoice
{
if (!$this->invoiceId) {
return null;
......
......@@ -8,6 +8,7 @@
use App\Models\User;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
......@@ -52,7 +53,8 @@ public function goToToday(): void
$this->weekStart = $today->startOfWeek(Carbon::SATURDAY)->format('Y-m-d');
}
public function getWeekDaysProperty(): array
#[Computed]
public function weekDays(): array
{
$start = Carbon::parse($this->weekStart);
$days = [];
......@@ -79,7 +81,8 @@ public function getWeekDaysProperty(): array
return $days;
}
public function getTimeSlotsProperty(): array
#[Computed]
public function timeSlots(): array
{
$slots = [];
for ($hour = 8; $hour <= 22; $hour++) {
......
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