# CSV / Excel импорт-экспорт

## Импорт CSV (`/admin/shop/products/import`)

Массовая загрузка каталога. Формат — UTF-8 с BOM (совместимо с Excel и LibreOffice). Размер ограничен `php.ini upload_max_filesize`.

### Разделитель

Можно выбрать запятую (`,`), точку с запятой (`;`) или табуляцию. По умолчанию — запятая.

### Логика обновления

Для каждой строки CSV:

1. Если есть `id` и товар найден — `UPDATE` по id.
2. Иначе — UPSERT по `slug`. Если `slug` пустой — генерируется из `title` (с транслитерацией кириллицы).
3. `manufacturer` и `category` ищутся по `slug`. Если не найдены — `null`.

### Структура CSV (колонки)

Первая строка — заголовки. Поддерживаемые имена (lowercase):

```
id, slug, title, sku, barcode, price, old_price, stock, status,
is_featured, manufacturer, category, short, body,
seo_title, seo_description, cover
```

Лишние колонки игнорируются. Отсутствующие — пустые/дефолтные значения.

### Результат

После запуска показывается отчёт: сколько добавлено / обновлено / пропущено, и до 20 первых ошибок с указанием номера строки.

## Экспорт (`/admin/shop/products/export`)

Не «один-кликом», а с **выбором формата и колонок** — это форма.

### Формат

- **Excel (.xlsx)** — реальный OOXML-файл, генерируется встроенным `XlsxWriter` без внешних зависимостей. Числа сохраняются числами (для сумм и фильтров), строки строками. Заголовок — жирным.
- **CSV (.csv)** — UTF-8 с BOM для Excel.

### Какие колонки

Все 22 поля каталога сгруппированы по разделам:

- **Основное**: id, slug, title, sku, barcode
- **Цены и склад**: price, old_price, stock
- **Публикация**: status, is_featured
- **Связи**: manufacturer (slug), category (slug)
- **Тексты**: short, body
- **SEO**: seo_title, seo_description
- **Медиа**: cover (URL)
- **Метрики**: rating_avg, rating_count, views
- **Даты**: created_at, updated_at

Дефолтный набор отмечен галками (id, slug, title, sku, price, stock, status, manufacturer, category). Кнопки «Выделить все» / «Снять все» / «По умолчанию».

### Что включать (scope)

Селект: все товары / только активные / только черновики / только архив. Со счётчиками рядом.

### Совместимость

Экспортированный файл со включёнными колонками `id` и `slug` можно вернуть обратно через импорт — для массового редактирования цен / остатков в Excel и upload'а назад.

## XLSX-генератор

`Celena\Plugin\Shop\Support\XlsxWriter` — минимальный writer:

```php
$w = new XlsxWriter('Products');
$w->writeRow(['ID', 'Title', 'Price'], header: true);
foreach ($rows as $r) {
    $w->writeRow([$r['id'], $r['title'], (float) $r['price']]);
}
$bytes = $w->finish();   // готовый .xlsx
```

Поддерживаемые типы ячеек определяются автоматически: int/float → число, bool → 1/0, null → пустая, string → inlineStr. Длинные числовые строки (>15 символов) сохраняются как строки, чтобы не терялась точность.
