431 lines
18 KiB
Markdown
431 lines
18 KiB
Markdown
# Интеграция с 1С:УНФ 3.0 (1С-Фреш)
|
||
|
||
> Дата исследования: 04.06.2026
|
||
> Статус: ИССЛЕДОВАНИЕ (код не написан)
|
||
|
||
---
|
||
|
||
## 1. Краткое описание
|
||
|
||
Документ описывает доступные API для интеграции сервисного портала AegisOne с 1С:УНФ 3.0, работающей в облаке 1С-Фреш.
|
||
|
||
**Цель:** Синхронизация данных между 1С:УНФ и порталом — клиенты, заказы, контактные лица.
|
||
|
||
---
|
||
|
||
## 2. Доступные интерфейсы 1С-Фреш
|
||
|
||
| Интерфейс | Назначение | Чтение | Запись | Сложность |
|
||
|-----------|-----------|--------|--------|-----------|
|
||
| **OData** | Стандартный интерфейс платформы 1С | ✅ | ✅ | Средняя |
|
||
| **REST API** | Портал 1С:ITS Fresh-Integration | ✅ | ✅ | Средняя |
|
||
| **HTTP-сервис** | УниверсальнаяИнтеграция (UniversalIntegration) | ✅ | ✅ | Высокая |
|
||
| **Система взаимодействия** | Вебхуки (внешние → 1С) | ❌ | ✅ | Низкая |
|
||
|
||
### Главный вывод
|
||
|
||
**OData** — основной и самый доступный способ интеграции. Через OData доступны практически все объекты 1С:УНФ 3.0: справочники, документы, регистры.
|
||
|
||
---
|
||
|
||
## 3. OData интерфейс
|
||
|
||
### 3.1 Формат URL
|
||
|
||
```
|
||
https://<server>/a/unf/<tenant>/odata/standard.odata/<Entity>
|
||
```
|
||
|
||
| Параметр | Описание | Пример |
|
||
|----------|----------|--------|
|
||
| `server` | Адрес сервера 1С-Фреш | `https://xxx.1cfresh.com` |
|
||
| `app` | Код приложения | `unf` (для УНФ) |
|
||
| `tenant` | Номер области данных | `34` |
|
||
| `Entity` | Имя объекта метаданных | `Catalog_Контрагенты` |
|
||
|
||
### 3.2 Аутентификация
|
||
|
||
```
|
||
Authorization: Basic <base64(login:password)>
|
||
```
|
||
|
||
Используется сервисный пользователь 1С-Фреш с правами доступа к OData.
|
||
|
||
### 3.3 Формат ответа
|
||
|
||
```
|
||
?$format=json — JSON
|
||
?$format=atom — Atom/XML (по умолчанию)
|
||
?$format=json;odata=nometadata — JSON без метаданных
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Доступные сущности 1С:УНФ 3.0
|
||
|
||
### 4.1 Справочники (Catalogs)
|
||
|
||
| OData URL | Описание | Приоритет для нас |
|
||
|-----------|----------|-------------------|
|
||
| `Catalog_Контрагенты` | Покупатели, поставщики, прочие контрагенты | 🔴 Высокий → **Клиенты** |
|
||
| `Catalog_КонтактныеЛица` | Контактные лица контрагентов | 🔴 Высокий → **Контакты** |
|
||
| `Catalog_Номенклатура` | Услуги, товары, работы | 🟡 Средний → Каталог услуг |
|
||
| `Catalog_Договоры` | Договоры с контрагентами | 🟡 Средний → Привязка к клиенту |
|
||
| `Catalog_Проекты` | Проекты | 🟡 Средний → Связь с заказами |
|
||
| `Catalog_Организации` | Наши организации | 🟢 Низкий → Контекст |
|
||
| `Catalog_БанковскиеСчета` | Расчётные счета | 🟢 Низкий |
|
||
|
||
### 4.2 Документы (Documents)
|
||
|
||
| OData URL | Описание | Приоритет для нас |
|
||
|-----------|----------|-------------------|
|
||
| `Document_ЗаказКлиента` | Заказ покупателя | 🔴 Высокий → **Заказ/Лид** |
|
||
| `Document_РеализацияТоваровУслуг` | Реализация товаров и услуг | 🟡 Средний → История работ |
|
||
| `Document_АктВыполненныхРабот` | Акт выполненных работ | 🟡 Средний → Подтверждение |
|
||
| `Document_СчетНаОплату` | Счёт на оплату | 🟡 Средний → Финансы |
|
||
| `Document_ПоступлениеТоваров` | Поступление товаров | 🟢 Низкий → Закупки |
|
||
| `Document_СчетНаОплатуПоставщика` | Счёт от поставщика | 🟢 Низкий |
|
||
|
||
### 4.3 Регистры сведений
|
||
|
||
| OData URL | Описание |
|
||
|-----------|----------|
|
||
| `InformationRegister_ЦеныНоменклатурыДокументов` | Цены номенклатуры |
|
||
| `InformationRegister_КурсыВалют` | Курсы валют |
|
||
| `InformationRegister_НастройкиСистемыНалогообложения` | Учётная политика |
|
||
|
||
### 4.4 Табличные части
|
||
|
||
Доступны через суффикс имени:
|
||
|
||
```
|
||
Document_ЗаказКлиента_Товары — табличная часть «Товары»
|
||
Document_ЗаказКлиента_Услуги — табличная часть «Услуги»
|
||
Catalog_Контрагенты_КонтактнаяИнформация — контактная информация
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Примеры запросов
|
||
|
||
### 5.1 Все контрагенты (покупатели)
|
||
|
||
```http
|
||
GET /odata/standard.odata/Catalog_Контрагенты?$format=json
|
||
&$select=Ref_Key,Description,ИНН,КПП,РегистрационныйНомер
|
||
&$filter=not (IsFolder)
|
||
&$orderby=Description
|
||
&$top=100
|
||
Authorization: Basic <auth>
|
||
```
|
||
|
||
### 5.2 Поиск контрагента по ИНН
|
||
|
||
```http
|
||
GET /odata/standard.odata/Catalog_Контрагенты?$format=json
|
||
&$select=Ref_Key,Description,ИНН,КПП
|
||
&$filter=(ИНН eq '2310031540')
|
||
Authorization: Basic <auth>
|
||
```
|
||
|
||
### 5.3 Поиск контрагента по наименованию
|
||
|
||
```http
|
||
GET /odata/standard.odata/Catalog_Контрагенты?$format=json
|
||
&$select=Ref_Key,Description,ИНН
|
||
&$filter=like(Description, 'Аегис%')
|
||
Authorization: Basic <auth>
|
||
```
|
||
|
||
### 5.4 Заказы конкретного клиента
|
||
|
||
```http
|
||
GET /odata/standard.odata/Document_ЗаказКлиента?$format=json
|
||
&$expand=Контрагент
|
||
&$select=Ref_Key,Number,Date,СуммаДокумента,Статус,Контрагент/Description
|
||
&$filter=Контрагент_Key eq guid'...'
|
||
&$orderby=Date desc
|
||
Authorization: Basic <auth>
|
||
```
|
||
|
||
### 5.5 Контактные лица контрагента
|
||
|
||
```http
|
||
GET /odata/standard.odata/Catalog_КонтактныеЛица?$format=json
|
||
&$select=Ref_Key,Description,Должность,Владелец_Key
|
||
&$filter=Владелец_Key eq guid'...'
|
||
Authorization: Basic <auth>
|
||
```
|
||
|
||
### 5.6 Номенклатура (услуги)
|
||
|
||
```http
|
||
GET /odata/standard.odata/Catalog_Номенклатура?$format=json
|
||
&$expand=ЕдиницаИзмерения
|
||
&$select=Ref_Key,Description,Артикул,ВидНоменклатуры
|
||
&$filter=not (IsFolder)
|
||
&$orderby=Description
|
||
Authorization: Basic <auth>
|
||
```
|
||
|
||
### 5.7 Создание нового контрагента (POST)
|
||
|
||
```http
|
||
POST /odata/standard.odata/Catalog_Контрагенты
|
||
Content-Type: application/json
|
||
Authorization: Basic <auth>
|
||
|
||
{
|
||
"Description": "ООО Ромашка",
|
||
"ИНН": "2310031540",
|
||
"КПП": "231001001",
|
||
"ЮридическоеФизическоеЛицо": "ЮридическоеЛицо"
|
||
}
|
||
```
|
||
|
||
### 5.8 Обновление контрагента (PATCH)
|
||
|
||
```http
|
||
PATCH /odata/standard.odata/Catalog_Контрагенты(guid'...')
|
||
Content-Type: application/json
|
||
Authorization: Basic <auth>
|
||
|
||
{
|
||
"Description": "ООО Ромашка (обновлено)"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Маппинг сущностей 1С:УНФ → Наш портал
|
||
|
||
### 6.1 Контрагенты → Клиенты
|
||
|
||
| Поле 1С:УНФ | Поле портала | Тип маппинга |
|
||
|-------------|-------------|--------------|
|
||
| `Ref_Key` | `onec_id` (UUID) | Прямой |
|
||
| `Description` | `company_name` | Прямой |
|
||
| `ИНН` | `inn` | Прямой (ключ дедупликации) |
|
||
| `КПП` | `kpp` | Прямой |
|
||
| `Телефон` | `phone` | Нормализация |
|
||
| `Email` | `email` | Прямой |
|
||
| `Адрес` | `address` | Прямой |
|
||
|
||
### 6.2 Заказ клиента → Лид/Заказ
|
||
|
||
| Поле 1С:УНФ | Поле портала | Тип маппинга |
|
||
|-------------|-------------|--------------|
|
||
| `Ref_Key` | `onec_order_id` (UUID) | Прямой |
|
||
| `Number` | `number` | Прямой |
|
||
| `Date` | `created_at` | Конвертация |
|
||
| `СуммаДокумента` | `amount` | Прямой |
|
||
| `Статус` | `status` | Маппинг статусов |
|
||
| `Контрагент_Key` | `customer_id` | FK (по onec_id) |
|
||
|
||
### 6.3 Статусы заказов
|
||
|
||
| Статус 1С:УНФ | Статус портала |
|
||
|---------------|---------------|
|
||
| В работе | `in_progress` |
|
||
| Закрыт | `completed` |
|
||
| Отменён | `cancelled` |
|
||
|
||
---
|
||
|
||
## 7. Стратегия интеграции
|
||
|
||
### Фаза 0: Настройка доступа (отдельная задача)
|
||
|
||
1. **Получить от пользователя:**
|
||
- URL базы в 1С-Фреш (типа `https://xxx.1cfresh.com/a/unf/`)
|
||
- Логин/пароль сервисного пользователя
|
||
- Номер области данных (tenant)
|
||
|
||
2. **Проверить доступность:**
|
||
- Выполнить тестовый запрос к `$metadata`
|
||
- Убедиться в наличии нужных сущностей
|
||
- Проверить права доступа
|
||
|
||
3. **Создать таблицу настроек:**
|
||
```sql
|
||
CREATE TABLE onec_settings (
|
||
id SERIAL PRIMARY KEY,
|
||
base_url VARCHAR(500) NOT NULL,
|
||
tenant VARCHAR(50) NOT NULL,
|
||
login VARCHAR(100) NOT NULL,
|
||
password_encrypted TEXT NOT NULL, -- fernet
|
||
last_sync_at TIMESTAMP,
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
### Фаза 1: Синхронизация контрагентов → клиенты
|
||
|
||
1. **Миграция:** Таблица `onec_sync_log` для логирования
|
||
```sql
|
||
CREATE TABLE onec_sync_log (
|
||
id SERIAL PRIMARY KEY,
|
||
entity_type VARCHAR(50) NOT NULL, -- 'contragent', 'order', etc.
|
||
onec_id UUID NOT NULL,
|
||
portal_id INTEGER,
|
||
action VARCHAR(20) NOT NULL, -- 'create', 'update', 'skip'
|
||
details JSONB,
|
||
synced_at TIMESTAMP DEFAULT NOW()
|
||
);
|
||
```
|
||
|
||
2. **Задача синхронизации:**
|
||
- Читаем `Catalog_Контрагенты` из 1С
|
||
- Дедупликация по ИНН (точное совпадение)
|
||
- Если ИНН нет — по наименованию + ИНН КПП
|
||
- Создаём/обновляем в таблице `customers`
|
||
- Логируем каждое действие
|
||
|
||
3. **Периодичность:** Раз в день (ночью) или по требованию
|
||
|
||
### Фаза 2: Синхронизация заказов
|
||
|
||
1. **Миграция:** Поле `onec_order_id` в `leads` или новая таблица
|
||
2. **Задача синхронизации:**
|
||
- Читаем `Document_ЗаказКлиента` из 1С
|
||
- Привязка к клиенту по `Контрагент_Key`
|
||
- Маппинг статусов
|
||
- Логирование
|
||
|
||
### Фаза 3 (опционально): Обратная запись
|
||
|
||
- Создание заказа в портале → создание в 1С
|
||
- Требует аккуратной обработки ошибок
|
||
- **Рекомендация:** Только после стабильности фаз 1-2
|
||
|
||
---
|
||
|
||
## 8. Технические детали
|
||
|
||
### 8.1 Python-клиент для OData
|
||
|
||
Рекомендуемая библиотека: `pyodata` или `requests` (raw OData).
|
||
|
||
```python
|
||
import base64
|
||
import httpx
|
||
|
||
class OneCFreshClient:
|
||
"""Клиент для работы с 1С-Фреш через OData."""
|
||
|
||
def __init__(self, base_url: str, tenant: str, login: str, password: str):
|
||
self.base_url = base_url.rstrip('/')
|
||
self.tenant = tenant
|
||
self.auth = base64.b64encode(f"{login}:{password}".encode()).decode()
|
||
|
||
async def get_contragents(self, top: int = 100, skip: int = 0) -> list:
|
||
"""Получить список контрагентов."""
|
||
url = f"{self.base_url}/a/unf/{self.tenant}/odata/standard.odata/Catalog_Контрагенты"
|
||
params = {
|
||
"$format": "json;odata=nometadata",
|
||
"$select": "Ref_Key,Description,ИНН,КПП",
|
||
"$filter": "not (IsFolder)",
|
||
"$top": str(top),
|
||
"$skip": str(skip),
|
||
}
|
||
headers = {"Authorization": f"Basic {self.auth}"}
|
||
|
||
async with httpx.AsyncClient() as client:
|
||
resp = await client.get(url, params=params, headers=headers)
|
||
resp.raise_for_status()
|
||
return resp.json().get("value", [])
|
||
|
||
async def get_contragent_by_inn(self, inn: str) -> dict | None:
|
||
"""Найти контрагента по ИНН."""
|
||
url = f"{self.base_url}/a/unf/{self.tenant}/odata/standard.odata/Catalog_Контрагенты"
|
||
params = {
|
||
"$format": "json;odata=nometadata",
|
||
"$select": "Ref_Key,Description,ИНН,КПП",
|
||
"$filter": f"(ИНН eq '{inn}')",
|
||
}
|
||
headers = {"Authorization": f"Basic {self.auth}"}
|
||
|
||
async with httpx.AsyncClient() as client:
|
||
resp = await client.get(url, params=params, headers=headers)
|
||
resp.raise_for_status()
|
||
items = resp.json().get("value", [])
|
||
return items[0] if items else None
|
||
```
|
||
|
||
### 8.2 Ограничения
|
||
|
||
| Ограничение | Описание | Решение |
|
||
|-------------|----------|---------|
|
||
| **Multi-tenancy** | Каждая база в своей области данных | Указать tenant в URL |
|
||
| **Публикация OData** | Должна быть включена в конфигурации | Проверить через `$metadata` |
|
||
| **Права доступа** | Сервисный пользователь должен иметь права на чтение | Настроить роли в 1С |
|
||
| **Пагинация** | Большие выборки — через `$top`/`$skip` | Построчная загрузка |
|
||
| **Rate limits** | Возможны ограничения на частоту запросов | Очередь задач, retry |
|
||
|
||
### 8.3 Проверка доступности
|
||
|
||
```bash
|
||
# Тестовый запрос метаданных
|
||
curl -u "login:password" \
|
||
"https://xxx.1cfresh.com/a/unf/34/odata/standard.odata/$metadata"
|
||
|
||
# Тестовый запрос контрагентов
|
||
curl -u "login:password" \
|
||
"https://xxx.1cfresh.com/a/unf/34/odata/standard.odata/Catalog_Контрагенты?\$format=json&\$top=5"
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Сравнение с webhook (Система взаимодействия)
|
||
|
||
| Критерий | OData | Webhook |
|
||
|----------|-------|---------|
|
||
| **Чтение данных** | ✅ Да | ❌ Нет (только запись) |
|
||
| **Запись данных** | ✅ Да | ✅ Да (только в 1С) |
|
||
| **Направление** | Bidirectional | One-way (внешнее → 1С) |
|
||
| **Формат** | JSON (стандартный OData) | JSON (свой формат) |
|
||
| **Аутентификация** | Basic Auth | URL + логин/пароль |
|
||
| **Сложность** | Средняя | Низкая |
|
||
| **Использование** | Синхронизация данных | Уведомления, сообщения |
|
||
|
||
**Вывод:** OData — для синхронизации данных. Webhook — для отправки уведомлений в 1С.
|
||
|
||
---
|
||
|
||
## 10. Рекомендации
|
||
|
||
### Приоритет implementation
|
||
|
||
1. **OData синхронизация контрагентов** — самый важный функционал
|
||
2. **OData синхронизация заказов** — расширение функционала
|
||
3. **Webhook уведомления** — опционально, для двусторонней связи
|
||
|
||
### Вопросы к пользователю (для фазы 0)
|
||
|
||
1. URL базы в 1С-Фреш?
|
||
2. Логин/пароль сервисного пользователя?
|
||
3. Номер области данных (tenant)?
|
||
4. Какие данные в приоритете: контрагенты, заказы, или всё сразу?
|
||
5. Направление синхронизации: только из 1С → портал, или bidirectional?
|
||
|
||
### Рекомендация
|
||
|
||
**Начать с read-only синхронизации контрагентов** — самый безопасный и быстрый способ:
|
||
- Не требует записи обратно
|
||
- Минимальные риски
|
||
- Быстро даёт результат (клиенты из 1С появляются в портале)
|
||
- Потом можно расширять до заказов и bidirectional
|
||
|
||
---
|
||
|
||
## 11. Ссылки
|
||
|
||
- [Документация 1С-Фреш: OData](https://its.1c.ru/db/fresh/content/19956692/hdoc)
|
||
- [Платформа 1С: REST интерфейс](https://v8.1c.ru/platforma/rest-interfeys/)
|
||
- [OData: правила формирования имени ресурса](https://42clouds.com/ru-ru/manuals/interfeys-odata-pravila-formirovaniya-imeni-resursa/)
|
||
- [Работа с 1С через OData (Infostart)](https://infostart.ru/1c/articles/1570140/)
|
||
- [odata1c-client (GitHub)](https://github.com/Dakword/odata1c-client) — PHP-клиент с примерами
|
||
- [Контрагенты и контактные лица в 1С:УНФ](https://unf4you.ru/publ/kontragenty_i_kontaktnye_lica/1-1-0-407)
|
||
- [Заказ покупателя в 1С:УНФ](https://estart1c.ru/unf-30/189-kak-v-1sroznice-i-1sunf-sozdat-i-ispolzovat-zakaz-pokupatelja.html)
|