Files
Vasyka 09fd0bada2 Faza 2 (din continuare): Email notifications
4 Mailables auto-trigger pe model events:
- WorkOrderReadyMail: la WO.status → 'ready', către client.email
  • Atașat PDF fișa lucru (via WorkOrderPdfService)
  • Total/achitat/rest, recomandări (warning box)
- PaymentReceivedMail: la Payment::created, confirmare cu sumă/metodă/ref
- AppointmentConfirmedMail: la Appointment::created status='scheduled'
- ServiceReminderMail: dispatch manual (vehicle, type=itp/oil/general, note)

Layout email branded (resources/views/emails/layout.blade.php):
- Header cu logo tenant + theme_color border-bottom
- Footer cu telefon/email/disclaimer
- Stiluri inline (compatibil tot mail client)

Settings page extins cu 4 toggle:
- 'Mașina e gata de ridicat'
- 'Confirmare plată primită'
- 'Programare confirmată'
- 'Reminder ITP / revizie'
Salvate în companies.settings.notify (JSON), default true.

NotificationDispatcher service centralizat:
- Verifică isEnabled() pe settings.notify[$key]
- Skip dacă client n-are email
- Try/catch + Log::warning pe eșec (nu crapă request-ul)

Mailables folosesc UsesTenantBranding trait pentru context unitar.
Test prin Mailpit: https://mailpit.service.mir.md (capturează toate).
2026-05-07 13:20:19 +00:00

66 lines
1.5 KiB
PHP

<?php
namespace App\Models\Tenant;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Appointment extends Model
{
use BelongsToTenant;
public const STATUSES = [
'scheduled' => 'Programat',
'arrived' => 'Sosit',
'done' => 'Finalizat',
'cancelled' => 'Anulat',
'no_show' => 'Neprezentat',
];
protected $fillable = [
'company_id', 'post_id', 'client_id', 'vehicle_id', 'master_id', 'deal_id',
'date', 'time_start', 'time_end',
'title', 'color', 'status', 'notes',
];
protected $casts = [
'date' => 'date',
];
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
public function client(): BelongsTo
{
return $this->belongsTo(Client::class);
}
public function vehicle(): BelongsTo
{
return $this->belongsTo(Vehicle::class);
}
public function master(): BelongsTo
{
return $this->belongsTo(User::class, 'master_id');
}
public function deal(): BelongsTo
{
return $this->belongsTo(Deal::class);
}
/** Auto-send confirmation email when a 'scheduled' appointment is created. */
protected static function booted(): void
{
static::created(function (self $a) {
if ($a->status === 'scheduled') {
app(\App\Services\NotificationDispatcher::class)->appointmentConfirmed($a);
}
});
}
}