# Хуки и события

В Celena есть две системы расширения: фильтры (`Hook::filter`) и действия (`Hook::action`). Плагин Shop подписывается на одни и диспатчит свои.

## Хуки, на которые плагин подписывается

| Имя | Тип | Зачем |
|---|---|---|
| `template.globals` | filter | Прокидывает все настройки магазина в шаблоны (`{shop.currency_symbol}`, `{shop.store_name}` и т.д.) и флаг `{shop.enabled}="1"`. |
| `admin.sidebar` | filter | Добавляет пункт «Магазин» с подменю (Товары / Производители / Атрибуты / Заказы / Клиенты / Доставка / Города / Оплата / Промокоды / Отзывы / Аналитика / Импорт CSV / Настройки). |
| `admin.notifications` | filter | Добавляет в колокольчик уведомления о новых заказах (`status='new'`). |
| `admin.dashboard.sections` | filter | Добавляет виджет «Витрина магазина» на главный дашборд. |
| `customfields.entities` | filter | Регистрирует сущность `shop_product` для модуля «Доп. поля». |
| `categories.entities` | filter | Регистрирует сущность `shop_product` для модуля «Категории». |
| `category.deleted` | action | Отвязывает товары от удалённой категории (без каскадного удаления самих товаров). |
| `search.sources` | filter | Добавляет товары в общую выдачу `/search`. |

Подписки находятся в `plugins/shop/plugin.php`. Если плагин **деактивирован** — подписки не выполняются: пункт меню исчезает, колокольчик не считает заказы, в селекторе «Применяется к» нет «Товары (магазин)», в общем поиске товары не находятся.

## Inline-теги, которые регистрирует плагин

| Тег | Что |
|---|---|
| `{price amount="1234.5"}` | Форматирует число согласно настройкам валюты: `$ 1,234.50` |
| `{currency}` | Возвращает символ текущей валюты: `$`, `€`, `₴` |
| `[products limit="6" sort="price"]…[/products]` | Блок-тег для вывода товаров в темах (по аналогии с `[news]` и `[categories]`) |

## События, которые плагин диспатчит

Любой плагин или модуль может подписаться через `Hook::addAction(…)` или `Hook::addFilter(…)`.

### `shop.order.created` — action

Срабатывает после успешного оформления заказа (после insert в `shop_orders`).

**Аргумент:**

```php
[
  'id'          => 42,
  'number'      => 'ORD-1A2B3C4D',
  'total'       => 1280.50,
  'email'       => 'customer@example.com',
  'name'        => 'Іван Петренко',
  'items_count' => 3,
  'source'      => 'web',     // или 'admin' для ручного создания
]
```

**Пример** — отправить email клиенту:

```php
Hook::on('shop.order.created', function (array $order) {
    $mailer = Kernel::container()->make(Mailer::class);
    $mailer->send($order['email'], 'Ваш заказ ' . $order['number'], '...');
});
```

### `shop.order.status_changed` — action

Срабатывает при смене статуса заказа в `Заказы → карточка → выбрать статус`.

**Аргумент:**

```php
[
  'id'     => 42,
  'number' => 'ORD-1A2B3C4D',
  'from'   => 'new',
  'to'     => 'paid',
  'email'  => 'customer@example.com',
]
```

**Пример** — отправлять webhook каждый раз при оплате:

```php
Hook::on('shop.order.status_changed', function (array $e) {
    if ($e['to'] !== 'paid') return;
    file_get_contents('https://your-erp.example/api/orders?paid=' . $e['number']);
});
```

## Свои AI-задачи

Плагин не привязывает свои AI-задачи, но кнопка «Заполнить SEO через ИИ» в карточке товара использует ядерную задачу `generate_meta`. Можно зарегистрировать свою:

```php
Kernel::container()->make(AiManager::class)->registerTask(
    'shop_product_description',
    function (array $args) use ($provider) {
        return $provider->complete(
            system: 'Сгенерируй продающее описание товара на 3-4 абзаца.',
            user: 'Название: ' . ($args['title'] ?? ''),
            opts: ['max_tokens' => 500],
        );
    }
);
```

После этого можно поставить кнопку `<button class="ai-btn" data-ai-task="shop_product_description" data-ai-target="[name=body]">…</button>` в форму товара (через оверрайд `products_form.tpl` в теме).

## Чек-лист «как добавить свою функциональность»

1. **Уведомление по email при заказе** — подписаться на `shop.order.created`.
2. **Свой статус заказа** (например, `refunded_request`) — пока статусы хардкодятся в `OrdersAdminController::STATUSES`. Это требует правки плагина, в будущей версии сделаем через хук `shop.order.statuses`.
3. **Своё поле товара** — `Доп. поля → Создать`, выбрать сущность «Товары (магазин)». Не нужно править плагин.
4. **Платёжный шлюз** (Stripe, ЮKassa, Kaspi…) — отдельный плагин, который добавляет `kind=online_gateway`-метод оплаты и маршруты `/checkout/pay/...`. В Shop v1.2 будет хук `shop.payment.process`.
5. **Email-рассылка по клиентам** — отдельный плагин, читающий `shop_customers` с фильтром `marketing_opt_in = true`.
