# Personel Yanıt Kancaları

https://dev.wisecp.com/tr/personel-yanit-kancalari

Personel yanıtları, iç notlar ve atamanın dokuz kancası.

## Genel Bakış

Personelin bir talebe dokunduğu her nokta burada: yanıt yazmak, düzenlemek, silmek, iç not eklemek ve atama yapmak.

Yanıt kancaları üçtür ve karıştırılmamalıdır: personelin yazdığı, müşterinin yazdığı ve **zamanlanmış görevin** yazdığı. Sonuncusu parametrelerini tek dizide taşır.

İçerikten ayrı bir soru daha var: mesaja **kimin adı** gidecek. Yazar kancası bunu yazma anından önce belirler.

## Referans

### Yazar adını ve imzayı değiştirme

filterticket.reply_author

`AdminTickets` değerler referansla önizlemede de çalışır

Personel mesajının **müşteriye görünen yazar adını** ve mesaja eklenecek imzayı, mesaj yazılmadan önce değiştirir.

Parametreler 3

&$namestringYanıtta görünecek ad. Yalnız ad değişir: gerçek personel kaydı yerinde kalır ve **avatar da o hesaptan** okunur. Ad ile hesap ayrıştığında personel akışında başka birinin fotoğrafı görünür.

&$signaturestringMesajın sonuna eklenecek imza; düz metin verirsiniz, kaçışı çekirdek yapar. Boş bırakırsanız hiçbir imza eklenmez.

$ctxarrayBağlam; değiştirilemez. Anahtarları: `ticket_id` (talep açma formunda henüz sıfır), `lang` (talebin açıldığı dil), `user_id` (talebin sahibi; misafir talebinde sıfır), `staff_id`, `source`, `explicit_name`, `ai`. `source` beş değer alır. Yazma yolları: `panel`, `panel-create`, `api`. Önizleme yolları: `panel-form`, `panel-create-form`.

Dönüş 1

voidDönüş yoksayılır; iki değeri de **yerinde** değiştirirsiniz. `explicit_name` doğruysa çağıran yazarı bilerek seçmiştir; ada dokunmayın.

Dinleyici PHP

```php
Hook::add('filter:ticket.reply_author', 10, function (&$name, &$signature, $ctx) {
    // Cagiran adi kendi verdiyse ona dokunmayin: API author_name, yapay zeka personasi.
    if (!empty($ctx['explicit_name'])) return;

    // Onizleme yollari sayfa her acildiginda calisir: burada yan etki uretmeyin.
    $agent = Acme::pickAgent((int) ($ctx['ticket_id'] ?? 0), (string) ($ctx['lang'] ?? ''));
    if (!$agent) return;

    $name      = $agent['name'];
    $signature = $agent['signature'];
});
```

### Personel yanıtını durdurma

gateticket.reply

`AdminTickets` imza eklenmiş

Personel yanıtı gönderilmeden önce çalışır.

Parametreler 3

$ticketarrayYanıtlanan talep.

$messagestringGönderilecek nihai metin. İşaretleme içerir ve **imza çoktan eklenmiştir**: uzunluk ölçüyorsanız bunu hesaba katın.

$admin_idintYanıtı yazan personel.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('gate:ticket.reply', 10, function ($ticket, $message, $admin_id) {
    // Imza coktan eklendi: uzunluk olcerken hesaba katin.
    if (Acme::containsSecret($message)) return 'Yanitta paylasilmamasi gereken bir deger var.';

    return null;
});
```

### Personel yanıtını izleme

actionticket.reply_added

`AdminTickets` hidratlı yanıt

Personel yanıtı eklendikten sonra çalışır.

Parametreler 3

$ticketarrayYanıt sonrası taze talep.

$reply_idintEklenen yanıtın kimliği.

$replyarrayYanıtın tamamı: metni, yazarı, ekleri ve adresi.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:ticket.reply_added', 10, function ($ticket, $reply_id, $reply) {
    Acme::stopSlaClock((int) ($ticket['id'] ?? 0));
});
```

### Otomatik yanıtı izleme

actionticket.replied

`cronjobs` tek bağlam dizisi

Zamanlanmış görev bir talebe yanıt eklediğinde çalışır. Kardeşlerinin aksine parametreleri **tek bir dizide** gelir.

Parametreler 1

$contextarrayHer şey burada: kaynağı, güncel talep ve eklenen yanıt. Ayrı parametre beklemeyin; bu kanca tek dizi taşır.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:ticket.replied', 10, function ($context) {
    // Tek dizi: kardeslerinden farkli.
    $ticket = $context['request'] ?? [];
    Acme::noteAutoReply((int) ($ticket['id'] ?? 0));
});
```

### Yanıt düzenlemesini izleme

actionticket.reply_updated

`AdminTickets` düzenleme sonrası

Bir yanıt düzenlendikten sonra çalışır.

Parametreler 3

$ticketIdintTalebin kimliği.

$replyIdintDüzenlenen yanıtın kimliği.

$replyarrayGüncellenmiş yanıt. Önceki hâli geçilmez: değişikliği karşılaştırmak istiyorsanız kendi kopyanızı tutmuş olmanız gerekir.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:ticket.reply_updated', 10, function ($ticketId, $replyId, $reply) {
    // Onceki hali gecilmez.
    Acme::reindexReply($replyId, $reply['message'] ?? '');
});
```

### Yanıt silinmesini izleme

actionticket.reply_deleted

`AdminTickets` silme sonrası

Bir yanıt silindikten sonra çalışır.

Parametreler 3

$ticketIdintTalebin kimliği.

$replyIdintSilinen yanıtın kimliği.

$replyarraySilinen yanıtın kaydı: sahibi ve personel olup olmadığı.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:ticket.reply_deleted', 10, function ($ticketId, $replyId, $reply) {
    Acme::dropFromIndex('reply', $replyId);
});
```

### İç not eklemeyi durdurma

gateticket.note_add

`AdminTickets` müşteri görmez

Personel iç not eklemeden önce çalışır. Notlar **müşteriye görünmez**.

Parametreler 3

$ticketarrayNotun ekleneceği talep.

$messagestringNot içeriği.

$admin_idintNotu ekleyen personel.

Dönüş 1

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

Dinleyici PHP

```php
Hook::add('gate:ticket.note_add', 10, function ($ticket, $message, $admin_id) {
    if (Acme::tooLong($message)) return 'Not cok uzun.';

    return null;
});
```

### İç not eklenmesini izleme

actionticket.note_added

`AdminTickets` not boş gelebilir

İç not eklendikten sonra çalışır.

Parametreler 3

$ticketarrayNotun eklendiği talep.

$admin_idintNotu ekleyen personel.

$notearrayNotun verisi: metni, sabitlenmiş olup olmadığı ve ekleri. ? **Boş gelebilir**: not okunamadıysa bu değer yoktur. Erişmeden önce sınayın.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:ticket.note_added', 10, function ($ticket, $admin_id, $note) {
    // Not BOS gelebilir.
    if (!$note) return;

    Acme::mirrorNote((int) ($ticket['id'] ?? 0), $note['message'] ?? '');
});
```

### Atamayı izleme

actionticket.assigned

`AdminTickets` sıfır = atama yok

Bir talep personele atandığında ya da ataması kaldırıldığında çalışır.

Parametreler 3

$ticketarrayAtama **öncesi** talep verisi.

$old_assigned_idintÖnceki atanan; **sıfır** ise atanmamıştı.

$new_assigned_idintYeni atanan; **sıfır** ise atama kaldırılmıştır.

Dönüş 1

voidDönüş yoksayılır.

Dinleyici PHP

```php
Hook::add('action:ticket.assigned', 10,
    function ($ticket, $old_assigned_id, $new_assigned_id) {
        // Sifir = atama kaldirildi.
        if (!$new_assigned_id) { Acme::backToPool((int) ($ticket['id'] ?? 0)); return; }

        Acme::notifyAgent($new_assigned_id, (int) ($ticket['id'] ?? 0));
    });
```

## Tuzaklar

> **Yazar kancası önizlemede de çalışır**
> 
> Yanıt formundaki imza kutusu değerini bu kancadan alır, yazma anında kanca **yeniden** çalışır. İki sonucu var: dinleyiciniz sayfa her açıldığında da çalıştığı için orada sayaç artırmamalı ya da kayıt yazmamalıdır; ve imzayı koşulsuz belirliyorsanız kutu bir önizlemedir, bir girdi değil. Operatörün kutuda yaptığı elle düzenleme yazma anında **ezilir**.

> **Not verisi boş gelebilir**
> 
> İç not kancasının üçüncü parametresi, not okunamadığında **boştur**. İçine doğrudan erişen bir dinleyici o durumda hata üretir; ilk satırda sınayın.

> **Otomatik yanıt kancası tek dizi taşır**
> 
> Kardeşleri talebi, yanıt kimliğini ve yanıtı ayrı parametreler olarak verir; zamanlanmış görevin yanıtı ise hepsini **tek bir bağlam dizisinde** taşır. Aynı imzayı bekleyen bir dinleyici burada boş değerlerle çalışır.

## İlgili Makaleler

- Destek Talebi Kancaları
- [Müşteri Hesabı Kancaları](https://dev.wisecp.com/tr/musteri-hesabi-kancalari)
- [Kancalar Nasıl Çalışır](https://dev.wisecp.com/tr/kancalar-nasil-calisir)
