Версия: 1.0.0
Дата: 2025-12-24
┌─────────────────────────────────────────────────────────────────────┐
│ УНИВЕРСАЛЬНАЯ АРХИТЕКТУРА │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ PIM │ │
│ │ (Товары) │ │
│ └──────┬──────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 1С │ │ Наша ERP │ │ Другая │ │
│ │(докум.) │ │ (учёт) │ │ ERP │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Генератор Основной Возможное │
│ документов учёт расширение │
│ │
└─────────────────────────────────────────────────────────────────────┘
Принцип: PIM — универсальный каталог, который работает с любой ERP через стандартизированный интерфейс.
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ СЛОЙ 1: PIM (Product Information Management) │
│ ───────────────────────────────────────────── │
│ Отвечает за: │
│ • Товарный каталог (name, description, specs) │
│ • Медиа (images, video) │
│ • Категории и характеристики │
│ • Ценообразование (retail_price, wholesale_price) │
│ • Выгрузка на маркетплейсы (OZON, WB) │
│ • Выгрузка на сайты (OpenCart) │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ СЛОЙ 2: ERP (Enterprise Resource Planning) │
│ ────────────────────────────────────────── │
│ Отвечает за: │
│ • Остатки (stock) │
│ • Себестоимость (cost_price) │
│ • Заказы и резервы │
│ • Поставщики и закупки │
│ • Клиенты и продажи │
│ • Финансы │
│ │
│ Реализации: │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Наша ERP │ │ Odoo │ │ Другие │ │
│ │ (PostgreSQL) │ │ (Odoo 18) │ │ (SAP, etc) │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ СЛОЙ 3: ДОКУМЕНТООБОРОТ (1С или другой) │
│ ─────────────────────────────────────── │
│ Отвечает за: │
│ • Первичные документы (накладные, счета) │
│ • Налоговая отчётность │
│ • Бухгалтерский учёт │
│ • ЭДО (электронный документооборот) │
│ │
│ ┌────────────────┐ │
│ │ 1С:УНФ │ ← Генератор документов │
│ │ (SaaS 1С) │ │
│ └────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
┌─────────┐ ┌─────────┐ ┌─────────┐
│ PIM │◄───────►│ 1С │────────►│ OZON │
│ │ товары │ ERP+Док │ ручной │ │
└─────────┘ остатки └─────────┘ └─────────┘
┌─────────┐ ┌─────────┐ ┌─────────┐
│ PIM │◄───────►│Наша ERP │────────►│ OZON │
│ │ товары │ (учёт) │ автомат │ │
└─────────┘ остатки └─────────┘ └─────────┘
│
│ документы
▼
┌─────────┐
│ 1С │
│(1С-Асс.)│
└─────────┘
┌─────────┐ ┌─────────┐ ┌─────────┐
│ PIM │◄───────►│Наша ERP │◄───────►│ OZON │
│ │ │ │ │ WB │
└─────────┘ └─────────┘ │ Сайты │
│ └─────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│1С-Асс. │ │ ЭДО │ │ Банк API│
│(докум.) │ │(Диадок) │ │ │
└─────────┘ └─────────┘ └─────────┘
-- ============================================
-- ТОВАРЫ (связь с PIM)
-- ============================================
CREATE TABLE erp_products (
id SERIAL PRIMARY KEY,
pim_id INT REFERENCES pim_products(id), -- Связь с PIM
-- ERP данные
sku VARCHAR(50) UNIQUE NOT NULL,
stock INT DEFAULT 0,
reserved INT DEFAULT 0,
available INT GENERATED ALWAYS AS (stock - reserved) STORED,
-- Себестоимость
cost_price DECIMAL(12,2),
cost_currency VARCHAR(3) DEFAULT 'RUB',
-- Поставщик
supplier_id INT REFERENCES erp_suppliers(id),
supplier_sku VARCHAR(50),
-- Метаданные
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- ============================================
-- ПОСТАВЩИКИ
-- ============================================
CREATE TABLE erp_suppliers (
id SERIAL PRIMARY KEY,
code VARCHAR(20) UNIQUE NOT NULL,
name VARCHAR(200) NOT NULL,
inn VARCHAR(12),
kpp VARCHAR(9),
-- Контакты
contact_name VARCHAR(100),
contact_phone VARCHAR(20),
contact_email VARCHAR(100),
-- Условия
payment_days INT DEFAULT 0, -- Отсрочка
min_order DECIMAL(12,2), -- Мин. заказ
delivery_days INT, -- Срок доставки
is_active BOOLEAN DEFAULT true
);
-- ============================================
-- ЗАКАЗЫ ПОСТАВЩИКУ
-- ============================================
CREATE TABLE erp_purchase_orders (
id SERIAL PRIMARY KEY,
order_number VARCHAR(20) UNIQUE NOT NULL,
supplier_id INT REFERENCES erp_suppliers(id),
-- Статус
status VARCHAR(20) DEFAULT 'draft', -- draft, sent, confirmed, shipped, received
order_date DATE,
expected_date DATE,
received_date DATE,
-- Суммы
total_amount DECIMAL(12,2),
currency VARCHAR(3) DEFAULT 'RUB',
-- 1С документ (после создания)
doc_1c_id VARCHAR(50),
doc_1c_number VARCHAR(20),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE erp_purchase_order_lines (
id SERIAL PRIMARY KEY,
order_id INT REFERENCES erp_purchase_orders(id),
product_id INT REFERENCES erp_products(id),
quantity INT NOT NULL,
price DECIMAL(12,2) NOT NULL,
amount DECIMAL(12,2) GENERATED ALWAYS AS (quantity * price) STORED,
received_qty INT DEFAULT 0
);
-- ============================================
-- ЗАКАЗЫ КЛИЕНТОВ
-- ============================================
CREATE TABLE erp_sales_orders (
id SERIAL PRIMARY KEY,
order_number VARCHAR(20) UNIQUE NOT NULL,
-- Источник
source VARCHAR(20) NOT NULL, -- ozon, wb, site, manual
external_order_id VARCHAR(50), -- ID в маркетплейсе
-- Клиент
customer_name VARCHAR(200),
customer_phone VARCHAR(20),
customer_email VARCHAR(100),
delivery_address TEXT,
-- Статус
status VARCHAR(20) DEFAULT 'new', -- new, confirmed, packed, shipped, delivered, cancelled
-- Суммы
total_amount DECIMAL(12,2),
delivery_amount DECIMAL(12,2),
commission_amount DECIMAL(12,2), -- Комиссия маркетплейса
-- 1С документ
doc_1c_id VARCHAR(50),
doc_1c_number VARCHAR(20),
created_at TIMESTAMP DEFAULT NOW()
);
-- ============================================
-- ДВИЖЕНИЕ ТОВАРОВ
-- ============================================
CREATE TABLE erp_stock_movements (
id SERIAL PRIMARY KEY,
product_id INT REFERENCES erp_products(id),
movement_type VARCHAR(20) NOT NULL, -- receipt, sale, return, adjustment, reserve
quantity INT NOT NULL, -- + приход, - расход
reference_type VARCHAR(20), -- purchase_order, sales_order, manual
reference_id INT,
-- До/После
stock_before INT,
stock_after INT,
created_at TIMESTAMP DEFAULT NOW(),
created_by VARCHAR(50)
);
-- Представление: товар со всеми данными
CREATE VIEW v_product_full AS
SELECT
p.id as pim_id,
p.sku,
p.name,
p.description,
p.category_slug,
p.specifications,
p.retail_price,
p.wholesale_price,
p.images,
-- ERP данные
e.stock,
e.reserved,
e.available,
e.cost_price,
e.supplier_id,
-- Вычисляемые
(p.retail_price - e.cost_price) as margin,
CASE WHEN e.cost_price > 0
THEN ((p.retail_price - e.cost_price) / e.cost_price * 100)
ELSE 0
END as margin_percent
FROM pim_products p
LEFT JOIN erp_products e ON e.pim_id = p.id
WHERE p.is_active = true;
┌─────────────────────────────────────────────────────────────────────┐
│ 1С-АССИСТЕНТ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ AI АГЕНТ │ │
│ │ • Понимает контекст (заказ, накладная, счёт) │ │
│ │ • Формирует данные для документа │ │
│ │ • Валидирует перед отправкой │ │
│ │ • Обрабатывает ошибки │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ КОННЕКТОР 1С │ │
│ │ • OData API (справочники, документы) │ │
│ │ • HTTP Service (кастомные операции) │ │
│ │ • Очередь операций │ │
│ │ • Retry логика │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 1С:УНФ │ │
│ │ Создаёт: │ │
│ │ • Заказ поставщику → Приходная накладная │ │
│ │ • Заказ покупателя → Расходная накладная │ │
│ │ • Счёт на оплату → Платёжное поручение │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
# 1С-Ассистент
**Тип:** Специалист
**Триггеры:** `1с`, `документ`, `накладная`, `счёт`, `создай в 1с`
## РОЛЬ
AI-ассистент для работы с 1С. Создаёт документы на основе данных из ERP.
## ВОЗМОЖНОСТИ
### Документы
| Документ | Команда | Источник данных |
|----------|---------|-----------------|
| Заказ поставщику | "создай заказ поставщику" | erp_purchase_orders |
| Приходная накладная | "создай приход" | erp_purchase_orders (received) |
| Расходная накладная | "создай расход" | erp_sales_orders |
| Счёт на оплату | "выстави счёт" | erp_sales_orders |
| Возврат | "оформи возврат" | erp_returns |
### Алгоритм создания документа
1. Получить данные из ERP
2. Проверить контрагента в 1С (создать если нет)
3. Проверить номенклатуру (сопоставить по артикулу)
4. Сформировать документ
5. Отправить в 1С
6. Получить номер документа
7. Обновить ERP (doc_1c_id, doc_1c_number)
### Примеры
"создай приходную накладную по заказу ЗП-00123"
→ Находит заказ в ERP
→ Проверяет поставщика в 1С
→ Создаёт документ "Приходная накладная"
→ Возвращает номер
"выстави счёт клиенту Иванов на заказ 12345"
→ Находит заказ в ERP
→ Проверяет контрагента
→ Создаёт "Счёт на оплату"
→ Генерирует PDF
→ Отправляет клиенту (опционально)
# library/connectors/api/1c/client.py
class Client1C:
"""Универсальный клиент к 1С OData API"""
def __init__(self, base_url: str, auth: tuple):
self.base_url = base_url
self.auth = auth
# ═══════════════════════════════════════════
# СПРАВОЧНИКИ
# ═══════════════════════════════════════════
async def get_contractor(self, inn: str) -> dict | None:
"""Найти контрагента по ИНН"""
...
async def create_contractor(self, data: ContractorCreate) -> str:
"""Создать контрагента, вернуть ref_key"""
...
async def get_nomenclature(self, article: str) -> dict | None:
"""Найти номенклатуру по артикулу"""
...
# ═══════════════════════════════════════════
# ДОКУМЕНТЫ
# ═══════════════════════════════════════════
async def create_purchase_order(self, data: PurchaseOrderCreate) -> str:
"""Создать Заказ поставщику"""
...
async def create_receipt(self, data: ReceiptCreate) -> str:
"""Создать Приходную накладную"""
...
async def create_shipment(self, data: ShipmentCreate) -> str:
"""Создать Расходную накладную"""
...
async def create_invoice(self, data: InvoiceCreate) -> str:
"""Создать Счёт на оплату"""
...
# ═══════════════════════════════════════════
# ОТЧЁТЫ
# ═══════════════════════════════════════════
async def get_stock_report(self) -> list[dict]:
"""Отчёт по остаткам"""
...
async def get_sales_report(self, date_from: date, date_to: date) -> list[dict]:
"""Отчёт по продажам"""
...
# library/connectors/api/1c/assistant.py
class Assistant1C:
"""AI-ассистент для работы с 1С"""
def __init__(self, client: Client1C, erp_db: AsyncSession):
self.client = client
self.erp = erp_db
async def create_document(self, command: str) -> DocumentResult:
"""
Создать документ по команде на естественном языке.
Примеры:
- "создай приход по заказу ЗП-00123"
- "выстави счёт на заказ 12345"
- "оформи возврат товара от клиента Петров"
"""
# 1. Парсинг команды (AI)
intent = await self._parse_intent(command)
# 2. Получение данных из ERP
erp_data = await self._get_erp_data(intent)
# 3. Валидация
validation = await self._validate(intent, erp_data)
if not validation.ok:
return DocumentResult(error=validation.error)
# 4. Создание документа
doc_id = await self._create_document(intent, erp_data)
# 5. Обновление ERP
await self._update_erp(intent, doc_id)
return DocumentResult(
success=True,
doc_type=intent.doc_type,
doc_id=doc_id,
doc_number=await self._get_doc_number(doc_id)
)
┌─────────────────────────────────────────────────────────────────────┐
│ ПОТОКИ ДАННЫХ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ТОВАРЫ: │
│ ──────── │
│ Прайс ──► PIM ──► Обогащение ──► Наша ERP (stock=0) │
│ │ │
│ ├──► OZON │
│ ├──► WB │
│ └──► OpenCart │
│ │
│ ОСТАТКИ: │
│ ───────── │
│ Наша ERP ◄─── Приход ◄─── Поставщик │
│ │ │
│ ├───► PIM (для маркетплейсов) │
│ └───► 1С-Асс. (документ "Приходная накладная") │
│ │
│ ЗАКАЗЫ: │
│ ──────── │
│ OZON ──► Наша ERP ──► Обработка ──► 1С-Асс. (накладная) │
│ WB ──► │ │
│ Сайт ──► └──► Отгрузка ──► Обновление остатков │
│ │
│ ДОКУМЕНТЫ: │
│ ─────────── │
│ Наша ERP ──► 1С-Ассистент ──► 1С:УНФ │
│ │ │
│ ├── Заказ поставщику │
│ ├── Приходная накладная │
│ ├── Расходная накладная │
│ ├── Счёт на оплату │
│ └── Возвраты │
│ │
└─────────────────────────────────────────────────────────────────────┘
# library/connectors/erp/interface.py
from abc import ABC, abstractmethod
class ERPInterface(ABC):
"""Абстрактный интерфейс ERP для PIM"""
@abstractmethod
async def get_stock(self, sku: str) -> int:
"""Получить остаток по артикулу"""
...
@abstractmethod
async def get_cost_price(self, sku: str) -> Decimal:
"""Получить себестоимость"""
...
@abstractmethod
async def reserve_stock(self, sku: str, qty: int, order_id: str) -> bool:
"""Зарезервировать товар"""
...
@abstractmethod
async def release_reserve(self, sku: str, qty: int, order_id: str) -> bool:
"""Снять резерв"""
...
@abstractmethod
async def sync_stock_updates(self, since: datetime) -> list[StockUpdate]:
"""Получить обновления остатков"""
...
# Реализации:
class OurERP(ERPInterface):
"""Наша ERP (PostgreSQL)"""
...
class Connector1C(ERPInterface):
"""1С как ERP (legacy)"""
...
class OdooConnector(ERPInterface):
"""Odoo ERP"""
...
| Этап | Что делаем | Результат |
|---|---|---|
| 0 | Создаём таблицы Нашей ERP | Структура готова |
| 1 | Импорт товаров 1С → PIM → ERP | Товары в обеих системах |
| 2 | Параллельная работа (1С + ERP) | Сверка данных |
| 3 | Переключение учёта на ERP | ERP = master |
| 4 | 1С-Ассистент для документов | Документы через AI |
| 5 | Отключение учёта в 1С | 1С = только документы |
Версия: 1.0.0