@php /** * TEDARİKÇİ KARTI — sabit quick-view "defter" (ledger) tasarımı. * * Alanlar iki eksende değişir: * type bireysel → Ad/Soyad · kurumsal → Firma unvanı + vergi bilgileri * supplier_type otel ise "Otel Bilgi Formu" sekmesi açılır * * Tip değişince başlık, sekme kümesi ve alan kümesi birden değiştiği için * satır kaydedildikten sonra çekmece yeniden yüklenir (dosya sonundaki * pfx:saved dinleyicisi). Bu yüzden tipe bağlı satırlar sunucuda süzülür. * * Kaydetme: PATCH agency.suppliers.update-field {field, value} */ $uf = route('agency.suppliers.update-field', $supplier); $isCorp = $supplier->type === 'corporate'; $statusOptions = [ ['value' => 'active', 'label' => 'Aktif'], ['value' => 'inactive', 'label' => 'Pasif'], ['value' => 'blocked', 'label' => 'Engelli'], ['value' => 'potential', 'label' => 'Potansiyel'], ]; $typeOptions = [ ['value' => 'individual', 'label' => 'Bireysel'], ['value' => 'corporate', 'label' => 'Kurumsal'], ]; /** Tek satır tanımı — müşteri künyesiyle aynı sözleşme. */ $row = function (string $label, ?string $field, $value, ?string $text = null, array $o = []) { return [ 'label' => $label, 'field' => $field, 'type' => $o['type'] ?? 'text', 'value' => $value === null ? '' : (string) $value, 'text' => $text === null ? ($value === null ? '' : (string) $value) : $text, 'options' => $o['options'] ?? null, 'lookup' => $o['lookup'] ?? null, 'mono' => $o['mono'] ?? false, 'ph' => $o['ph'] ?? null, 'url' => $o['url'] ?? null, ]; }; // Çoklu değerler tek satırda virgülle düzenlenir (uç, string'i diziye çevirir) $emailsText = is_array($supplier->emails) ? implode(', ', $supplier->emails) : (string) ($supplier->emails ?? ''); $phonesText = is_array($supplier->phones) ? implode(', ', $supplier->phones) : (string) ($supplier->phones ?? ''); // ── Kimlik / Firma: tipe göre TEK bölüm ── $identitySection = $isCorp ? [ 'title' => 'Firma', 'icon' => 'fa-building', 'rows' => [ $row('Unvan', 'company_name', $supplier->company_name, null, ['ph' => 'Firma unvanı']), $row('Vergi No', 'company_tax_number', $supplier->company_tax_number, null, ['mono' => true, 'ph' => '10 hane']), $row('Vergi Dairesi', 'company_tax_office', $supplier->company_tax_office), ], ] : [ 'title' => 'Kimlik', 'icon' => 'fa-id-badge', 'rows' => [ $row('Ad', 'first_name', $supplier->first_name), $row('Soyad', 'last_name', $supplier->last_name), $row('Ad Soyad', null, $supplier->full_name), ], ]; $contactSection = [ 'title' => 'İletişim', 'icon' => 'fa-address-book', 'rows' => [ $row('Telefon', 'phone', $supplier->phone, null, ['mono' => true]), $row('Diğer Telefonlar', 'phones', $phonesText, $phonesText, ['mono' => true, 'ph' => 'Virgülle ayırın']), $row('E-postalar', 'emails', $emailsText, $emailsText, ['type' => 'email', 'ph' => 'Virgülle ayırın']), ], ]; $addressSection = [ 'title' => 'Adres', 'icon' => 'fa-location-dot', 'rows' => [ // Sütun iki karakterlik ISO kodu tutar; kullanıcı ülke adıyla arar $row('Ülke', 'country', $supplier->country, \App\Models\Definition\Country::nameByCode($supplier->country), ['type' => 'lookup', 'lookup' => 'countries', 'ph' => 'Ülke arayın']), $row('İl', 'city', $supplier->city), $row('İlçe', 'district', $supplier->district), $row('Posta Kodu', 'postal_code', $supplier->postal_code, null, ['mono' => true]), $row('Açık Adres', 'address', $supplier->address, null, ['type' => 'textarea']), ], ]; $profileSection = [ 'title' => 'Profil', 'icon' => 'fa-user-gear', 'rows' => [ $row('Tedarikçi Tipi', 'type', $supplier->type, $isCorp ? 'Kurumsal' : 'Bireysel', ['type' => 'select', 'options' => $typeOptions]), $row('Durum', 'status', $supplier->status, $supplier->status_label, ['type' => 'select', 'options' => $statusOptions]), $row('Birincil Hizmet', null, $supplier->supplier_type_label), ], ]; // ── Fatura & resmî bilgiler (Firma & Fatura sekmesi) ── $billingSection = [ 'title' => 'Fatura Bilgileri', 'icon' => 'fa-file-invoice-dollar', 'rows' => [ $row('Fatura Vergi No', 'billing_tax_number', $supplier->billing_tax_number, null, ['mono' => true]), $row('Fatura Vergi Dairesi', 'billing_tax_office', $supplier->billing_tax_office), $row('Fatura E-posta', 'billing_email', $supplier->billing_email, null, ['type' => 'email']), $row('Fatura İl', 'billing_city', $supplier->billing_city), $row('Fatura İlçe', 'billing_district', $supplier->billing_district), $row('Fatura Adresi', 'billing_address', $supplier->billing_address, null, ['type' => 'textarea']), ], ]; $officialSection = $isCorp ? [ 'title' => 'Resmî Bilgiler', 'icon' => 'fa-stamp', 'rows' => [ $row('Ticari Unvan', 'company_name', $supplier->company_name), $row('VKN', 'company_tax_number', $supplier->company_tax_number, null, ['mono' => true, 'ph' => '10 hane']), $row('Vergi Dairesi', 'company_tax_office', $supplier->company_tax_office), ], ] : [ 'title' => 'Resmî Bilgiler', 'icon' => 'fa-stamp', 'rows' => [ $row('Ad Soyad', null, $supplier->full_name), $row('TCKN / Vergi No', 'billing_tax_number', $supplier->billing_tax_number, null, ['mono' => true, 'ph' => '11 hane']), ], ]; $systemSection = [ 'title' => 'Sistem', 'icon' => 'fa-clock-rotate-left', 'muted' => true, 'rows' => [ $row('Kayıt No', null, '#' . $supplier->code, '#' . $supplier->code, ['mono' => true]), $row('Hizmet Tipleri', null, implode(', ', $supplier->type_labels)), $row('Oluşturulma', null, $supplier->created_at?->format('d.m.Y H:i')), $row('Son Güncelleme', null, $supplier->updated_at?->format('d.m.Y H:i')), ], ]; // Faturaya kopyalanacak blok (tek tuşla panoya) $billingBlock = trim(implode(PHP_EOL, array_filter([ filled($supplier->company_name) ? 'Unvan: ' . $supplier->company_name : (filled($supplier->full_name) ? 'Unvan: ' . $supplier->full_name : null), filled($supplier->company_tax_number) ? 'VKN: ' . $supplier->company_tax_number : null, filled($supplier->company_tax_office) ? 'Vergi Dairesi: ' . $supplier->company_tax_office : null, filled($supplier->billing_tax_number) ? 'Fatura Vergi No: ' . $supplier->billing_tax_number : null, filled($supplier->billing_tax_office) ? 'Fatura Vergi Dairesi: ' . $supplier->billing_tax_office : null, filled($supplier->billing_email) ? 'Fatura E-posta: ' . $supplier->billing_email : null, filled($supplier->billing_address) ? 'Fatura Adresi: ' . trim($supplier->billing_address . ' ' . $supplier->billing_district . ' ' . $supplier->billing_city) : null, ]))); @endphp {{-- slim: avatar yok, başlık + rozetler tek şeritte (sabit QV tasarımı) --}} @if($isCorp) {{-- Kurumsalda başlık = company_name kolonunun ta kendisi → düzenlenebilir --}} @else {{-- Bireyselde başlık ad+soyaddan TÜRETİLİR; tek alana yazmak veriyi bozardı. Ad ve soyad künyedeki "Kimlik" satırlarından ayrı ayrı düzenlenir. --}} {{ $supplier->first_name }} {{ $supplier->last_name }} @endif {{-- Header'da avatar yok (slim); yığın tutamağı baş harfleri buradan okur --}} {{-- Durum rozeti: ortak pil menüsü --}} {{ $supplier->status_label }} #{{ $supplier->code }} {{ $isCorp ? 'Kurumsal' : 'Bireysel' }} @foreach($supplier->type_labels as $tlabel) {{ $tlabel }} @endforeach
FİYAT LİSTELERİ {{ $supplier->priceLists->count() }} Sezon
KAYNAKLAR {{ $supplier->resources->count() }}
YETKİLİLER {{ $supplier->responsibles->count() }}
@if($supplier->supplier_type === 'hotel') @endif
{{-- Etkinlik solda, künye sağda; dar ekranda künye öne gelir --}}
{{-- Etkinlik yazma alanı: künye paneliyle aynı dil. Tür seçimi tek satır çip şeridi, gövde tek odak kutusu. --}}
@csrf
{{-- Açıklama zengin metin: eski kayıtlar HTML tuttuğu için Quill korunuyor --}}
{{-- Etkinlik akışı: ince ray, tür rengiyle işaretli nokta. Postaların ayrı sekmesi yoktur: Mail modülünden bu tedarikçiyle ilişkilendirilmiş gelen/giden iletiler notlarla aynı akışta görünür ve satırın altında okunur. --}} @php $mailLinks = app(\App\Services\Mail\MailLinkService::class); // Gönderici tanıma senkron anında çalışır; özellik açılmadan önce // inmiş ya da kart yazışmadan sonra açılmışsa geçmiş postalar // bağsız kalır. Kart her açıldığında bir kez taranıp tamamlanır. // Yetkililerin adresleri de kuruma sayılır — otelin rezervasyon // sorumlusundan gelen posta o otelin akışına aittir. $mailLinks->backfillForRecord( $supplier, array_merge( $mailLinks->addressesOf($supplier), $supplier->responsibles->pluck('email')->filter()->all() ) ); $supplierMails = $mailLinks->messagesFor( $supplier, $mailLinks->accountIds((int) $supplier->agency_id, (int) auth()->id()), 50 ); $supplierFeed = $recentActivities ->map(fn ($a) => ['kind' => 'activity', 'at' => $a->activity_date, 'item' => $a]) ->concat($supplierMails->map(fn ($m) => ['kind' => 'mail', 'at' => $m->date_at, 'item' => $m])) ->filter(fn ($e) => $e['at'] !== null) ->sortByDesc(fn ($e) => $e['at']->getTimestamp()) ->values(); @endphp
Etkinlik Akışı {{-- Sayaçlar rozet (flw-stat) — müşteri/operasyon akışıyla aynı dil --}} {{ $supplierFeed->count() }} kayıt @if($supplierMails->isNotEmpty()) {{ $supplierMails->count() }} yazışma @endif
@forelse($supplierFeed as $entry) @if($entry['kind'] === 'mail') @include('components.quick-view.mail-flow-row', [ 'mail' => $entry['item'], 'linkId' => $entry['item']->mail_link_id, 'linkAuto' => (bool) $entry['item']->mail_link_auto, 'linkLabel' => $entry['item']->mail_link_auto ? 'Zincirden' : 'İlişkilendirildi', 'detachable' => false, ]) @continue @endif @php $activity = $entry['item']; @endphp @php $icon = match($activity->activity_type) { 'call' => 'phone', 'email' => 'envelope', 'meeting' => 'handshake', 'note' => 'sticky-note', 'whatsapp' => 'whatsapp', 'sms' => 'comment-sms', default => 'circle-dot' }; $color = match($activity->activity_type) { 'call' => '#3b82f6', 'email' => '#ec4899', 'meeting' => '#10b981', 'note' => '#f59e0b', 'whatsapp' => '#22c55e', 'sms' => '#8b5cf6', default => '#64748b' }; $isBrandIcon = $activity->activity_type === 'whatsapp'; @endphp
{{ $activity->activity_type_label }} @if($activity->priority === 'urgent') Acil @endif
@if($activity->subject)
{{ $activity->subject }}
@endif @if($activity->description) {{-- Zengin metin: akış satırında kırpılmış gösterilir --}}
{!! $activity->description !!}
@endif
{{ $activity->performedBy?->first_name ?: 'Sistem' }}
@empty Yukarıdaki kutudan not, arama veya görüşme kaydı ekleyin; Mail modülünden bir yazışmayı bu tedarikçiyle ilişkilendirirseniz o da burada görünür. @endforelse
{{-- Akıştaki posta satırlarının stili ve satır içi okuyucusu --}} @include('components.quick-view.mail-ui') @include('components.quick-view.mail-reader')
{{-- Künye: profilin tamamı tek defterde. Ayrı "Künye" sekmesi yoktur; tipe bağlı bölüm (Kimlik ↔ Firma) sunucuda seçilir. --}}
@include('components.quick-view.ledger-card', ['card' => [ 'title' => 'Künye', 'icon' => 'fa-address-card', 'url' => $uf, 'foldable' => true, 'sections' => [$profileSection, $identitySection, $contactSection, $addressSection, $systemSection], ]]) {{-- Hizmet kategorileri: çoklu seçim, kendi ucuna (update-types) yazar --}}
Hizmet Kategorileri Birden fazla seçilebilir
@include('agency.suppliers._type-chips', ['selected' => $supplier->type_codes])
İlk seçilen kategori birincil tiptir; otel seçilirse "Otel Bilgi Formu" sekmesi açılır.
{{-- Sorumlu yetkililer: ayrı tabloda tutulur, kart içinden yönetilir --}}
Sorumlu Yetkililer {{ $supplier->responsibles->count() }} kişi
@forelse($supplier->responsibles as $resp)
{{ mb_strtoupper(mb_substr($resp->first_name ?: '?', 0, 1, 'UTF-8'), 'UTF-8') }}
{{ $resp->full_name }} @if($resp->position){{ $resp->position }}@endif @if($resp->gender_label) {{ $resp->gender_label }} @endif
@if($resp->phone){{ $resp->phone }}@endif @if($resp->email){{ $resp->email }}@endif @if(! $resp->phone && ! $resp->email)İletişim bilgisi girilmemiş@endif
@empty Yukarıdaki "Ekle" ile sorumlu kişi tanımlayın. @endforelse
{{-- Yorum & dahili notlar --}}
Yorum Alanı
{!! $supplier->notes !!}

Tedarikçi hakkında dahili notlar — yalnızca acentenize görünür.

@php // Kaynak tipi görsel eşlemesi. Resource modelinde accessor yok; renkler // quick-view-drawer'daki .theme-resources avatar renkleriyle aynı tutuldu. $resourceTypeMap = [ 'guide' => ['label' => 'Rehber', 'icon' => 'fas fa-user-tie', 'gradient' => 'linear-gradient(135deg,#3b82f6,#1d4ed8)'], 'vehicle' => ['label' => 'Araç', 'icon' => 'fas fa-bus', 'gradient' => 'linear-gradient(135deg,#10b981,#047857)'], 'captain' => ['label' => 'Kaptan', 'icon' => 'fas fa-id-card', 'gradient' => 'linear-gradient(135deg,#8b5cf6,#6d28d9)'], ]; $resourcesByType = $supplier->resources->groupBy('type'); @endphp {{-- Kaynak ekleme modalı — açılışta body'ye taşınır (drawer kendi stacking context'ini oluşturduğu için kart içinde kalırsa panelin altında görünürdü). --}}
Yeni Kaynak Ekle
Kaynak dış kaynak olarak {{ $supplier->company_name }} tedarikçisine bağlanacak.
{{-- Araç: tek ad/tanım --}} {{-- Rehber/Kaptan: ad + soyad --}}
{{-- Rehber / Kaptan alanları --}}
Rehber / Kaptan Bilgileri
Virgülle ayırın.
{{-- Araç alanları --}}
Maliyet & Durum
@if($supplier->supplier_type === 'hotel') @php $fs = $supplier->factSheet; $fsUrl = route('agency.suppliers.fact-sheet.update-field', $supplier); $starOptions = [['value' => '', 'label' => '—']]; for ($i = 1; $i <= 5; $i++) { $starOptions[] = ['value' => (string) $i, 'label' => $i . ' Yıldız']; } /** Bilgi formu satırı — kendi ucuna yazar (tedarikçi kaydına değil). */ $fsRow = function (string $label, string $field, $value, ?string $text = null, array $o = []) use ($fsUrl) { return [ 'label' => $label, 'field' => $field, 'type' => $o['type'] ?? 'text', 'value' => $value === null ? '' : (string) $value, 'text' => $text === null ? ($value === null ? '' : (string) $value) : $text, 'options' => $o['options'] ?? null, 'mono' => $o['mono'] ?? false, 'ph' => $o['ph'] ?? null, 'url' => $fsUrl, ]; }; @endphp @endif
{{-- Ortak katmanlar: pfx satır davranışı ledger-ui'de, etkinlik yazma alanı ve akış activity-ui'de. Aşağısı yalnızca tedarikçi kartına özgü stil. --}} @include('components.quick-view.ledger-ui') @include('components.quick-view.activity-ui') @once @endonce