# Hizmet Detay Kancaları

https://dev.wisecp.com/tr/hizmet-detay-kancalari

Müşterinin hizmet detayında gördüğü on dört kanca: sayfa verisi, kartlar, araçlar, ek hizmetler ve metrikler.

## Genel Bakış

Hizmet detayı müşterinin en çok baktığı ekrandır ve içeriğinin çoğu **modülden** gelir: kartlar, araçlar, yetenekler. Buradaki filtreler o çıktıyı ekrana varmadan önce yakalar.

İkinci grup ek hizmetlerdir. Ek hizmetin kendi **durum akışı** vardır ve ana hizmetten ayrı ilerler: ayrı satın alınır, ayrı faturalanır, ayrı askıya alınır.

## Referans

### Detay sayfasının verisini değiştirme

filterservice.detail_data

`ClientServices` sayfanın tamamı

Detay sayfasının bütün şablon verisi hazırlandıktan sonra çalışır.

Parametreler 2

$dataarrayrefSayfaya gidecek **tüm** veri. En geniş müdahale noktasıdır: var olan anahtarı bozmadan yenisini ekleyin.

$servicearrayAktif hizmet kaydı.

Dönüş 1

voidDeğer **referansla** değişir; dönüş kullanılmaz.

Dinleyici PHP

```php
Hook::add('filter:service.detail_data', 10, function (&$data, $service) {
    // Var olan anahtarlari bozmadan kendi verinizi ekleyin.
    $data['acme_health'] = Acme::health((int) ($service['id'] ?? 0));
});
```

### Pano kartlarını değiştirme

filterservice.dashboard.cards

`ServerModule` modül çıktısı

Modülün sunduğu kart tanımları hazırlandıktan sonra, ekrana gitmeden önce çalışır.

Parametreler 2

$cardsarrayrefKart tanımları. Kart ekleyebilir, çıkarabilir ya da sırasını değiştirebilirsiniz.

$moduleServerModuleHizmetin modül örneği. Hangi modül olduğuna göre ayırmak için kullanın; kural her modüle uymayabilir.

Dönüş 1

voidDeğer **referansla** değişir; dönüş kullanılmaz.

Dinleyici PHP

```php
Hook::add('filter:service.dashboard.cards', 10, function (&$cards, $module) {
    // Kendi kartinizi sona degil, ilgili yere koyun.
    array_splice($cards, 1, 0, [Acme::usageCard()]);
});
```

### Araç listesini değiştirme

filterservice.dashboard.tools

`ServerModule` gruplu liste

Modülün araç listesi hazırlandıktan sonra çalışır.

Parametreler 2

$toolsarrayrefGruplanmış araç listesi: her grup kendi bilgisini ve araçlarını taşır. Düz liste değildir; grubun içine inmeniz gerekir.

$moduleServerModuleHizmetin modül örneği.

Dönüş 1

voidDeğer **referansla** değişir; dönüş kullanılmaz.

Dinleyici PHP

```php
Hook::add('filter:service.dashboard.tools', 10, function (&$tools, $module) {
    // Liste GRUPLUDUR: araclara grubun icinden ulasin.
    foreach ($tools as &$group)
        $group['tools'] = array_filter($group['tools'] ?? [],
            fn ($t) => ($t['key'] ?? '') !== 'rebuild');
});
```

### Alan adı yeteneklerini değiştirme

filterservice.detail_tabs_capabilities

`ClientDomains` sekmeleri açar

Alan adı detayındaki sekmelerin hangi yetenekleri göstereceği belirlendikten sonra çalışır.

Parametreler 3

$capabilitiesarrayrefYetenek işaretleri: DNS kayıtları, posta yönlendirme ve benzerleri. Buraya yazdığınız her işaret ekranın ilgili anahtarına **geri aktarılır**: kapatmak sekmeyi gizler.

$servicearrayAktif alan adı hizmeti.

$moduleobject|nullSağlayıcı modülü — **boş olabilir**. Modülsüz alan adında `null` gelir; metot çağırmadan önce kontrol edin.

Dönüş 1

voidDeğer **referansla** değişir; dönüş kullanılmaz.

Dinleyici PHP

```php
Hook::add('filter:service.detail_tabs_capabilities', 10,
    function (&$capabilities, $service, $module) {
        if ($module === null) return;                 // modulsuz alan adi

        // Isaret kapatmak sekmeyi ekrandan gizler.
        $capabilities['has_email_forwarding'] = Acme::mailAllowed($service);
    });
```

### Ek hizmetin açıldığını öğrenme

actionservice.addon.created

`Services` fatura ayrı

Hizmete bir ek hizmet eklendikten sonra çalışır.

Parametreler 5

$addonRecordIdintOluşan ek hizmet kaydının kimliği.

$serviceIdintÜst hizmetin kimliği.

$addonIdintEk hizmet ürününün kimliği. `0` demek bunun bir **alan adı ek hizmeti** olduğu demektir; ürün kataloğunda karşılığı yoktur.

$invoiceIdintKesilen faturanın kimliği; fatura yoksa `0`.

$totalAmountfloatEk hizmet için tahsil edilen toplam.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.addon.created', 10,
    function ($addonRecordId, $serviceId, $addonId, $invoiceId, $totalAmount) {
        // addonId 0 ise bu bir ALAN ADI ek hizmetidir, urun degil.
        if ($addonId === 0) return;

        Crm::addonSold($serviceId, $addonId, (float) $totalAmount);
    });
```

### Ek hizmet durumunu izleme

actionservice.addon.status_changed

`Services` tek dizi parametre

Ek hizmetin durumu değiştikten sonra çalışır.

Parametreler 1

$payloadarrayTek dizi: `service`, `addon`, `addon_id`, `old_status`, `new_status`, `user_id`. Ek hizmetin durumu ana hizmetten **bağımsızdır**: biri askıdayken diğeri çalışıyor olabilir.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.addon.status_changed', 10, function ($payload) {
    // TEK dizi gelir; eski ve yeni durum icindedir.
    if (($payload['new_status'] ?? '') === 'suspended')
        Acme::addonOff((int) ($payload['addon_id'] ?? 0));
});
```

### Metrik anahtarını durdurma

gateservice.metric_toggle

`ClientServices` hiçbir şey yazılmaz

Müşteri kullanım metriğini açıp kapatırken çalışır. Durdurursanız **ne veritabanına ne modüle** bir şey gider.

Parametreler 4

$servicearrayHizmet kaydı.

$metricKeystringMetrik anahtarı. Ürünün metrik ayarında tanımlıdır.

$enableboolHedef durum.

$labelstringMetriğin gösterim etiketi. Hata mesajınızda kullanmak için hazır gelir.

Dönüş 1

stringBoş olmayan bir string geçişi **durdurur**; metin hata olarak fırlatılır.

Dinleyici PHP

```php
Hook::add('gate:service.metric_toggle', 10,
    function ($service, $metricKey, $enable, $label) {
        // Etiket hazir gelir: mesaji musterinin gordugu adla yazin.
        if (!$enable && Acme::metricRequired($metricKey))
            return $label . ' kapatilamaz.';

        return null;
    });
```

### Metrik değişimini izleme

actionservice.metric_toggled

`ClientServices` yazıldı

Metrik durumu yazıldıktan sonra çalışır.

Parametreler 3

$servicearrayHizmet kaydı.

$metricKeystringMetrik anahtarı.

$enableboolYazılan yeni durum.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.metric_toggled', 10, function ($service, $metricKey, $enable) {
    // Kapatilan metrik faturalanmaya devam edebilir: kendi sayacinizi ayarlayin.
    Acme::metricState((int) ($service['id'] ?? 0), $metricKey, (bool) $enable);
});
```

### Müşterinin detay sayfasını açmasını izleme

actionservice.detail.viewed

`website/services` her açılışta

Müşteri kendi hizmetinin yönetim sayfasını açtığında çalışır. Sahiplik ve erişim denetimleri çoktan geçilmiştir.

Parametreler 2

$servicearrayYüklenen hizmet kaydı.

$serviceIdintHizmetin kimliği.

Dönüş 1

voidDönüş yoksayılır. Sayfa verisini değiştirmek için bu kanca değil, detay verisi filtresi kullanılır.

Dinleyici PHP

```php
Hook::add('action:service.detail.viewed', 10, function ($service, $serviceId) {
    // Hafif tutun: musteri sayfanin acilmasini bekliyor.
    Acme::touchLastSeen($serviceId);
});
```

### Yöneticinin detay sayfasını açmasını izleme

actionservice.viewed

`admin/services` her açılışta

Yönetici bir hizmet detayını açtığında çalışır. Müşteri tarafındaki ikizle **aynı verileri** alır, yalnız izleyen kişi farklıdır.

Parametreler 2

$servicearrayYüklenen hizmet kaydı.

$service_idintHizmetin kimliği.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.viewed', 10, function ($service, $service_id) {
    // Uzak panelden canli durumu simdiden cekin.
    Acme::prefetchStatus($service_id);
});
```

### Dosya indirmeyi durdurma

gateservice.file_download

`website/services` üç akış

Müşteri bir hizmet dosyası indirmeden önce çalışır. Üç akışın hepsi buradan geçer: gereksinim eki, yazılım paketi ve teslim dosyası.

Parametreler 2

$kindstringHangi akış: `requirement`, `package` ya da `delivery`.

$ctxarrayBağlam. Ortak: `user_id`, `service_id`. Akışa göre dosya adı, sürüm ve kayıt kimliği eklenir.

Dönüş 1

mixed**Dolu bir dönüş indirmeyi engeller**: yanıt anında 403 olur. Tuzak: bu uç ham dosya döndürdüğü için dönüşünüz **müşteriye gösterilmez**. Diğer kapıların aksine gerekçe ekrana çıkmaz; sebebi kendiniz kaydedin. Boş dönüş indirmeyi sürdürür.

Dinleyici PHP

```php
Hook::add('gate:service.file_download', 10, function ($kind, $ctx) {
    if ($kind !== 'package') return null;

    // Kota dolduysa engelleyin; gerekce ekrana cikmaz, kendiniz kaydedin.
    if (Acme::quotaExceeded((int) ($ctx['user_id'] ?? 0))) {
        Acme::log('indirme kotasi doldu', $ctx);
        return true;
    }

    return null;
});
```

### İndirilecek dosyayı değiştirme

filterservice.file_download.source

`website/services` bağla geçer

Dosya akışa verilmeden önce çalışır. Kuruluma özgü anahtarları gömülü bir paket hazırlayıp onu sunabilir, ya da indirmeyi kendi adresinize yönlendirebilirsiniz.

Parametreler 2

$sourcearraybağlaSunulacak kaynak: `path` (diskteki tam yol), `name` (kaydedilecek ad), `link` (dış adres), `cleanup`.

$ctxarraybağlaBağlam: `kind`, `user_id`, `service_id`, hizmet kaydı ve ürün kimliği.

Dönüş 1

voidDönüş yoksayılır; kaynağın üzerine yazarsınız. Yol doluysa o dosya gönderilir; boş ama dış adres varsa oraya yönlendirilir; ikisi de yoksa yanıt 404 olur. `cleanup` koyarsanız gönderim bittikten sonra **yalnız dosya** silinir, üst dizin kalır.

Dinleyici PHP

```php
Hook::add('filter:service.file_download.source', 10, function (&$source, &$ctx) {
    if (($ctx['kind'] ?? '') !== 'package') return;

    // Kuruluma ozgu anahtari gomulmus paketi hazirlayin ve sonra sildirin.
    $source['path']    = Acme::buildPackage((int) ($ctx['service_id'] ?? 0));
    $source['name']    = 'acme-setup.zip';
    $source['cleanup'] = true;
});
```

### Faturalama profili atamasını durdurma

gateservice.billing_profile_assign

`ClientServiceBilling` yazımdan önce

Müşteri bir hizmete faturalama profili atarken, kayıt yazılmadan önce çalışır. Alan adları da bu kapıdan geçer.

Parametreler 3

$servicearrayHizmet ya da alan adı kaydı.

$profileIdintAtanacak profilin kimliği. **Sıfır** gelirse özel atama kaldırılıp hesabın varsayılanına dönülüyordur.

$uidintProfilin ve hizmetin sahibi hesap.

Dönüş 1

string|null**Boş olmayan bir metin atamayı engeller** ve metin müşteriye hata olarak gösterilir. Boş dönüş devam ettirir.

Dinleyici PHP

```php
Hook::add('gate:service.billing_profile_assign', 10,
    function ($service, $profileId, $uid) {
        // Dondurulmus hesapta profil degistirmeye izin vermeyin.
        if (Acme::frozen($uid)) return 'Hesabiniz incelemede, profil degistirilemez.';

        return null;
    });
```

### Faturalama profili atamasını izleme

actionservice.billing_profile_assigned

`ClientServiceBilling` yazımdan sonra

Atama kaydedildikten sonra çalışır. Kapı geçilmiş, değer yazılmıştır.

Parametreler 4

$servicearrayHizmet ya da alan adı kaydı.

$profileIdintAtanan profil; sıfır ise varsayılana dönülmüştür.

$profileNamestringGörünen ad: şirket ya da kişi adı, varsayılana dönüldüyse “Varsayılan”.

$uidintSahip hesap.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.billing_profile_assigned', 10,
    function ($service, $profileId, $profileName, $uid) {
        Acme::syncAccounting((int) ($service['id'] ?? 0), $profileId);
    });
```

## Tuzaklar

> **Araç listesi gruplu gelir**
> 
> Araç filtresi **düz bir liste değil**, grupların listesini verir; her grubun içinde kendi araçları durur. Doğrudan gezmeye çalışan bir dinleyici araç bulamaz, çünkü elindeki her eleman bir **gruptur**.

> **Yetenek filtresinde modül boş olabilir**
> 
> Alan adı yetenek filtresinde üçüncü parametre **boş gelebilir**: modülü olmayan alan adları vardır. Kontrol etmeden metot çağırmak sayfayı düşürür. Ayrıca buraya yazdığınız her işaret ekrana **geri aktarılır**, yani bir işareti kapatmak sekmeyi görünmez yapar.

> **Ek hizmet ana hizmetten bağımsızdır**
> 
> Ek hizmetin kendi durumu, kendi faturası ve kendi askı akışı vardır. Ana hizmet çalışırken ek hizmet askıda olabilir ya da tersi. Ana hizmetin durumuna bakıp ek hizmetin de açık olduğunu varsaymak **ödenmemiş bir yeteneği** açık bırakır.

> **Sıfır ek hizmet kimliği alan adı demektir**
> 
> Ek hizmet olayında ürün kimliği `0` ise bu bir **alan adı ek hizmetidir** (DNS yönetimi, gizlilik, yönlendirme) ve ürün kataloğunda karşılığı yoktur. Ürün okumaya çalışan dinleyici burada **boş bulur**.

## İlgili Makaleler

- [Hizmet Modül Kancaları](https://dev.wisecp.com/tr/hizmet-modul-kancalari)
- [Hizmet Durum Kancaları](https://dev.wisecp.com/tr/hizmet-durum-kancalari)
- [Müşteri Sitesi Kancaları](https://dev.wisecp.com/tr/musteri-sitesi-kancalari)
