# Hizmet Yenileme Kancaları

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

Hizmetin süresini uzatan ve paketini değiştiren on bir kanca: yenileme, otomatik yenileme, yükseltme ve düşürme.

## Genel Bakış

Yenileme **üç ayrı yoldan** gelir: müşteri elle başlatır, otomatik yenileme saklı karttan çeker, ya da ödenen bir fatura yenilemeyi tetikler. Üçü de aynı olay kancasında buluşur.

Paket değişikliği ise tek adım değildir. Talep alınır, ödeme durumuna göre bir **akış** seçilir (fatura kesildi, dönem sonuna planlandı ya da doğrudan kuyruğa alındı) ve değişiklik ancak sonunda uygulanır.

## Referans

### Elle yenilemeyi durdurma

gateservice.manual_renew

`ClientServices` yalnız elle yol

Müşteri elle yenileme başlattığında, yenileme motoru **hiç çağrılmadan** önce çalışır.

Parametreler 2

$servicearrayYenilenen hizmet kaydı.

$renew_optsarrayMotora gidecek seçenekler: `source` (burada `manual`), ek hizmet keşfi, metrik işleme ve bildirim seçenekleri. Bu kapı yalnız elle başlatılan yolu görür; otomatik yenileme ve fatura yolu buradan geçmez.

Dönüş 1

stringBoş olmayan bir string işlemi **durdurur**; metin hata olarak fırlatılır ve müşteriye gösterilir.

Dinleyici PHP

```php
Hook::add('gate:service.manual_renew', 10, function ($service, $renew_opts) {
    // Askidaki hizmeti yenilemek parayi bosa harcar; once acilmali.
    if (($service['status'] ?? '') === 'suspended')
        return 'Askidaki hizmet once aktif edilmelidir.';

    return null;
});
```

### Yenilemenin işlendiğini öğrenme

actionservice.renewed

`Services::process_renewal()` kayıt ESKİ vadeyi taşır

Vade uzatıldıktan sonra çalışır. **Üç yenileme yolu da** buraya gelir.

Parametreler 4

$serviceIdintYenilenen hizmetin kimliği.

$servicearrayUzatma **öncesi** anlık görüntü. Vade, dönem ve tutar hâlâ **eski** değerlerdir; yeni vadeyi buradan okumayın.

$newDuedatestringYazılan yeni vade. Tarih asla geriye gitmez: aday ile mevcut arasından **büyük olan** yazılır.

$oldDuedatestringUzatma öncesi vade. Kayıttakiyle aynıdır, karşılaştırma kolaylığı için ayrıca verilir.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.renewed', 10,
    function ($serviceId, $service, $newDuedate, $oldDuedate) {
        // Vade GERCEKTEN ilerledi mi? Ayni tarih yazilmis olabilir.
        if ($newDuedate === $oldDuedate) return;

        Crm::renewed($serviceId, $oldDuedate, $newDuedate);
    });
```

### Otomatik yenileme anahtarını durdurma

gateservice.autorenew_toggle

`ClientServices` istenen yeni durum

Müşteri otomatik yenilemeyi açıp kapatırken çalışır; değer henüz **yazılmamıştır**.

Parametreler 3

$servicearrayHizmet kaydı. Otomatik yenileme alanı hâlâ **eski** değerdedir.

$enableboolİstenen **yeni** durum.

$uidintHizmetin **sahibi**. İşlemi yapan bir alt kullanıcı olabilir; o kimlik burada gelmez.

Dönüş 1

stringBoş olmayan bir string işlemi **durdurur**; metin hata olarak fırlatılır ve müşteriye gösterilir.

Dinleyici PHP

```php
Hook::add('gate:service.autorenew_toggle', 10, function ($service, $enable, $uid) {
    // Kapatmak, hizmetin sessizce sona ermesine yol acar: kart borclu ise engelle.
    if (!$enable && Acme::hasDebt($uid))
        return 'Odenmemis bakiye varken otomatik yenileme kapatilamaz.';

    return null;
});
```

### Otomatik yenileme değişimini izleme

actionservice.autorenew_changed

`ClientServices` kayıt ESKİ değeri taşır

Değer yazıldıktan sonra çalışır.

Parametreler 2

$servicearrayHizmet kaydı — **değişiklikten önce** okunmuş anlık görüntü. Otomatik yenileme alanı hâlâ eski değerdedir; yeni durum ikinci parametrededir.

$enableboolYazılan **yeni** durum.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.autorenew_changed', 10, function ($service, $enable) {
    // Yeni durum IKINCI parametredir; kayittaki alan hala eskidir.
    if (!$enable) Retention::flag((int) ($service['id'] ?? 0), 'autorenew-off');
});
```

### Paket değişikliğini durdurma

gateservice.upgrade

`Services` yükseltme ve düşürme

Paket değişikliği başlamadan önce çalışır. Yükseltme ve düşürmenin **ikisi de** buradan geçer.

Parametreler 5

$servicearrayMevcut hizmet satırı.

$old_pidintMevcut ürünün kimliği.

$product_idintHedef ürünün kimliği.

$price_dataarrayÇözülmüş hedef fiyat satırı.

$isUpbool`true` yükseltme, `false` düşürme. Yönü buradan okuyun; ürün kimliklerini karşılaştırarak çıkarmayın.

Dönüş 1

stringBoş olmayan bir string işlemi **durdurur**; metin hata olarak fırlatılır ve müşteriye gösterilir.

Dinleyici PHP

```php
Hook::add('gate:service.upgrade', 10,
    function ($service, $old_pid, $product_id, $price_data, $isUp) {
        // Dusurme veri kaybina yol acabilir: kotayi asan hesabi durdurun.
        if (!$isUp && Acme::usageAbovePlan($service, $product_id))
            return 'Mevcut kullaniminiz hedef pakete sigmiyor.';

        return null;
    });
```

### Paket değişikliği talebini izleme

actionservice.plan_change_requested

`ClientServices` üç ayrı akış

Talep alındıktan sonra çalışır. Değişikliğin **ne zaman uygulanacağını** akış değeri söyler.

Parametreler 6

$servicearrayHizmet kaydı, **eski** plan üzerinde.

$old_pidintEski ürünün kimliği.

$new_pidintİstenen ürünün kimliği.

$flowstringSonuç akışı: `invoice_unpaid` (fatura kesildi, **ödenmedi**), `scheduled` (dönem sonuna planlandı), `queued` (bedelsiz, doğrudan kuyruğa). Üçünde de değişiklik **henüz uygulanmadı**.

$updown_idintOluşan paket değişikliği kaydının kimliği.

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

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.plan_change_requested', 10,
    function ($service, $old_pid, $new_pid, $flow, $updown_id, $invoice_id) {
        // Degisiklik HENUZ uygulanmadi; ne zaman uygulanacagini flow soyler.
        if ($flow === 'invoice_unpaid') Crm::awaitPayment($invoice_id, $updown_id);
    });
```

### Paket değişikliğinin uygulandığını öğrenme

actionservice.updowngrade.applied

`Services` tek dizi parametre

Paket değişikliği gerçekten uygulandıktan sonra çalışır.

Parametreler 1

$payloadarrayTek dizi: `service_id`, `old_service`, `new_product`, `type` (`upgrade` ya da `downgrade`), `needs_recreate`, `params`. `needs_recreate` doğruysa hizmet sunucuda **yeniden kurulacak** demektir.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.updowngrade.applied', 10, function ($payload) {
    // Yeniden kurulacaksa hizmet bir sure kesintiye ugrar: musteriyi uyarin.
    if (!empty($payload['needs_recreate']))
        Notify::planRebuild((int) ($payload['service_id'] ?? 0));
});
```

### Sunulan paketleri değiştirme

filterservice.upgrade_products

`Hook::runRefs` referansla

Müşteriye gösterilecek yükseltme seçenekleri hazırlandıktan sonra çalışır.

Parametreler 1

$productsarrayrefSunulacak ürünler. Listeden çıkarmak seçeneği ekranda gizler; kapı yerine burayı kullanmak müşteriye **ulaşamayacağı bir seçenek** göstermez.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('filter:service.upgrade_products', 10, function (&$products) {
    // Kapida reddedecegin paketi listede hic gosterme.
    $products = array_values(array_filter($products,
        fn ($p) => Acme::sellable((int) ($p['id'] ?? 0))));
});
```

### Eklenti yenilemesini izleme

actionservice.addon.renewed

`handle_extend_addon_paid` ödeme sonrası

Bir eklentinin vadesi uzadıktan sonra çalışır. Ödeme alınmış, yeni vade yazılmıştır.

Parametreler 5

$addonIdintEklenti kaydının kimliği.

$addonarrayEklenti satırı, **uzatma öncesi** hâliyle. Vade ve tutar alanları eski değerleri taşır; yenisini ayrı parametreden alın.

$servicearrayÜst hizmet kaydı.

$newDuedatestringYazılan yeni vade.

$oldDuedatestringUzatma öncesi vade.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.addon.renewed', 10,
    function ($addonId, $addon, $service, $newDuedate, $oldDuedate) {
        // Dis lisanstaki hak suresini yeni vadeye cekin.
        Acme::extendEntitlement($addonId, $newDuedate);
    });
```

### Tekrar sayısının dolmasını izleme

actionservice.recurring_completed

`generate_renewal` son döngü

Bir ürünün tanımlı tekrar sayısı dolup **son** yenileme faturası üretildiğinde çalışır. Bundan sonrası için otomatik yenileme yoktur.

Parametreler 4

$service_idintDöngüsü dolan hizmetin kimliği.

$servicearrayHizmet kaydı.

$countintBu hizmet için üretilmiş toplam yenileme sayısı.

$limitintÜründe tanımlı tekrar sınırı.

Dönüş 1

voidDönüş yoksayılır. Fatura çoktan üretilmiştir; burada durdurulamaz.

Dinleyici PHP

```php
Hook::add('action:service.recurring_completed', 10,
    function ($service_id, $service, $count, $limit) {
        // Son donguyu yakalayin: musteriye devam teklifi gonderin.
        Acme::offerContinuation((int) ($service['owner_id'] ?? 0), $service_id);
    });
```

### Otomatik ödeme kaynağı var mı sorusunu değiştirme

filterservice.auto_pay_source_available

`ClientAutoRenewGuard` bağla geçer

“Yenileme görevi bu hesaptan müşteri olmadan tahsilat yapabilir mi?” sorusunun cevabı verilmeden önce çalışır. Çekirdeğin bilmediği bir kaynağı burada beyan edersiniz.

Parametreler 2

$availableboolbağlaÇekirdeğin kararı. Üzerine yazabilirsiniz.

$ctxarrayBağlam: `owner_id`, kaynağı sorulan hesap.

Dönüş 1

voidDönüş yoksayılır; değeri yerinde değiştirirsiniz. Doğru demek yenilemeyi **denemeye** yetki verir. Kaynağınız gerçekten çekemezse yenileme başarısız olur ve hizmet askıya alınır.

Dinleyici PHP

```php
Hook::add('filter:service.auto_pay_source_available', 10,
    function (&$available, $ctx) {
        if ($available) return;   // cekirdek zaten bir kaynak buldu

        // Kendi sakladiginiz yetkilendirmeyi beyan edin.
        $available = Acme::hasMandate((int) ($ctx['owner_id'] ?? 0));
    });
```

## Tuzaklar

> **Yenileme olayında kayıt ESKİ vadeyi taşır**
> 
> İkinci parametredeki hizmet, uzatma **öncesi** anlık görüntüdür: vade, dönem ve tutar hâlâ eskidir. Yeni vade **üçüncü parametrededir**. Kayıttan okuyup "yenilenmemiş" sonucuna varmak buradan çıkar. Ayrıca tarih asla geriye gitmez, yani eski ve yeni **aynı** olabilir.

> **Paket değişikliği talebi uygulama değildir**
> 
> Talep kancasında değişiklik **henüz uygulanmamıştır**. Akış değeri üç şey söyleyebilir: fatura kesildi ve ödenmedi, dönem sonuna planlandı, ya da doğrudan kuyruğa alındı. Yeni pakete göre iş yapmak için **uygulandı** kancasını bekleyin.

> **Anahtar kancalarında kayıt eski değeri gösterir**
> 
> Otomatik yenileme hem kapıda hem olayda size **değişiklik öncesi** hizmet kaydı verir. Yeni durum her ikisinde de **ayrı bir parametredir**. Kayıttaki alanı okuyan bir dinleyici, açma işlemini kapatma sanır.

> **Reddedeceğiniz paketi listeden çıkarın**
> 
> Yükseltme kapısı seçeneği **müşteri seçtikten sonra** reddeder. Aynı kuralı liste filtresine de yazarsanız seçenek hiç görünmez ve müşteri boşuna denemez. Kapıyı güvenlik için tutun, filtreyi **nezaket** için kullanın.

## İlgili Makaleler

- [Hizmet Durum Kancaları](https://dev.wisecp.com/tr/hizmet-durum-kancalari)
- Fatura ve Ödeme Kancaları
- [Hizmet Yaşam Döngüsü Kancaları](https://dev.wisecp.com/tr/hizmet-yasam-dongusu-kancalari)
