# Fatura Yaşam Döngüsü Kancaları

https://dev.wisecp.com/tr/fatura-yasam-dongusu-kancalari

Faturanın kesilmesinden silinmesine on altı kanca: oluşturma kapısı, iki ayrı oluşturma olayı, durum geçişleri ve silme.

## Genel Bakış

Fatura kancalarında dikkat edilecek ilk şey **iki ayrı oluşturma olayının** bulunmasıdır. Biri yalnız yenileme faturalarında çalışır, diğeri **her** fatura için. Adları benzediği için sık karıştırılır.

İkinci nokta paranın nerede olduğudur: fatura kesmek para almak değildir. Ödeme ayrı kancalarda gelir ve durum geçişi **ödendi** olduğunda tamamlanır.

## Referans

### Yenileme faturasını atlamak

gateinvoice.create

`cronjobs/InvoiceGenerate` görev iptale döner

Yenileme faturası kesilmeden önce çalışır. Bu kapı zamanlanmış görev içindedir; durdurmak **hata üretmez**, işi atlar.

Parametreler 3

$target_typestring`service` ya da `addon`.

$target_idintFaturası kesilecek kaydın kimliği.

$duedatestringYenileme vadesi.

Dönüş 1

stringBoş olmayan bir string faturayı **atlatır**: görev iptal olarak biter ve döndürdüğünüz metin **gerekçe** olarak kaydedilir. Müşteri bir şey görmez; fatura hiç kesilmez.

Dinleyici PHP

```php
Hook::add('gate:invoice.create', 10, function ($target_type, $target_id, $duedate) {
    // Iptal talebi acikken yenileme faturasi kesmek musteriyi kizdirir.
    if ($target_type === 'service' && Acme::cancelPending($target_id))
        return 'Iptal talebi acik; yenileme faturasi kesilmedi.';

    return null;
});
```

### Fatura kaydını yazılmadan değiştirme

filterinvoice.create_payload

`Hook::runRefs` referansla

Fatura satırı veritabanına yazılmadan önce çalışır.

Parametreler 1

$dataarrayrefYazılacak kayıt: `user_id`, `user_data`, `currency`, `status`, toplamlar, `pmethod`. JSON alanlar bu noktada **kodlanmış** hâldedir; ham dizi beklemeyin.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('filter:invoice.create_payload', 10, function (&$data) {
    // Kendi referansinizi ekleyin; JSON alanlar zaten kodlanmis gelir.
    $data['notes'] = trim(($data['notes'] ?? '') . ' ' . Acme::stamp());
});
```

### Her faturayı yakalama

actioninvoice.created.any

`Invoices::create()` istisnasız hepsi

**Her** fatura yazıldıktan sonra çalışır: yenileme, elle kesilen, sipariş faturası, hepsi.

Parametreler 2

$invoice_idintYeni faturanın kimliği. Yazma başarısızsa `0` gelir; kontrol etmeden kullanmayın.

$dataarrayYazılan veri, kodlanmış JSON alanlarıyla.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.created.any', 10, function ($invoice_id, $data) {
    if ($invoice_id === 0) return;                 // yazma dustu

    Accounting::mirror($invoice_id, $data);
});
```

### Yenileme faturasını yakalama

actioninvoice.created

`cronjobs/InvoiceGenerate` yalnız yenileme

Yenileme faturası kesildikten sonra çalışır. **Her fatura için değil**: elle kesilen ve sipariş faturaları buraya gelmez.

Parametreler 1

$invoice_idintOluşan ya da birleştirilen faturanın kimliği. Birden çok yenileme aynı faturada birleşmiş olabilir.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.created', 10, function ($invoice_id) {
    // Bu YALNIZ yenileme faturalaridir; hepsini istiyorsaniz .any kullanin.
    Dunning::scheduleReminder((int) $invoice_id);
});
```

### Elle kesilen faturayı yakalama

actioninvoice.created_manually

`AdminInvoices` operatör kesti

Operatör panelden fatura kestiğinde çalışır.

Parametreler 2

$invoice_idintKesilen faturanın kimliği.

$dataarrayFatura verisi.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.created_manually', 10, function ($invoice_id, $data) {
    // Elle kesilen fatura otomatik olanlardan ayri raporlanir.
    Accounting::tagManual((int) $invoice_id);
});
```

### Fatura durum geçişini durdurma

gateinvoice.status_change

`Invoices::change_status()` eski ve yeni durum

Fatura durumu değişmeden önce çalışır.

Parametreler 4

$invoicearrayFatura kaydı, çözülmüş hâlde.

$statusstringHedef durum: `paid`, `unpaid`, `cancelled`, `refund`, `waiting`.

$old_statusstringMevcut durum.

$optionsarrayGeçiş seçenekleri: bildirim, ödeme yöntemi, iade yolu, işlemi yapan. Değiştirilemez bağlam.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('gate:invoice.status_change', 10,
    function ($invoice, $status, $old_status, $options) {
        // Odenmis faturayi geri almak muhasebeyi bozar.
        if ($old_status === 'paid' && $status === 'unpaid')
            return 'Odenmis fatura odenmemise cevrilemez.';

        return null;
    });
```

### Fatura durumunu izleme

actioninvoice.status_changed

`Invoices::change_status()` taze okunmuş kayıt

Durum yazıldıktan sonra çalışır.

Parametreler 4

$invoicearrayDurum yazıldıktan sonra **yeniden okunmuş** fatura. Diğer birçok kancanın aksine burada **güncel** kayıt gelir.

$statusstringYeni durum.

$old_statusstringÖnceki durum.

$optionsarrayGeçiş seçenekleri: ödeme yöntemi, iade yolu, işlemi yapan, bildirim.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.status_changed', 10,
    function ($invoice, $status, $old_status, $options) {
        // Para GERCEKTEN girdi mi? Yalniz odenmise gecise tepki verin.
        if ($status === 'paid' && $old_status !== 'paid')
            Accounting::settled((int) ($invoice['id'] ?? 0), $options['pmethod'] ?? '');
    });
```

### Fatura silmeyi durdurma

gateinvoice.delete

`Invoices::delete()` resmi belge olabilir

Fatura silinmeden önce çalışır.

Parametreler 2

$idintSilinecek faturanın kimliği.

$invoicearrayFatura kaydı: `status`, `taxed`, `total`. Resmileşmiş faturayı silmek yasal iz bırakmaz; bu alanları kontrol edin.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('gate:invoice.delete', 10, function ($id, $invoice) {
    // Resmilesmis fatura silinmez; iptal edilir.
    if (!empty($invoice['taxed'])) return 'Resmilesmis fatura silinemez.';

    return null;
});
```

### Fatura silinmesini izleme

actioninvoice.deleted

`Invoices::delete` silme sonrası

Bir fatura silindikten sonra çalışır. Kayıt artık yoktur: elinizdeki anlık görüntü son kopyadır.

Parametreler 2

$idintSilinen faturanın kimliği.

$invoicearraySilme **öncesi** anlık görüntü. Veritabanına dönüp bakamazsınız; ihtiyacınız olan alanı buradan alın.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.deleted', 10, function ($id, $invoice) {
    // Kayit gitti: gerekli alani anlik goruntuden alin.
    Acme::voidInAccounting($id, $invoice['number'] ?? '');
});
```

### Kalem ayırmayı izleme

actioninvoice.items_split

`AdminInvoices` iki fatura

Bir faturanın kalemleri yeni bir faturaya taşındıktan sonra çalışır. Ortada artık iki fatura vardır.

Parametreler 3

$source_invoice_idintKalemlerin alındığı fatura.

$new_invoice_idintOluşturulan yeni fatura.

$item_idsarrayTaşınan kalemlerin kimlikleri.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.items_split', 10,
    function ($source_invoice_id, $new_invoice_id, $item_ids) {
        // Iki fatura da muhasebeye ayri ayri gitmeli.
        Acme::resync($source_invoice_id);
        Acme::resync($new_invoice_id);
    });
```

### Yenileme faturasının üretilmesini izleme

actioninvoice.renewal_generated

`generate_renewal` yenileme

Bir yenileme faturası üretildikten veya var olana eklendikten sonra çalışır. Hem hizmetler hem eklentiler bu kancaya düşer.

Parametreler 3

$invoice_idintÜretilen ya da birleştirilen faturanın kimliği.

$target_typestring`service` ya da `addon`.

$targetarrayYenilenen kayıt. Aynı faturaya birden çok kalem girebilir: kanca her kalem için ayrı çalışır, fatura kimliği aynı kalır.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.renewal_generated', 10,
    function ($invoice_id, $target_type, $target) {
        // Ayni fatura birden cok kez gelebilir: tekrarli calismaya dayanikli yazin.
        Acme::noteRenewal($invoice_id, $target_type, (int) ($target['id'] ?? 0));
    });
```

### Ödeme hatırlatmasını izleme

actioninvoice.reminder_sent

`Invoices::remind()` `cronjobs/InvoiceReminder` her hatırlatmada

Bir fatura hatırlatması müşteriye ulaştıktan sonra çalışır; gönderilmiş ya da kuyrukta olabilir, hatırlatma görevinden, panelden ya da API'den gelebilir. Yalnız personele ulaşan hatırlatma onu çalıştırmaz. Aynı fatura için birden çok kez çalışabilir: hatırlatma tekrarlanır.

Parametreler 1

$invoicearrayHatırlatılan fatura: numarası, sahibi, tutarı, durumu ve vadesi.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.reminder_sent', 10, function ($invoice) {
    // Ikinci kanaldan da hatirlatin.
    Acme::smsReminder((int) ($invoice['user_id'] ?? 0), $invoice['number'] ?? '');
});
```

### Müşterinin faturayı açmasını izleme

actioninvoice.viewed_by_client

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

Müşteri bir faturayı görüntülediğinde çalışır. Faturanın okunduğunu bilmek, hatırlatma ve tahsilat akışları için değerli bir sinyaldir.

Parametreler 3

$invoicearrayFatura kaydı.

$idintFaturanın kimliği.

$ctxarrayGörüntüleme bağlamı. Şablona veri eklemek için bu kanca değil, hemen ardından çalışan görüntüleme verisi filtresi kullanılır.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:invoice.viewed_by_client', 10, function ($invoice, $id, $ctx) {
    // Okundu bilgisi tahsilat akisini yumusatir.
    Acme::markSeen($id, (int) ($invoice['user_id'] ?? 0));
});
```

### Durum değişimini durdurma

gateinvoice.update_status

`AdminInvoices` yazımdan önce

Yönetici bir faturanın durumunu elle değiştirirken çalışır. Ödendi işaretlemek, iptal etmek ve iade etmek bu kapıdan geçer.

Parametreler 4

$idintFatura kimliği.

$statusstringHedef durum: `paid`, `unpaid`, `refund` ya da `cancelled`.

$pmethodstringÖdendi işaretlenirken seçilen yöntem.

$refund_methodstringİade edilirken seçilen yöntem.

Dönüş 1

string|null**Boş olmayan bir metin işlemi engeller** ve yöneticiye hata olarak gösterilir. Boş dönüş devam ettirir.

Dinleyici PHP

```php
Hook::add('gate:invoice.update_status', 10,
    function ($id, $status, $pmethod, $refund_method) {
        // Kapanmis donemde elle iade yapilmasin.
        if ($status === 'refund' && Acme::periodClosed($id))
            return 'Bu donem kapandi, iade muhasebeden yapilmali.';

        return null;
    });
```

### Paylaşım bağlantısını durdurma

gateinvoice.share_view

`ClientInvoices` oturumsuz erişim

Bir fatura paylaşım bağlantısıyla açıldığında çalışır. Bağlantıyı açan **giriş yapmamış** olabilir: erişimin tek dayanağı adresteki gizli değerdir.

Parametreler 5

$invoicearrayÇözülen fatura kaydı.

$idintFatura kimliği.

$ownerintFaturanın sahibi hesap.

$tokenstringPaylaşım değeri. Kendi kaydınıza yazmayın: bu değeri gören fatura da ödeme sayfası da açabilir.

$isOwnerboolAçan kişi giriş yapmış sahip mi. Yanlışsa oturumsuz erişimdir; denetiminizi buna göre sıkın.

Dönüş 1

string|null**Boş olmayan bir metin erişimi keser**: görüntülemede sayfa bulunamadı, ödemede engel. Boş dönüş devam ettirir.

Dinleyici PHP

```php
Hook::add('gate:invoice.share_view', 10,
    function ($invoice, $id, $owner, $token, $isOwner) {
        // Oturumsuz erisimi kendi IP listenizle sinirlayin.
        if (!$isOwner && !Acme::ipAllowed()) return 'erisim disarida';

        return null;
    });
```

### Faturaya gömülen müşteri bilgisini değiştirme

filterinvoice.client_details

`AdminInvoices` bağla geçer

Faturaya yazılacak müşteri ve adres bilgisi hazırlandıktan sonra, kaydedilmeden önce çalışır. Buraya yazdığınız değerler faturanın kalıcı parçası olur.

Parametreler 2

$merged_dataarraybağlaFaturaya gömülecek bilgi: ad, soyad, e-posta, vergi numarası, adres.

$invoicearrayDüzenlenen fatura kaydı.

Dönüş 1

voidDönüş yoksayılır; dizinin üzerine yazarsınız. Fatura arşiv belgesidir: buraya yazdığınız yanlış bir değer sonradan düzelmez, faturayla birlikte kalır.

Dinleyici PHP

```php
Hook::add('filter:invoice.client_details', 10, function (&$merged_data, $invoice) {
    // Kurumsal musteride unvani muhasebedeki resmi adla esitleyin.
    $official = Acme::officialName($merged_data['company_tax_number'] ?? '');
    if ($official !== '') $merged_data['company'] = $official;
});
```

## Tuzaklar

> **İki oluşturma olayı vardır ve kapsamları farklıdır**
> 
> Adı yalın olan olay **yalnız yenileme** faturalarında çalışır; sonu `.any` ile biten ise **her** faturada. Muhasebe aynası, dış senkron ya da tam sayım isteyen her iş `.any` ile yazılır — yoksa elle kesilen ve sipariş faturaları sessizce kaçar.

> **Sıfır kimlik yazmanın düştüğü demektir**
> 
> `.any` olayı, veritabanı yazması **başarısız olduğunda da** çalışır ve kimlik `0` gelir. Kontrol etmeden kullanmak, olmayan bir faturaya işlem yazmaya çalışmak demektir.

> **Fatura kesmek para almak değildir**
> 
> Oluşturma kancalarında fatura **ödenmemiştir**. Hizmet açmak, ek hizmet etkinleştirmek ya da "teşekkürler" demek buraya yazılmaz. Paranın girdiği an durum geçişinin **ödendiye** döndüğü andır.

> **Aynı duruma geçiş de kanca çalıştırır**
> 
> Durum olayı, yeni ve eski durum **aynı** olsa bile çalışabilir. Ödeme sayfası iki kez çağrıldığında ya da bir görev tekrar koştuğunda bunu görürsünüz. İki durumu **karşılaştırmadan** tepki veren dinleyici işi çiftler.

## İlgili Makaleler

- Fatura ve Ödeme Kancaları
- [Hizmet Yenileme Kancaları](https://dev.wisecp.com/tr/hizmet-yenileme-kancalari)
- Sipariş Akışı Kancaları
