Версия: 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 — обработка
| Параметр | Значение | Обоснование |
|---|---|---|
| Формат | JPEG (.jpg) | Универсальный, сжатие |
| Качество | 85% | Баланс размер/качество |
| Размер | 800×800 px | Минимум для маркетплейсов |
| Фон | Белый (#FFFFFF) | Стандарт e-commerce |
| Прозрачность | Удалена | JPEG не поддерживает |
# Конвертация с белым фоном
convert input.png \
-background white \
-alpha remove \
-alpha off \
-resize 800x800\> \
-quality 85 \
output.jpg
Флаги:
- -background white — белый фон вместо прозрачности
- -alpha remove — удалить альфа-канал
- -resize 800x800\> — уменьшить если больше, не увеличивать
- -quality 85 — качество JPEG
# Все 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
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)
$DATASPACE/projects/pirotehnika/
├── images/ ← Обработанные фото
│ └── products/ ← По артикулам
│ ├── {article}.jpg ← Основное фото
│ └── {article}_2.jpg ← Дополнительные
│
├── originals/ ← Исходники (backup)
│ └── {source}/ ← По источникам
│ └── {article}_orig.{ext}
│
└── certificates/ ← Сертификаты PDF
└── {article}_cert.pdf
| Поле | Тип | Описание | Пример |
|---|---|---|---|
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/... |
| Тип | Формат | Пример |
|---|---|---|
| Основное фото | {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 |
| Источник | Тип | Поля | Приоритет |
|---|---|---|---|
| 1С OData | API | article, name, code_1c, brand | 1 (основной) |
| Прайсы xlsx | Файл | article, price, stock | 2 |
| Сайты производителей | Scraper | photo, caliber, effects | 3 |
| Ручной ввод | UI | любые | 4 |
ИСТОЧНИК STAGING PIM
━━━━━━━━ ━━━━━━━ ━━━
pim_price_file_uploads
1С OData ────────────────────────────────────────────► pim_products
pim_pirotehnika
Прайс xlsx ─────► pim_staging_products ─────────────► (merge)
↓
pim_validation_log
Scraper (фото) ──────────────────────────────────────► (enrich)
pim_price_file_uploads (status: pending)pim_staging_products (status: processing)pim_validation_log (ошибки)pim_products + pim_pirotehnika| Поле | Правило | Действие при ошибке |
|---|---|---|
article |
Обязателен, < 50 симв | Пропустить запись |
name |
Обязателен | Генерировать из article |
brand |
Из справочника | Установить "Unknown" |
price |
Число ≥ 0 | Установить 0 |
caliber |
Число или пустой | Пустой |
shots |
Целое ≥ 0 | 0 |
photo_urls |
Массив URL | Пустой массив |
Набор — это комплект из нескольких единиц базового товара, созданный в 1С для продажи на маркетплейсах.
Базовый товар: MA0511 ← 1 хлопушка
Наборы: MA0511_x4 ← 4 хлопушки
MA0511_x10 ← 10 хлопушек
| Источник | Поле | Значение | Описание |
|---|---|---|---|
1С (таблица 1c_pim) |
is_bundle |
true |
Официальный маркер |
| Артикул | паттерн | _x[0-9]+$ |
Суффикс количества |
| Название | текст | НАБОР, N шт, N штук |
Ключевые слова |
Наборы ИСКЛЮЧАЮТСЯ из 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;
Файл: 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
| Тип | Кол-во | Действие |
|---|---|---|
Наборы по is_bundle=true |
161 | Деактивированы |
Наборы по паттерну _x |
269 | Деактивированы |
Услуги USL-* |
28 | Деактивированы |
| Итого исключено | 458 | — |
| # | Категория | 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 |
{Группа} {Тип} {Калибр} {Залпы} {Эффекты} {Имя} {Артикул} {Бренд}
Пример:
Салют веерный 1.2" 25 выстрелов 8 эффектов Бабочка НФ7302 Народный Фейерверк
| 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 |
| 1С поле | PIM поле | Примечание |
|---|---|---|
| Ref_Key | ref_key_1c | UUID |
| Code | code_1c | НФ-NNNNNNNN |
| Артикул | article | PK |
| Description | name_short | 150 симв |
| Наименование | name | Полное |
| БазоваяЕдиницаИзмерения | — | (не используем) |
| Parent_Key | category | через lookup |
| Производитель → Наименование | brand |
| Скрипт | Назначение | Путь |
|---|---|---|
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/ |
| Endpoint | Метод | Назначение |
|---|---|---|
/products |
GET | Список товаров |
/products/{article} |
GET | Один товар |
/products/{article}/images |
POST | Загрузить фото |
/prices/upload |
POST | Загрузить прайс |
/sync/1c |
POST | Синхронизация с 1С |
Переместить в архив после консолидации:
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 |
Схема БД |
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