projects/org/pirotehnika/data/PRODUCT_DATA_STANDARD.md

Стандарт работы с данными товаров

Версия: 1.0.0
Дата: 2025-12-24
Статус: МАСТЕР-ДОКУМЕНТ


НАЗНАЧЕНИЕ

Единый стандарт работы с товарами:
- Загрузка данных
- Хранение изображений
- Обработка фото
- Структура каталога

Консолидирует:
- app/pim/PIM_MASTER_STANDARD.md — структура БД, маппинг
- data/PIM_CLASSIFICATION.md — 20 категорий, названия
- data/SESSION_2025-12-13_IMAGES.md — загрузка изображений
- app/site/.../PNG_TO_JPEG_CONVERSION_2025-11-14.md — обработка


1. ИЗОБРАЖЕНИЯ

1.1 Стандарт обработки

Параметр Значение Обоснование
Формат JPEG (.jpg) Универсальный, сжатие
Качество 85% Баланс размер/качество
Размер 800×800 px Минимум для маркетплейсов
Фон Белый (#FFFFFF) Стандарт e-commerce
Прозрачность Удалена JPEG не поддерживает

1.2 Команда обработки (ImageMagick)

# Конвертация с белым фоном
convert input.png \
  -background white \
  -alpha remove \
  -alpha off \
  -resize 800x800\> \
  -quality 85 \
  output.jpg

Флаги:
- -background white — белый фон вместо прозрачности
- -alpha remove — удалить альфа-канал
- -resize 800x800\> — уменьшить если больше, не увеличивать
- -quality 85 — качество JPEG

1.3 Пакетная обработка

# Все PNG в папке → JPEG
for f in *.png; do
  convert "$f" -background white -alpha remove -alpha off -resize 800x800\> -quality 85 "${f%.png}.jpg"
done

# Удалить оригиналы после проверки
# rm *.png

1.4 Python обработка (Pillow)

from PIL import Image

def process_image(input_path: str, output_path: str):
    """Обработать изображение по стандарту"""
    img = Image.open(input_path)

    # Конвертировать RGBA → RGB с белым фоном
    if img.mode in ('RGBA', 'LA', 'P'):
        background = Image.new('RGB', img.size, (255, 255, 255))
        if img.mode == 'P':
            img = img.convert('RGBA')
        background.paste(img, mask=img.split()[-1] if 'A' in img.mode else None)
        img = background
    elif img.mode != 'RGB':
        img = img.convert('RGB')

    # Resize если больше 800x800 (сохраняя пропорции)
    img.thumbnail((800, 800), Image.Resampling.LANCZOS)

    # Сохранить JPEG качество 85%
    img.save(output_path, 'JPEG', quality=85, optimize=True)

2. ХРАНЕНИЕ

2.1 Структура хранилищ

$DATASPACE/projects/pirotehnika/
├── images/                      ← Обработанные фото
│   └── products/                ← По артикулам
│       ├── {article}.jpg        ← Основное фото
│       └── {article}_2.jpg      ← Дополнительные
│
├── originals/                   ← Исходники (backup)
│   └── {source}/                ← По источникам
│       └── {article}_orig.{ext}
│
└── certificates/                ← Сертификаты PDF
    └── {article}_cert.pdf

2.2 Поля в БД (pim_pirotehnika)

Поле Тип Описание Пример
photo_url TEXT Внешняя ссылка (источник) https://jf-pyro.ru/.../img.jpg
photo_hub VARCHAR(500) Путь на HUB files.0kt.ru/pirotehnika/images/...
video_youtube VARCHAR(200) YouTube видео https://youtube.com/watch?v=...
video_rutube VARCHAR(200) RuTube видео https://rutube.ru/video/...

2.3 Именование файлов

Тип Формат Пример
Основное фото {article}.jpg JFC20-100.jpg
Галерея {article}_{N}.jpg JFC20-100_2.jpg
Сертификат {article}_cert.pdf JFC20-100_cert.pdf
Оригинал {article}_orig.{ext} JFC20-100_orig.png

3. ЗАГРУЗКА ДАННЫХ

3.1 Источники

Источник Тип Поля Приоритет
1С OData API article, name, code_1c, brand 1 (основной)
Прайсы xlsx Файл article, price, stock 2
Сайты производителей Scraper photo, caliber, effects 3
Ручной ввод UI любые 4

3.2 Поток данных

ИСТОЧНИК                      STAGING                     PIM
━━━━━━━━                      ━━━━━━━                     ━━━
                              pim_price_file_uploads
1С OData ────────────────────────────────────────────► pim_products
                                                       pim_pirotehnika

Прайс xlsx ─────► pim_staging_products ─────────────►  (merge)
                         
                  pim_validation_log

Scraper (фото) ──────────────────────────────────────► (enrich)

3.3 Алгоритм импорта

  1. Загрузка файлаpim_price_file_uploads (status: pending)
  2. Парсингpim_staging_products (status: processing)
  3. Валидацияpim_validation_log (ошибки)
  4. Маппинг → применить правила полей
  5. Сохранениеpim_products + pim_pirotehnika
  6. Статус → status: imported

3.4 Валидация

Поле Правило Действие при ошибке
article Обязателен, < 50 симв Пропустить запись
name Обязателен Генерировать из article
brand Из справочника Установить "Unknown"
price Число ≥ 0 Установить 0
caliber Число или пустой Пустой
shots Целое ≥ 0 0
photo_urls Массив URL Пустой массив

4. ФИЛЬТРАЦИЯ НАБОРОВ (1С)

4.1 Что такое набор

Набор — это комплект из нескольких единиц базового товара, созданный в 1С для продажи на маркетплейсах.

Базовый товар:  MA0511         ← 1 хлопушка
Наборы:         MA0511_x4      ← 4 хлопушки
                MA0511_x10     ← 10 хлопушек

4.2 Как определить набор

Источник Поле Значение Описание
(таблица 1c_pim) is_bundle true Официальный маркер
Артикул паттерн _x[0-9]+$ Суффикс количества
Название текст НАБОР, N шт, N штук Ключевые слова

4.3 Правило работы

Наборы ИСКЛЮЧАЮТСЯ из PIM:
- is_active = false
- review_comment = 'Набор 1С (is_bundle=true)'

SQL для деактивации:

-- По флагу 1С
UPDATE pim_products p
SET is_active = false,
    review_comment = 'Набор 1С (is_bundle=true)'
FROM "1c_pim" c
WHERE p.article = c.article
  AND c.is_bundle = true
  AND p.is_active = true;

-- По паттерну артикула (резервный)
UPDATE pim_products
SET is_active = false,
    review_comment = 'Набор 1С - исключён из работы'
WHERE article ~ '_x[0-9]+$'
  AND is_active = true;

4.4 Автоматическая фильтрация при импорте

Файл: app/pim/import_from_1c.py → функция validate_1c_record()

При импорте из 1С автоматически пропускаются:

# Услуги
if article.startswith('USL-'):
    return SKIP

# Наборы по паттерну
if re.search(r'[-_]x[0-9]+$', article):
    return SKIP

# Наборы по флагу
if record.get('is_bundle', False):
    return SKIP

4.5 Статистика (2025-12-24)

Тип Кол-во Действие
Наборы по is_bundle=true 161 Деактивированы
Наборы по паттерну _x 269 Деактивированы
Услуги USL-* 28 Деактивированы
Итого исключено 458

5. КАТЕГОРИИ ТОВАРОВ

5.1 20 категорий (из PIM_CLASSIFICATION.md)

# Категория GUID 1С Ключевые поля
1 Салюты и фейерверки 0699197f... caliber, shots, effects
2 Римские свечи 414d8f60... caliber, shots, barrels
3 Ракеты ... caliber, shots
4 Фонтаны ... height, duration
5 Петарды ... class, pack_qty
6 Бенгальские огни ... length, duration, color
7 Дневные фейерверки ... color, duration
8 Дымовые шашки ... color, duration
9 Свечи холодного огня ... height, duration
10 Хлопушки ... size, content
11 Наземные ... type, duration
12 Профессиональные ... class, weight
13 Связки ... items_count
14 Комплекты ... items_list
15 Упаковка ... qty
16 Стойки/подставки ... size
17 Запуск ... type
18 Средства защиты ... type
19 Аксессуары ... type
20 Сувениры ... type

5.2 Шаблон названия

{Группа} {Тип} {Калибр} {Залпы} {Эффекты} {Имя} {Артикул} {Бренд}

Пример:

Салют веерный 1.2" 25 выстрелов 8 эффектов Бабочка НФ7302 Народный Фейерверк

6. МАППИНГ ПОЛЕЙ

6.1 Scraper → PIM

JSON (scraper) PIM таблица PIM поле Преобразование
article pim_products article trim, upper
name pim_products name trim
price pim_products base_price float, ×100 → коп
source pim_products brand map: jf-pyro.ru → JF-Pyro
caliber pim_pirotehnika caliber_inch float
caliber pim_pirotehnika caliber_mm ×25.4
shots pim_pirotehnika shots_count int
duration pim_pirotehnika duration_sec int
height pim_pirotehnika height_mm ×1000 (м→мм)
effects pim_pirotehnika effects text
photo_urls[0] pim_pirotehnika photo_url first URL
video_url pim_pirotehnika video_youtube if youtube

6.2 1С → PIM (из 1C_PIM_MASTER_MAPPING.md)

1С поле PIM поле Примечание
Ref_Key ref_key_1c UUID
Code code_1c НФ-NNNNNNNN
Артикул article PK
Description name_short 150 симв
Наименование name Полное
БазоваяЕдиницаИзмерения (не используем)
Parent_Key category через lookup
Производитель → Наименование brand

7. API и СКРИПТЫ

7.1 Ключевые скрипты

Скрипт Назначение Путь
scraper_jfpyro.py Парсинг jf-pyro.ru app/pim/scrapers/
scraper_maxsem.py Парсинг maxsem.ru app/pim/scrapers/
import_manufacturer_data.py Импорт JSON в PIM app/pim/ (создать)
upload_images_to_hub.py Загрузка фото app/pim/scripts/
sync_images_to_1c.py Синхр. фото в 1С app/pim/scripts/

7.2 REST API (FastAPI)

Endpoint Метод Назначение
/products GET Список товаров
/products/{article} GET Один товар
/products/{article}/images POST Загрузить фото
/prices/upload POST Загрузить прайс
/sync/1c POST Синхронизация с 1С

8. АРХИВ ДОКУМЕНТОВ

Переместить в архив после консолидации:

projects/org/pirotehnika/
├── data/
│   ├── SESSION_2025-12-13_IMAGES.md      → archive/
│   └── PIM_CLASSIFICATION.md             → остаётся (справочник)
│
├── app/pim/
│   ├── PIM_MASTER_STANDARD.md            → остаётся (БД схема)
│   ├── ALGORITHM_1C_SYNC.md              → archive/
│   ├── ALGORITHM_PIM_UPDATE.md           → archive/
│   ├── DATA_COMPLETENESS_REPORT_*.md     → archive/
│   └── DISCUSSION_*.md                   → archive/
│
└── app/site/.../management/
    ├── PNG_TO_JPEG_CONVERSION_*.md       → archive/
    ├── IMAGE_RESTORATION_*.md            → archive/
    └── MASS_DOWNLOAD_*.md                → archive/

Оставить актуальными:

Документ Назначение
data/PRODUCT_DATA_STANDARD.md ЭТОТ ФАЙЛ — мастер
data/PIM_CLASSIFICATION.md Справочник категорий
app/pim/CLAUDE.md Точка входа PIM
app/pim/PIM_MASTER_STANDARD.md Схема БД

9. БЫСТРЫЙ СТАРТ

Загрузить спарсенные данные

cd /opt/claude-workspace/projects/org/pirotehnika/app/pim

# 1. Проверить JSON
python -c "import json; print(json.load(open('/mnt/beget-s3/projects/pirotehnika/data/processed/MAXSEM_PARSED_2025-12-24.json'))['count'])"

# 2. Импортировать (после создания скрипта)
python import_manufacturer_data.py \
  --file /mnt/beget-s3/.../MAXSEM_PARSED_2025-12-24.json \
  --brand "Maxsem"

# 3. Обработать фото
python scripts/upload_images_to_hub.py --limit 100

Обработать одно фото

# ImageMagick
convert input.png -background white -alpha remove -resize 800x800\> -quality 85 output.jpg

Версия: 1.0.0 | Дата: 2025-12-24