# Генератор этикеток и штрихкодов (v1.0)

## Скрипты

| Скрипт | Назначение |
|--------|-----------|
| `barcode_gen.py` | Генерация штрихкода (EAN-13, Code128, EAN-8) → PNG |
| `label_builder.py` | Сборка этикетки: баркод + текстовые поля + знаки |
| `pdf_builder.py` | Компоновка в PDF: A4 сетка или термоэтикетки |
| `batch_labels.py` | Пакетная генерация из списка товаров |

## Быстрый старт

### Одна этикетка
Импорты — из единого фасада `labels`: он реэкспортит `barcode_gen`, `batch_labels`, `label_builder`, `pdf_builder`,
поэтому `from labels import <примитив>` резолвится всегда — под-модуль угадывать не нужно.

```python
from labels import build_label
path = build_label(
    name="Футболка мужская",
    barcode_value="4680000000001",
    brand="MyBrand",
    article="FT-001",
    composition="хлопок 100%",
    country="Китай",
    size="XL",
    marks=["EAC"],
    label_size="58x40",
    output_path=cw.output_path("label.png"),
)
```

### Пакетная генерация → PDF
```python
from labels import batch_generate
products = [
    {"name": "Футболка", "barcode": "4680000000001", "brand": "Brand", "qty": 10},
    {"name": "Джинсы", "barcode": "4680000000002", "article": "J-100", "qty": 5},
]
path = batch_generate(
    products,
    label_size="58x40",
    page_format="a4",        # "a4" | "58x40" | "58x30" | "40x30"
    preset="70x37",           # A4 раскладка
    output_path=cw.output_path("labels.pdf"),
)
```

### Только штрихкод
```python
from labels import generate_barcode
path = generate_barcode("4680000000001", fmt="ean13")
```

### Свой PDF из готовых этикеток
```python
from labels import build_pdf_a4, build_pdf_thermal
# A4
build_pdf_a4(["l1.png", "l2.png"], quantities=[10, 5], preset="70x37")
# Термо
build_pdf_thermal(["l1.png"], quantities=[20], page_size="58x40")
```

## Параметры этикетки

| Параметр | Описание | Обязательный |
|----------|----------|:---:|
| name | Название товара | Да |
| barcode_value | Значение штрихкода | Да |
| barcode_format | ean13 / code128 / ean8 | Нет (ean13) |
| brand | Бренд | Нет |
| article | Артикул | Нет |
| composition | Состав | Нет |
| country | Страна производства | Нет |
| size | Размер | Нет |
| color | Цвет | Нет |
| marks | ["EAC", "РСТ"] | Нет |
| custom_fields | {"Телефон": "+7..."} | Нет |

## Размеры этикеток

| Код | Размер | Применение |
|-----|--------|------------|
| 58x40 | 58x40 мм | Стандартная термоэтикетка |
| 58x30 | 58x30 мм | Компактная термоэтикетка |
| 40x30 | 40x30 мм | Малая термоэтикетка |
| 43x25 | 43x25 мм | Ювелирная этикетка |
| (W, H) | Произвольный | tuple в мм |

## A4 раскладки (preset)

| Пресет | Ячейка | Сетка | На листе |
|--------|--------|-------|----------|
| 70x37 | 70x37 мм | 3x8 | 24 |
| 52.5x29.7 | 52.5x29.7 мм | 4x10 | 40 |
| 70x42.3 | 70x42.3 мм | 3x7 | 21 |
| 105x48 | 105x48 мм | 2x6 | 12 |

## Интеграция с маркетплейсами

### Импорт товаров из WB
```
connector(service="wildberries", action="POST /content/v2/get/cards/list", params={"settings": {"cursor": {"limit": 100}, "filter": {"withPhoto": -1}}})
```
Маппинг: `title` → name, `vendorCode` → article, `sizes[].skus[]` → barcode.

### Импорт товаров из Ozon
```
connector(service="ozon", action="POST /v3/product/list", params={"filter": {"visibility": "ALL"}, "last_id": "", "limit": 1000})
```
`filter` обязателен (минимум `{"visibility": "ALL"}`) — иначе 400. Пагинация по `last_id`.

Затем батч-инфо (до 1000 id за раз):
```
connector(service="ozon", action="POST /v3/product/info/list", params={"offer_id": ["SKU-001", "SKU-002"]})
```
Принимает любой из массивов: `product_id[] | offer_id[] | sku[]`.

Маппинг: `items[].name` → name, `items[].offer_id` → article, `items[].barcodes[0]` → barcode_value.

### FBO этикетки
Для FBO поставок используй SKU-баркоды маркетплейса:
- WB: `barcode` из карточки товара (поле `sizes[].skus[]`)
- Ozon: `barcode` из карточки товара (см. секцию «Импорт товаров из Ozon» выше)

Генерируй информационные этикетки с этими баркодами через `batch_generate()`.

### FBS стикеры
Стикеры заказов получаются через API маркетплейса (готовые файлы):
- WB: `connector(service="wildberries", action="POST /api/v3/orders/stickers", params={"orders": [id1, id2]})`
- Ozon: `connector(service="ozon", action="POST /v2/posting/fbs/package-label", params={"posting_number": ["..."]})`

Скачай стикеры через коннектор. При необходимости объедини несколько PDF через `pdf_builder`.

## Запреты

- Не генерируй невалидные EAN-13 (должно быть 12 цифр + контрольная, библиотека считает сама).
- Не хардкодь контрольную цифру EAN-13 — передавай 12 цифр, `python-barcode` добавит 13-ю.
- Для Code128 допустимы буквы и символы.

## Пути

| Что | Путь |
|-----|------|
| Временные файлы | /tmp/ |
| Результат | /home/user/output/ |

## Перед отдачей

- Убедись что файл сгенерирован без ошибок
- `present_files` для отдачи результата пользователю
