# Lisans Devri Kancaları

https://dev.wisecp.com/tr/lisans-devri-kancalari

Yazılım lisansını başka bir hesaba taşıyan ve kurulumu sıfırlayan on iki kanca.

## Genel Bakış

Lisans devri, hizmet devrinden **ayrı bir akıştır**. Kendi kaydını tutar, kendi ücretini keser ve **iki tarafın da e-posta doğrulaması** ile ilerler.

Yeniden verme (reissue) ise devirle ilgisizdir: lisansın bağlı olduğu kurulum bilgisi sıfırlanır, böylece müşteri yazılımı **başka bir sunucuya** kurabilir.

## Referans

### Lisans devrini durdurma

gateservice.license_transfer

`LicenseTransfer` ürün ayarı gelir

Lisans devri başlamadan önce çalışır.

Parametreler 2

$servicearrayDevredilecek hizmet kaydı, seçenekleri çözülmüş hâlde.

$lt_configarrayÜrünün lisans devri ayarları: ücret tipi, faturanın hangi tarafa kesileceği, sınırlar. Kendi kuralınızı yazarken buradaki ayarı okuyun; operatör her üründe farklı davranmış olabilir.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('gate:service.license_transfer', 10, function ($service, $lt_config) {
    // Ucretsiz verilen gelistirici lisansi devredilemez.
    if (!empty($service['options']['developer']))
        return 'Gelistirici lisansi baska bir hesaba devredilemez.';

    return null;
});
```

### Devir ücretini değiştirme

filterservice.license_transfer_fee

`Hook::runRefs` referansla

Devir ücreti hesaplandıktan sonra, fatura kesilmeden önce çalışır.

Parametreler 3

$feearrayrefHesaplanan ücret: `type`, `amount`, `currency_id`, `basis`, `base_amount`, `base_currency_id`. Yüzde tipinde taban ürünün güncel tek seferlik fiyatıdır (`basis` = `product_price`); ürünün aktif tek seferlik fiyatı yoksa hizmet tutarına düşer. Tutarı sıfırlamak devri ücretsiz yapar.

$servicearrayDevredilen hizmet, tutarı ve para birimiyle.

$lt_configarrayÜrünün ücret ayarları.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('filter:service.license_transfer_fee', 10,
    function (&$fee, $service, $lt_config) {
        // Kurum ici devirlerde ucret almayin.
        if (Acme::sameCompany($service)) $fee['amount'] = 0.0;
    });
```

### Devrin başladığını öğrenme

actionservice.license_transfer_started

`LicenseTransfer` doğrulama bekleniyor

Devir kaydı oluşturulduktan sonra çalışır. Lisans bu noktada **henüz geçmemiştir**.

Parametreler 4

$transfer_idintOluşturulan devir kaydının kimliği.

$service_idintDevredilen hizmetin kimliği.

$transferor_idintMevcut sahip.

$transferee_idintHedef sahip.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_transfer_started', 10,
    function ($transfer_id, $service_id, $transferor_id, $transferee_id) {
        // Lisans HENUZ gecmedi: iki taraf da dogrulayana kadar bekler.
        Audit::licenseTransfer('started', $transfer_id, $service_id);
    });
```

### Bir tarafın onayını izleme

actionlicense.transfer.verified

`LicenseTransfer` iki kez çalışır

Taraflardan biri e-posta bağlantısını onayladığında çalışır. **Her devir için iki kez** çalışır.

Parametreler 2

$transferarrayGüncel devir kaydı, onay sonrası hâliyle.

$partystringOnaylayan taraf: `transferor` (gönderen) ya da `transferee` (alıcı). Hangi tarafın onayladığını buradan okuyun; kanca iki kez çalışır.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:license.transfer.verified', 10, function ($transfer, $party) {
    // Kanca IKI kez calisir: yalniz alicinin onayina tepki verin.
    if ($party === 'transferee') Crm::licenseAccepted($transfer['id'] ?? 0);
});
```

### Devrin tamamlandığını öğrenme

actionservice.license_transfer.completed

`LicenseTransfer` taze okunmuş kayıt

Lisans yeni sahibe geçtikten sonra çalışır.

Parametreler 2

$transfer_idintDevir kaydının kimliği.

$transferarrayDevrin **taze okunmuş** satırı: durumu tamamlandı, tamamlanma zamanı dolu. Önbellek atlanmıştır, yani değerler günceldir.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_transfer.completed', 10,
    function ($transfer_id, $transfer) {
        // Kayit taze okunmustur: durum ve zaman guncel.
        Acme::licenseMoved((int) ($transfer['owner_id'] ?? 0), $transfer);
    });
```

### Lisansın yeniden verilmesini izleme

actionservice.license_reissued

`ClientServices` kurulum sıfırlandı

Lisansın kurulum bağı sıfırlandıktan sonra çalışır; müşteri artık yazılımı başka bir sunucuya kurabilir.

Parametreler 2

$servicearrayHizmet kaydı — **sıfırlama öncesi** anlık görüntü. Kurulum ve adres alanları hâlâ **eski** değerleri taşır; eski sunucuyu buradan öğrenirsiniz.

$uidint**Her zaman hizmetin sahibi**. İşlemi yapan kişi değildir: alt kullanıcı ya da personel tetiklemiş olabilir.

Dönüş 1

arrayisteğe bağlıLisansı bir lisans sunucusuna yayınlayan dinleyici sonucu `['network' => string, 'queue_id' => int]` biçiminde bildirebilir. Yalnız `failed` ekranı değiştirir: yönetici hızlı işlemi de müşterinin Yeniden Düzenle butonu da başarı mesajı yerine uyarı gösterir, çünkü sunucu değişikliği duymamıştır. `queued`, `legacy` ve `unbound` başarı mesajını korur. Başka biçimdeki dönüş ve `null` yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_reissued', 10, function ($service, $uid) {
    // Eski kurulum bilgisi HALA kayitta: yeni degil, eskisini gorursunuz.
    $ok = Acme::forgetInstall($service['options']['install'] ?? '');

    // Istege bagli: sunucunuzun degisikligi duyup duymadigini panele bildirin.
    return ['network' => $ok ? 'queued' : 'failed', 'queue_id' => 0];
});
```

### Lisans güncellemesini izleme

actionservice.license_updated

`AdminServices` lisans alanları kaydedildi

Operatör hizmetin Yönetim sekmesini kaydettikten ve lisansa dair bir şey değiştikten sonra çalışır. O lisansı başka bir yerde tutan her şey artık eskidi. Kendi kaydınızı burada güncellersiniz.

İzlenen alanlar: anahtar, alan adı, IP, sürüm ve lisans parametreleri. Hiçbiri değişmediyse kanca çalışmaz. Kayıt zaten yapıldı; döndürdüğünüz hiçbir şey okunmaz.

Parametreler 3

$serviceIdintKaydedilen hizmet.

$changesarrayYalnız değişenler: `alan => ['old' => …, 'new' => …]`. Anahtarlar: `key`, `domain`, `ip`, `version`, `parameters`.

$servicearrayKayıttan **önceki** hizmet satırı. Saklanan satır gerekiyorsa taze okuyun.

`$changes['key']` nasıl okunur 3

old boşoluşturmaAnahtar ilk kez verildi. Kaydı taşımak yerine oluşturun.

ikisi de dolutaşımaKaydınızı eski anahtardan bulup yenisine alın.

new boştemizlendiOperatör alanı boşalttı. Anahtar zaten dağıtıldı; uzak kaydı silmek çoğu zaman yanlıştır.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_updated', 10,
    function ($serviceId, $changes, $service) {
        // Anahtar taşınmadı: başka bir alan değişti, yeniden yayınlamak yeter.
        if (!isset($changes['key'])) return Acme::republish((int) $serviceId);

        $old = (string) $changes['key']['old'];
        $new = (string) $changes['key']['new'];

        if ($new === '') return;                                 // temizlendi, silinmedi

        $old === ''
            ? Acme::register((int) $serviceId, $new)             // ilk kez verildi
            : Acme::rekey($old, $new);                           // yeni anahtara taşındı
    });
```

### Lisans bildirimini izleme

actionservice.license_report_submitted

`ClientServices` müşteri bildirimi

Müşteri lisansıyla ilgili bir bildirim gönderdiğinde çalışır.

Parametreler 2

$servicearrayBildirimin ilgili olduğu hizmet.

$uidintHizmet sahibinin kimliği.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_report_submitted', 10, function ($service, $uid) {
    Ops::queue('license-report', (int) ($service['id'] ?? 0));
});
```

### Devrin iptalini izleme

actionservice.license_transfer_cancelled

`LicenseTransfer` üç son durum

Bir lisans devri sonlandığında çalışır. Üç ayrı son bu kancaya düşer: iptal, ret ve süre aşımı.

Parametreler 3

$transfer_idintSonlanan devrin kimliği.

$statusstringHangi son: `cancelled`, `rejected` ya da `expired`.

$reasonstringGerekçe kodu, örneğin yönetici iptali ya da doğrulama süresinin dolması.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_transfer_cancelled', 10,
    function ($transfer_id, $status, $reason) {
        // Lisans sunucusundaki devir kilidini kaldirin.
        Acme::unlockTransfer($transfer_id);
    });
```

### Doğrulamanın yeniden gönderilmesini izleme

actionservice.license_transfer.verification_resent

`ClientLicenseTransfer` bekleyen taraflara

Devir doğrulama e-postaları yeniden gönderildiğinde çalışır. Yalnız **henüz doğrulamamış** taraflara gider; onaylayanlara tekrar gönderilmez.

Parametreler 3

$servicearrayDevredilecek hizmetin kaydı. Devir tamamlanmadı: hizmet hâlâ mevcut sahibindedir.

$activearrayEtkin devir kaydı; kimliği ve durumu içindedir.

$pendingarrayYeniden gönderim yapılan tarafların listesi.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.license_transfer.verification_resent', 10,
    function ($service, $active, $pending) {
        // Ikinci kanaldan hatirlatin: yalniz bekleyen taraflara.
        foreach ($pending as $party) Acme::remind($party, (int) ($active['id'] ?? 0));
    });
```

### Yazılım alan adı değişimini durdurma

gateservice.software_domain_change

`ClientServices` yazımdan önce

Müşteri lisansının bağlı olduğu alan adını değiştirirken, çekirdek denetimleri geçtikten sonra ve kayıt yazılmadan önce çalışır.

Parametreler 4

$servicearrayHizmet kaydı, **değişiklik öncesi** hâliyle.

$oldstringBağlı olan alan adı; hiç bağlanmamışsa boş gelir.

$domainstringİstenen yeni alan adı, **normalize edilmiş** hâli: küçük harfli, başındaki www atılmış. Bu ham form verisi değildir; denetiminizi bu değere göre yazın.

$uidintHizmetin sahibi hesap.

Dönüş 1

string|null**Boş olmayan bir metin değişimi engeller**; metin müşteriye gösterilir. Engellenirse ne alan adı yazılır ne de değişim kancası çalışır.

Dinleyici PHP

```php
Hook::add('gate:service.software_domain_change', 10,
    function ($service, $old, $domain, $uid) {
        // Kendi kara listenizi uygulayin.
        if (Acme::blockedDomain($domain)) return 'Bu alan adi lisansa baglanamaz.';

        return null;
    });
```

### Yazılım alan adı değişimini izleme

actionservice.software_domain_changed

`ClientServices` yazımdan sonra

Lisansın bağlı alan adı kaydedildikten sonra çalışır. Lisans sunucusuna haber vermenin yeri burasıdır.

Parametreler 4

$servicearrayHizmet kaydı.

$oldstringÖnceki alan adı; ilk atamada boş gelir.

$domainstringYeni bağlı alan adı.

$uidintSahip hesap.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:service.software_domain_changed', 10,
    function ($service, $old, $domain, $uid) {
        Acme::rebindLicence((int) ($service['id'] ?? 0), $domain);
    });
```

## Tuzaklar

> **Onay kancası her devirde iki kez çalışır**
> 
> Gönderen ve alıcı ayrı ayrı onaylar; kanca **her ikisinde de** çalışır. Tarafı okumadan tepki veren bir dinleyici aynı işi iki kez yapar. İkinci parametredeki taraf değerini **ilk satırda** kontrol edin.

> **Yeniden verme kancasında kurulum ESKİ değerdir**
> 
> Kanca size **sıfırlama öncesi** hizmet kaydını verir: kurulum ve adres alanları eski sunucuyu gösterir. Bu bir kusur değil, **tek şansınızdır**: eski kuruluma dair ne yapacaksanız burada yapın, çünkü değer birazdan silinecek.

> **Sahip ile işlemi yapan aynı kişi değildir**
> 
> Yeniden verme kancasındaki kimlik **her zaman hizmetin sahibidir**. İşlemi bir alt kullanıcı ya da personel tetiklemiş olabilir; o kimlik bu kancaya **hiç gelmez**. "Bunu kim yaptı" sorusunu buradan cevaplayamazsınız.

> **Lisans devri hizmet devrinden ayrıdır**
> 
> İki akış birbirine benzese de **ayrı kancalar** kullanır: lisans devrinin kendi kaydı, kendi ücreti ve iki taraflı e-posta doğrulaması vardır. Hizmet devri kancalarını dinleyen bir sistem lisans devirlerini **hiç görmez**.

## İlgili Makaleler

- [Hizmet Devir Kancaları](https://dev.wisecp.com/tr/hizmet-devir-kancalari)
- [Hizmet Durum Kancaları](https://dev.wisecp.com/tr/hizmet-durum-kancalari)
- Fatura ve Ödeme Kancaları
