projects/org/pirotehnika/app/pim/ARCHITECTURE.md

PIM ARCHITECTURE — Главный документ

Версия: 4.0.0
Дата: 2025-12-27
Статус: ✅ АКТУАЛЬНЫЙ
Автор: Claude Opus (Архитектор)

ВАЖНО: Это главный документ архитектуры PIM. Все остальные документы архивированы или устарели.


КРАТКАЯ СУТЬ

PIM = Product Information Management — централизованный каталог товаров.

Основная идея:

ВХОДЫ (источники)  →  PIM (ядро)  →  ВЫХОДЫ (каналы)
1С, прайсы xlsx    →  PostgreSQL  →  OZON, сайт, отчёты

Ключевое разделение:
- Товары (pim_products) = характеристики (название, бренд, вес...)
- Цены (price_supplier_cost) = цены закупки от каждого поставщика
- Остатки (stock_inventory) = количество на каждом складе


АРХИТЕКТУРА БД

PRODUCTION: PostgreSQL (NocoDB)

Подключение:
- Host: localhost:5433
- Database: nocodb
- Schema: pt7k98pv0fwi1el
- User: nocodb

Статус: ✅ Production, 4626 товаров

Подробнее о базах: ../../data/connectors/DATABASE_ARCHITECTURE.md

5 СЛОЁВ ТАБЛИЦ

1. ТОВАРЫ (характеристики)

pim_products (4626 записей)

article          артикул (PK)
name             название
brand            бренд
category         категория
product_type     тип (салют, фонтан, ракета...)
base_price       базовая цена от производителя
weight_grams     вес

ВАЖНО: cost_price и stock_qty УДАЛЕНЫ → данные в отдельных таблицах!

2. ЦЕНЫ ОТ ПОСТАВЩИКОВ

price_supplier_cost (переименовано в v4.0)

id              SERIAL PRIMARY KEY
article         TEXT NOT NULL
supplier_code   TEXT NOT NULL  suppliers(code)
cost_price      NUMERIC NOT NULL
valid_from      TIMESTAMP       -- начало действия
valid_to        TIMESTAMP       -- конец действия (NULL = актуально)
source_file     TEXT

Пример:

Товар: JF-001
  ├─ jf:      43.92 (2025-11-01  )
  ├─ maxsem:  45.00 (2025-11-07  )
  └─ pirosnab: 48.00 (2025-12-26  )

suppliers (справочник)

code             jf, maxsem, pirosnab, gordeev...
name             JF-Pyro, Maxsem, Pirosnab...
api_type         json, xlsx, web_scraper

3. ОСТАТКИ

A. Остатки НА СКЛАДАХ (stock_inventory) — где физически лежит товар

id              SERIAL PRIMARY KEY
article         TEXT NOT NULL
warehouse_id    INTEGER  stock_warehouses(id)
quantity        INTEGER
reserved        INTEGER
available       INTEGER

stock_warehouses (склады)

id  code            name                    warehouse_type
1   gordeev_1       ИП Гордеев основной     supplier
9   pirosnab        Pirosnab Софийская      supplier
2   ozon_o1_fbo     OZON O1 FBO             marketplace

B. Остатки У ПОСТАВЩИКОВ (stock_supplier) — сколько поставщик может дать

id              SERIAL PRIMARY KEY
article         TEXT NOT NULL
supplier_code   TEXT NOT NULL  suppliers(code)
quantity        INTEGER

Разница:
- stock_inventory = физические места хранения (склад Pirosnab на Софийской)
- stock_supplier = источники закупки (сколько JF может поставить)

4. ПРАЙС-ЛИСТЫ (история импортов)

PriceList — загруженные прайсы

name             "Pirosnab прайс-лист 2025-12"
supplier_code    pirosnab
source_file      pirosnab.spb.ru (API)
loaded_at        2025-12-26 15:30

PriceListItem — позиции прайсов

pricelist_id    → PriceList
article
cost_price

Связь: PriceListItem → price_supplier_cost (при импорте)

5. ПРАВИЛА И АНАЛИТИКА


ПРОЦЕССЫ

1. Импорт товаров

1С JSON  pim_products (характеристики)

Скрипт: app/pim/import_from_1c.py
Частота: Ежедневно
Что обновляет: name, brand, category, base_price

2. Импорт цен от поставщиков

Прайс xlsx/API → PriceList + PriceListItem → supplier_cost

Примеры:
- Pirosnab: data/connectors/import_pirosnab_to_pim_v3.py (веб-скрейпер)
- Maxsem: data/scripts/import_maxsem_price.py (xlsx)
- JF: data/scripts/import_jf_price.py (json)

Что происходит:
1. Загрузить прайс → PriceList (запись о файле)
2. Парсить позиции → PriceListItem (все строки)
3. Обновить цены → price_supplier_cost (с valid_from=NOW, закрыть старые)

3. Импорт остатков

A. Остатки со складов

API склада → stock_inventory (warehouse_id, quantity)

Примеры:
- OZON API → stock_inventory (warehouse_id=2, OZON FBO)
- Pirosnab API → stock_inventory (warehouse_id=9, Pirosnab)

B. Остатки от поставщиков

Прайс поставщика → stock_supplier (supplier_code, quantity)

4. Расчёт розничной цены

# Получить лучшую цену среди поставщиков
cost, supplier = get_best_supplier_cost(article)

# Применить наценку
retail_price = cost * (1 + markup) * (1 - brand_discount)

Правила наценки: price_cost_rules, price_sale_rules


КОННЕКТОРЫ

Входящие (источники данных)

Коннектор Путь Что импортирует
1C data/scripts/sync_1c_to_nocodb.py Товары (характеристики)
Pirosnab data/connectors/import_pirosnab_to_pim_v3.py Цены + остатки
JF-Pyro data/scripts/import_jf_price.py Цены
Maxsem data/scripts/import_maxsem_price.py Цены

Исходящие (каналы продаж)

Канал Путь Что экспортирует
OZON app/mp1/ Товары + цены + остатки
Сайт pirotehnika.spb.ru OpenCart Каталог + цены
Отчёты app/pim/api/ Аналитика, выгрузки

API

Сервер: uvicorn pim.main:app --port 8000

Endpoint Метод Описание
/products GET Список товаров
/products/{article} GET Детали товара
/products/{article}/costs GET Цены от всех поставщиков
/products/{article}/stocks GET Остатки на всех складах
/suppliers/{code}/products GET Товары от поставщика
/warehouses/{code}/stocks GET Остатки на складе

КОД

Структура

app/pim/
├── api/              ← REST API (FastAPI)
│   ├── products.py
│   ├── prices.py
│   └── stocks.py
├── core/             ← Бизнес-логика
│   ├── products.py   ← ProductService
│   ├── pricing.py    ← PricingService
│   └── stocks.py     ← StocksService
├── models/           ← SQLAlchemy модели
│   ├── product.py
│   ├── supplier.py   ← NEW: Supplier, SupplierCost, SupplierStock
│   └── warehouse.py  ← Warehouse, Stock
├── utils/
│   └── supplier_helpers.py  ← NEW: get_supplier_cost(), update_supplier_cost()
└── tests/

Хелперы (v3.0)

Файл: utils/supplier_helpers.py

from utils.supplier_helpers import (
    get_supplier_cost,        # Цена от поставщика
    get_best_supplier_cost,   # Лучшая цена среди всех
    get_supplier_stock,       # Остаток у поставщика
    update_supplier_cost      # Обновить цену (с историей)
)

# Пример
cost = get_supplier_cost('JF-001', supplier_code='jf')
# → 43.92

cost, supplier = get_best_supplier_cost('JF-001')
# → (43.92, 'jf')

ДОКУМЕНТАЦИЯ

✅ АКТУАЛЬНЫЕ

Документ Описание
ARCHITECTURE.md Этот файл — главный!
standards/DATABASE.md Структура БД (будет обновлён до v3.0)
CLAUDE.md Контекст для Claude (API, процессы)
../../data/PRODUCT_DATA_STANDARD.md Стандарт работы с данными
../../data/PRODUCT_RULES.md Правила разбивки товаров
../../data/connectors/MIGRATION_PLAN.md План миграции на v3.0
../../data/connectors/ARCHITECTURE_COMPARISON.md Анализ проблемы

📦 АРХИВ

Папка: archive/2025-12-26-refactoring/

Устаревшие документы о рефакторинге (применялись к SQLite вместо PostgreSQL):
- REFACTORING_REPORT.md
- REFACTORING_FINAL_REPORT.md
- COMBINED_REFACTORING_PLAN.md
- DATA_REFACTORING_REPORT.md
- COMPLETION_REPORT.md
- PRICING_STOCK_TABLES.md

Причина архивации: Описывают SQLite базу, которая не используется в production.


МИГРАЦИЯ НА v3.0

Текущий статус

Компонент PostgreSQL SQLite Статус
pim_products ✅ 4626 товаров ✅ 424 товара Production = PostgreSQL
price_supplier_cost ✅ 3268 цен ✅ 424 цены Production = PostgreSQL
stock_supplier ✅ Есть ✅ 27 остатков Production = PostgreSQL
stock_inventory ✅ 122 остатка ❌ Нет Только в PostgreSQL
stock_warehouses ✅ 9 складов ❌ Нет Только в PostgreSQL

Статус миграции v4.0

Миграция 013 + 014 выполнена 2025-12-27:

  1. ✅ Бэкап PostgreSQL (/tmp/backup_before_013_20251227_065547.sql)
  2. ✅ Удалено 7 таблиц (5 пустых + 2 старых системы ценообразования)
  3. ✅ Переименовано 16 таблиц (11 PRICE + 5 STOCK с новыми префиксами)
  4. ✅ Объединены две системы ценообразования (3 правила мигрированы)
  5. ✅ Обновлены 6 функций и 3 VIEW с новыми именами таблиц
  6. ✅ Рефакторинг Python кода (PriceCostRule, price_supplier_cost, stock_supplier)
  7. ✅ Протестированы: модели, API, расчёт цен

Отчёт: /tmp/MIGRATION_013_014_COMPLETE_REPORT.md


ПРАВИЛА РАБОТЫ С ТОВАРАМИ

1. Типы номенклатуры 1С

Грузить в PIM только:
- ТипНоменклатуры='Запас' AND ЭтоНабор=false

Игнорировать:
- Наборы (ЭтоНабор=true)
- Услуги (ТипНоменклатуры='Услуга')

Подробнее: ../../CLAUDE.md (раздел "Правила работы с товарами")

2. Разбивка товаров по цветам/упаковкам

Пример:

От поставщика: JF-DM30 (коробка 60 шт, все цвета)
  ↓ разбивка в PIM
  JF-DM30-красный-1шт
  JF-DM30-красный-3шт
  JF-DM30-синий-1шт
  ...

Подробнее: ../../data/PRODUCT_RULES.md


СВЯЗИ


ИСТОРИЯ ВЕРСИЙ

Версия Дата Изменения
4.0.0 2025-12-27 BREAKING: Переименованы все таблицы PRICE/STOCK с префиксами. Объединены системы ценообразования (миграции 013+014)
3.0.0 2025-12-26 Разделение цен (supplier_cost) и остатков (supplier_stock, stocks)
2.0.0 2025-12-25 Добавлены warehouses, stocks, PriceList/PriceListItem
1.0.0 2025-12-23 Первая версия PIM на PostgreSQL NocoDB

Версия: 4.0.0
Автор: Claude Opus (Архитектор)
Дата: 2025-12-27

Для Claude: При любых вопросах по PIM — читать этот файл первым. Он актуальный и главный.