┌─────────────────────────────────────────────────────────────┐
│ ИСТОЧНИКИ ИСТИНЫ ПО ТИПАМ ДАННЫХ │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Номенклатура (артикулы, названия) │
│ ✓ Эталон: 1С (главная учетная система) │
│ ✓ Таблица: 1c_products (READ-ONLY клон 1С) │
│ │
│ 2. Цены и характеристики │
│ ✓ Эталон: PIM (обогащенные данные) │
│ ✓ Таблица: pim_products (мастер-данные) │
│ │
│ 3. Правила ценообразования │
│ ✓ Эталон: PIM │
│ ✓ Таблица: price_cost_rules │
│ │
│ 4. Сырые данные от поставщиков │
│ ✓ Эталон: Файлы + метаданные в БД │
│ ✓ Хранение: файловая система + таблица staging │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ ШАГ 1: Синхронизация номенклатуры из 1С │
└─────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────┐
│ 1C Export (JSON/XML) │
└────────────────────────┘
│
▼
┌────────────────────────┐
│ Импорт в 1c_products │ ← READ-ONLY таблица
│ (полная перезапись) │ (клон 1С)
└────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ШАГ 2: Анализ и валидация │
└─────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────┐
│ Поиск ошибок: │
│ - Пустые названия │
│ - Дубли артикулов │
│ - Отсутствие цен │
│ - Невалидные данные │
└────────────────────────┘
│
▼
┌────────────────────────┐
│ Логирование ошибок │
│ → pim_validation_log │
└────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ШАГ 3: Обогащение в PIM │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┴────────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────────┐
│ Новые товары │ │ Существующие товары │
│ из 1c_products │ │ обновление данных │
└──────────────────┘ └──────────────────────┘
│ │
└─────────────────┬────────────────┘
▼
┌────────────────────────┐
│ 1. Применить правила │
│ ценообразования │
│ 2. Добавить характ-ки │
│ 3. Обновить описания │
│ │
│ → pim_products │ ← MASTER данные
└────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ ШАГ 4: Экспорт обратно в 1С │
└─────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────┐
│ Формирование файла │
│ для импорта в 1С: │
│ - cost_price │
│ - updated_description │
│ - characteristics │
└────────────────────────┘
│
▼
┌────────────────────────┐
│ 1С Import │
│ (обновление цен) │
└────────────────────────┘
Рассмотрим типы данных:
Характеристики:
- Файлы Excel/CSV/PDF (1-5 МБ каждый)
- Приходят 1-2 раза в неделю
- Нужно хранить историю (для аудита)
- Структура файлов разная у каждого бренда
Решение: Файловая система + метаданные в БД
/data/price-lists/
├── ФЕЙЕРВЕРК/
│ ├── 2024-01-15_price.xlsx
│ ├── 2024-01-22_price.xlsx
│ └── 2024-01-29_price.xlsx
├── САЛЮТ/
│ ├── 2024-01-10_catalog.csv
│ └── 2024-01-20_catalog.csv
└── ...
БД: pim_price_file_uploads
├── id
├── brand
├── file_path ← путь к файлу
├── upload_date
├── file_size
├── file_hash ← для дедупликации
├── parsed_status ← 'pending', 'parsed', 'error'
└── parsed_at
Почему файлы:
- ✓ Сохраняем оригинал (аудит)
- ✓ Не раздуваем БД
- ✓ Можно переобработать при ошибке
- ✓ Легко бэкапить
Характеристики:
- Структурированные данные после парсинга
- Временные (промежуточные)
- Нужна валидация перед импортом в pim_products
Решение: Staging таблица в БД
CREATE TABLE pim_staging_products (
id SERIAL PRIMARY KEY,
-- Источник
upload_id INTEGER REFERENCES pim_price_file_uploads(id),
brand VARCHAR(100),
-- Данные товара (как распознали из файла)
article VARCHAR(100),
name TEXT,
base_price NUMERIC(10, 2),
characteristics JSONB, -- гибкая структура
-- Статус обработки
status VARCHAR(20), -- 'pending', 'matched', 'imported', 'error'
matched_article VARCHAR(100), -- сопоставленный артикул из 1c_products
match_confidence NUMERIC(3, 2), -- 0.0 - 1.0
-- Ошибки
validation_errors JSONB,
-- Метаданные
created_at TIMESTAMP DEFAULT NOW(),
processed_at TIMESTAMP
);
Почему staging в БД:
- ✓ Удобно делать SQL-запросы для сопоставления
- ✓ Можно хранить статус обработки
- ✓ Легко показать в UI для ручной модерации
- ✓ Очищаем после успешного импорта
Характеристики:
- Изображения (JPG/PNG, 100-500 КБ)
- HTML описания
- Сертификаты (PDF)
Решение: Комбинированное
Изображения → S3/MinIO + URL в БД
/images/products/
├── ФЕЙЕРВЕРК/
│ ├── ART123_main.jpg
│ ├── ART123_gallery_1.jpg
│ └── ...
└── ...
Описания → БД (TEXT/JSONB)
pim_products.description_html
Сертификаты → Файловая система + URL в БД
/data/certificates/
├── ФЕЙЕРВЕРК/
│ ├── cert_2024.pdf
│ └── ...
└── ...
Таблица метаданных:
CREATE TABLE pim_product_images (
id SERIAL PRIMARY KEY,
article VARCHAR(100) REFERENCES pim_products(article),
image_url VARCHAR(500), -- URL в S3/CDN
image_type VARCHAR(20), -- 'main', 'gallery', 'certificate'
source VARCHAR(100), -- откуда получено
downloaded_at TIMESTAMP,
file_size INTEGER,
is_active BOOLEAN DEFAULT TRUE
);
┌─────────────────────────────────────────────────────────────┐
│ ТИП ДАННЫХ │ ХРАНИЛИЩЕ │ ТАБЛИЦА │
├─────────────────────────────────────────────────────────────┤
│ │
│ Номенклатура из 1С │ PostgreSQL │ 1c_products (клон, read-only)
│ │ │ │
│ Мастер-данные PIM │ PostgreSQL │ pim_products (эталон цен)
│ │ │ │
│ Сырые прайсы │ Файловая система │ pim_price_file_uploads (метаданные)
│ │ /data/price-lists/ │ │
│ │ │ │
│ Staging (парсинг) │ PostgreSQL │ pim_staging_products (временные)
│ │ │ │
│ Изображения товаров │ S3 / MinIO │ pim_product_images (URLs)
│ │ │ │
│ Сертификаты │ Файловая система │ pim_product_images (URLs)
│ │ /data/certificates/│ │
│ │ │ │
│ Логи синхронизации │ PostgreSQL │ pim_import_logs
│ │ │ │
│ История цен │ PostgreSQL │ pim_price_history
│ │ │ │
│ Ошибки валидации │ PostgreSQL │ pim_validation_log
│ │ │ │
└─────────────────────────────────────────────────────────────┘
class PimPriceFileUpload(Base):
"""Загруженные файлы прайсов"""
__tablename__ = "pim_price_file_uploads"
id = Column(Integer, primary_key=True)
brand = Column(String(100), nullable=False)
file_path = Column(String(500), nullable=False)
file_name = Column(String(255), nullable=False)
file_size = Column(Integer)
file_hash = Column(String(64)) # SHA256 для дедупликации
uploaded_at = Column(DateTime, default=datetime.utcnow)
uploaded_by = Column(String(100)) # user ID
parsed_status = Column(String(20), default='pending') # pending, parsed, error
parsed_at = Column(DateTime)
parsed_count = Column(Integer) # кол-во распознанных товаров
parse_errors = Column(Text)
class PimStagingProduct(Base):
"""Staging таблица для импорта из парсеров"""
__tablename__ = "pim_staging_products"
id = Column(Integer, primary_key=True)
upload_id = Column(Integer, ForeignKey('pim_price_file_uploads.id'))
# Источник данных
brand = Column(String(100))
source = Column(String(50)) # 'price_parser', 'site_parser', 'manual'
# Распознанные данные
article = Column(String(100))
name = Column(Text)
base_price = Column(Numeric(10, 2))
characteristics = Column(JSON) # гибкая структура
# Сопоставление с существующими товарами
status = Column(String(20), default='pending') # pending, matched, imported, error
matched_article = Column(String(100)) # артикул из 1c_products
match_confidence = Column(Numeric(3, 2)) # 0.0-1.0
match_method = Column(String(50)) # 'exact', 'fuzzy', 'manual'
# Валидация
validation_errors = Column(JSON)
is_valid = Column(Boolean, default=False)
# Метаданные
created_at = Column(DateTime, default=datetime.utcnow)
processed_at = Column(DateTime)
processed_by = Column(String(100))
class PimValidationLog(Base):
"""Лог ошибок валидации"""
__tablename__ = "pim_validation_log"
id = Column(Integer, primary_key=True)
# Что проверяли
table_name = Column(String(50)) # '1c_products', 'staging', 'pim_products'
record_id = Column(String(100)) # article или ID
# Ошибка
error_type = Column(String(50)) # 'missing_field', 'invalid_price', 'duplicate'
error_message = Column(Text)
severity = Column(String(20)) # 'error', 'warning', 'info'
# Контекст
import_log_id = Column(Integer, ForeignKey('pim_import_logs.id'))
detected_at = Column(DateTime, default=datetime.utcnow)
# Исправление
resolved = Column(Boolean, default=False)
resolved_at = Column(DateTime)
resolved_by = Column(String(100))
resolution_note = Column(Text)
1. ЗАГРУЗКА ПРАЙСА
├─→ Сохраняем файл в /data/price-lists/BRAND/
├─→ Создаем запись в pim_price_file_uploads
└─→ file_hash проверяет дубли
2. ПАРСИНГ
├─→ Читаем файл
├─→ Извлекаем данные → pim_staging_products
├─→ Обновляем pim_price_file_uploads.parsed_status = 'parsed'
└─→ Количество записей → parsed_count
3. ВАЛИДАЦИЯ STAGING
├─→ Проверяем обязательные поля
├─→ Проверяем диапазоны цен
├─→ Ошибки → pim_validation_log
└─→ Статус → validation_errors, is_valid
4. СОПОСТАВЛЕНИЕ (MATCHING)
├─→ Точное совпадение по article
├─→ Fuzzy matching по name
├─→ Записываем matched_article, match_confidence
└─→ Низкая уверенность → ручная модерация
5. ИМПОРТ В PIM_PRODUCTS
├─→ Только is_valid = TRUE
├─→ Создаем/обновляем pim_products
├─→ История → pim_price_history
├─→ Лог → pim_import_logs
└─→ Обновляем staging.status = 'imported'
6. ОЧИСТКА STAGING
└─→ Удаляем успешно импортированные записи старше 30 дней
1C → номенклатура (артикулы, базовая информация)
↓
1c_products (read-only клон)
↓
PIM → цены, характеристики, обогащение
↓
pim_products (master-данные)
↓
1C ← обновленные цены и данные
Файлы < 1 МБ, структурированные → БД
Файлы > 1 МБ, бинарные → Файловая система
Изображения → S3/MinIO/CDN
Все внешние данные сначала → staging
Валидация → staging
Модерация → staging
Импорт → master таблицы
Где хранить:
| Тип данных | Хранилище | Причина |
|---|---|---|
| Номенклатура 1С | 1c_products (БД) |
Клон 1С, read-only |
| Мастер-данные | pim_products (БД) |
Источник истины для цен |
| Сырые прайсы | Файлы + метаданные | Аудит, переобработка |
| Staging парсинга | pim_staging_products (БД) |
Валидация, модерация |
| Изображения | S3 + URLs в БД | Масштабируемость |
| Сертификаты | Файлы + URLs в БД | Долгосрочное хранение |
Поток данных:
1С → 1c_products → Валидация → Обогащение → pim_products → Экспорт → 1С
↑
Парсеры → Staging → Валидация → Matching
Создавать реализацию?