565 lines
21 KiB
Markdown
565 lines
21 KiB
Markdown
|
|
# Техническая документация: Потоки данных и процессы
|
|||
|
|
|
|||
|
|
## 🔄 Диаграмма основного потока
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ПОЛЬЗОВАТЕЛЬ │
|
|||
|
|
│ (Браузер) │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
│ GET index.php
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ INDEX.PHP │
|
|||
|
|
│ - Определение IP через ip-api.com │
|
|||
|
|
│ - Генерация session_id для sub_dir │
|
|||
|
|
│ - Рендеринг формы (3 шага) │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
│ [SMS ВЕРИФИКАЦИЯ]
|
|||
|
|
│
|
|||
|
|
├─► POST sms-test.php
|
|||
|
|
│ • Генерация кода (6 цифр)
|
|||
|
|
│ • Отправка через SigmaSMS API
|
|||
|
|
│ • Возврат success/error
|
|||
|
|
│
|
|||
|
|
│ Пользователь вводит код
|
|||
|
|
│ Проверка на клиенте (JS)
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ШАГ 1: Проверка полиса │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
├─► POST database.php
|
|||
|
|
│ {
|
|||
|
|
│ action: "user_verify",
|
|||
|
|
│ birthday: "DD.MM.YYYY",
|
|||
|
|
│ inn: "полис номер"
|
|||
|
|
│ }
|
|||
|
|
│ ↓
|
|||
|
|
│ SELECT * FROM ci20465_erv.lexrpiority
|
|||
|
|
│ WHERE voucher = 'полис номер'
|
|||
|
|
│ ↓
|
|||
|
|
│ Response:
|
|||
|
|
│ {
|
|||
|
|
│ success: "true|false",
|
|||
|
|
│ message: "Полис найден|не найден",
|
|||
|
|
│ result: {
|
|||
|
|
│ insured_from: "дата",
|
|||
|
|
│ insured_to: "дата"
|
|||
|
|
│ }
|
|||
|
|
│ }
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ Заполнение персональных данных │
|
|||
|
|
│ • ФИО │
|
|||
|
|
│ • Дата рождения → проверка возраста │
|
|||
|
|
│ • Если < 18: показать поля законного представителя │
|
|||
|
|
│ • Банковские реквизиты │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ШАГ 2: Описание события │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
├─► Выбор типа события (select)
|
|||
|
|
│ • Задержка рейса
|
|||
|
|
│ • Отмена рейса → показать поле подтверждения
|
|||
|
|
│ • Стыковочный → показать доп. поля
|
|||
|
|
│ • Посадка на запасной
|
|||
|
|
│ • Поезд/паром
|
|||
|
|
│
|
|||
|
|
├─► Загрузка документов
|
|||
|
|
│ ├─► Выбор файлов (макс 10, до 5MB)
|
|||
|
|
│ │ • Валидация формата
|
|||
|
|
│ │ • Валидация размера
|
|||
|
|
│ │
|
|||
|
|
│ ├─► POST fileupload_v2.php
|
|||
|
|
│ │ FormData:
|
|||
|
|
│ │ • files: field_name-0, field_name-1, ...
|
|||
|
|
│ │ • lastname
|
|||
|
|
│ │ • files_names[]
|
|||
|
|
│ │ • docs_names[]
|
|||
|
|
│ │ • sub_dir (session_id)
|
|||
|
|
│ │ ↓
|
|||
|
|
│ │ [ImageMagick convert] → PDF
|
|||
|
|
│ │ [Ghostscript merge] → единый PDF
|
|||
|
|
│ │ ↓
|
|||
|
|
│ │ Response:
|
|||
|
|
│ │ {
|
|||
|
|
│ │ success: "true",
|
|||
|
|
│ │ empty_file: "путь/к/объединенному.pdf",
|
|||
|
|
│ │ real_file: "путь/к/оригиналу.pdf"
|
|||
|
|
│ │ }
|
|||
|
|
│ │
|
|||
|
|
│ └─► Сохранение upload_url в data-атрибут input
|
|||
|
|
│
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ШАГ 3: Документы и согласия │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
├─► Адрес (с автозаполнением через DaData)
|
|||
|
|
├─► Документ удостоверяющий личность
|
|||
|
|
├─► Страна события
|
|||
|
|
├─► Email
|
|||
|
|
├─► Загрузка скана паспорта
|
|||
|
|
└─► Чекбокс согласия
|
|||
|
|
│
|
|||
|
|
│ [SUBMIT FORM]
|
|||
|
|
▼
|
|||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|||
|
|
│ ФИНАЛЬНАЯ ОТПРАВКА │
|
|||
|
|
└────────────┬────────────────────────────────────────────────────┘
|
|||
|
|
│
|
|||
|
|
├─► Сбор всех данных формы
|
|||
|
|
│ FormData {
|
|||
|
|
│ upload_urls[]: массив путей к файлам
|
|||
|
|
│ upload_urls_real[]: оригинальные пути
|
|||
|
|
│ files_names[]: имена полей
|
|||
|
|
│ docs_names[]: названия документов
|
|||
|
|
│ docs_ticket_files_ids[]: индексы файлов билетов
|
|||
|
|
│ appends[]: массив JSON-объектов с полями
|
|||
|
|
│ {
|
|||
|
|
│ ws_name: "имя поля",
|
|||
|
|
│ ws_type: "client|contractor|project|other|ticket",
|
|||
|
|
│ field_val: "значение"
|
|||
|
|
│ }
|
|||
|
|
│ lastname: фамилия
|
|||
|
|
│ sub_dir: session_id
|
|||
|
|
│ }
|
|||
|
|
│
|
|||
|
|
├─► POST https://form.clientright.ru/server_webservice2.php
|
|||
|
|
│ ↓
|
|||
|
|
│ [Обработка на стороне server_webservice2.php]
|
|||
|
|
│ ├─► Создание записей в CRM
|
|||
|
|
│ ├─► Привязка файлов
|
|||
|
|
│ └─► Отправка email
|
|||
|
|
│
|
|||
|
|
├─► Показ модалки успеха (Fancybox)
|
|||
|
|
│
|
|||
|
|
└─► Redirect → https://lexpriority.ru/ok (через 30ms)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🎯 Детализация процессов
|
|||
|
|
|
|||
|
|
### 1. SMS Верификация
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// Генерация кода
|
|||
|
|
sended_code = Math.floor(Math.random()*(999999-100000+1)+100000)
|
|||
|
|
|
|||
|
|
// Отправка
|
|||
|
|
POST sms-test.php
|
|||
|
|
{
|
|||
|
|
smscode: "123456",
|
|||
|
|
phonenumber: "9991234567"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SigmaSMS API
|
|||
|
|
POST https://online.sigmasms.ru/api/sendings
|
|||
|
|
Headers: {
|
|||
|
|
Authorization: "Token 27f89492e00973263ff746a655663678fae7203bac8b62919700e489e33b3902"
|
|||
|
|
}
|
|||
|
|
Body: {
|
|||
|
|
type: "sms",
|
|||
|
|
recipient: "79991234567",
|
|||
|
|
payload: {
|
|||
|
|
sender: "Clientright",
|
|||
|
|
text: "Код подтверждения: 123456"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Таймер**: 30 секунд до повторной отправки
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. Проверка полиса в БД
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- Запрос
|
|||
|
|
SELECT * FROM ci20465_erv.lexrpiority
|
|||
|
|
WHERE voucher = ?
|
|||
|
|
|
|||
|
|
-- Замена букв (Русская → Латинская)
|
|||
|
|
Е → E
|
|||
|
|
А → A
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Результат**:
|
|||
|
|
- ✅ Найден → `cf_2446 = "1"`, скрыть загрузку полиса
|
|||
|
|
- ❌ Не найден → `cf_2446 = "0"`, показать загрузку полиса
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. Загрузка и обработка файлов
|
|||
|
|
|
|||
|
|
#### Клиентская валидация:
|
|||
|
|
```javascript
|
|||
|
|
Проверки:
|
|||
|
|
1. Количество ≤ 10
|
|||
|
|
2. Формат ∈ ['pdf', 'jpg', 'png', 'gif', 'jpeg']
|
|||
|
|
3. Размер ≤ 5 МБ
|
|||
|
|
|
|||
|
|
Если валидация прошла:
|
|||
|
|
→ upload_file(elem)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Серверная обработка (fileupload.php):
|
|||
|
|
```php
|
|||
|
|
1. Получение файлов (field_name-0, field_name-1, ...)
|
|||
|
|
|
|||
|
|
2. Для каждого файла:
|
|||
|
|
IF расширение != 'pdf':
|
|||
|
|
convert image.jpg image_timestamp.pdf
|
|||
|
|
→ Добавить в массив $pdfFiles[]
|
|||
|
|
ELSE:
|
|||
|
|
→ Добавить в массив $pdfFiles[]
|
|||
|
|
→ Подсчитать страницы: identify file.pdf
|
|||
|
|
|
|||
|
|
3. Объединение всех PDF:
|
|||
|
|
gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
|
|||
|
|
-sOutputFile=output.pdf file1.pdf file2.pdf ...
|
|||
|
|
|
|||
|
|
4. Имя результата:
|
|||
|
|
{docname}_{дата}_{фамилия}_{кол-во страниц}_CTP.pdf
|
|||
|
|
|
|||
|
|
Пример:
|
|||
|
|
Podtverzhdayushchie_dokumenty_23-10-2025_Ivanov_15_CTP.pdf
|
|||
|
|
|
|||
|
|
5. Response:
|
|||
|
|
{
|
|||
|
|
success: "true",
|
|||
|
|
message: "uploads/path/to/file.pdf"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Сохранение пути:
|
|||
|
|
```javascript
|
|||
|
|
thisfile.attr('data-uploadurl', res.empty_file)
|
|||
|
|
thisfile.attr('data-uploadurl_real', res.real_file)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. Формирование данных для CRM
|
|||
|
|
|
|||
|
|
#### Структура appends[]:
|
|||
|
|
```javascript
|
|||
|
|
appends[] = [
|
|||
|
|
// Клиент
|
|||
|
|
'{"ws_name":"lastname","ws_type":"client","field_val":"Иванов"}',
|
|||
|
|
'{"ws_name":"firstname","ws_type":"client","field_val":"Иван"}',
|
|||
|
|
'{"ws_name":"mobile","ws_type":"client","field_val":"9991234567"}',
|
|||
|
|
'{"ws_name":"email","ws_type":"client","field_val":"ivan@mail.ru"}',
|
|||
|
|
|
|||
|
|
// Контрагент (ERV)
|
|||
|
|
'{"ws_name":"inn","ws_type":"contractor","field_val":"7714312079"}',
|
|||
|
|
'{"ws_name":"accountname","ws_type":"contractor","field_val":"Филиал ООО РСО ЕВРОИНС..."}',
|
|||
|
|
|
|||
|
|
// Проект (кастомные поля)
|
|||
|
|
'{"ws_name":"cf_1885","ws_type":"other","field_val":"E123-456789"}', // Номер полиса
|
|||
|
|
'{"ws_name":"cf_1887","ws_type":"other","field_val":"01-01-2025"}', // Дата от
|
|||
|
|
'{"ws_name":"cf_1889","ws_type":"other","field_val":"31-12-2025"}', // Дата до
|
|||
|
|
|
|||
|
|
// Тикет
|
|||
|
|
'{"ws_name":"cf_1726","ws_type":"ticket","field_val":"delay_flight"}', // Тип события
|
|||
|
|
'{"ws_name":"description","ws_type":"other","field_val":"Описание..."}',
|
|||
|
|
|
|||
|
|
// Другие
|
|||
|
|
'{"ws_name":"cf_2446","ws_type":"other","field_val":"1"}', // В базе
|
|||
|
|
'{"ws_name":"cf_2502","ws_type":"project","field_val":"1"}' // Согласие
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Маппинг ws_type:
|
|||
|
|
- `client` → Модуль Contacts (Контакты)
|
|||
|
|
- `contractor` → Модуль Organizations (Организации)
|
|||
|
|
- `project` → Модуль HelpDesk или кастомный модуль
|
|||
|
|
- `ticket` → Модуль Tickets
|
|||
|
|
- `other` → Общие поля
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 5. Отправка в CRM (server.php или server_webservice2.php)
|
|||
|
|
|
|||
|
|
```php
|
|||
|
|
// Подготовка данных
|
|||
|
|
$new_post = [
|
|||
|
|
'__vtrftk' => 'sid:session_token',
|
|||
|
|
'publicid' => '3ddc71c2d79ef101c09b0d4e9c6bd08b',
|
|||
|
|
'urlencodeenable' => '1',
|
|||
|
|
'name' => 'websiteticket'
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// Добавление полей из appends[]
|
|||
|
|
foreach($appends as $item) {
|
|||
|
|
$data = json_decode($item);
|
|||
|
|
$new_post[$data->crm_name] = $data->field_val;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Добавление файлов
|
|||
|
|
foreach($upload_urls as $index => $url) {
|
|||
|
|
$files_array[$files_names[$index]] = new CURLFile(realpath($url));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Отправка
|
|||
|
|
$final_post = array_merge($new_post, $files_array);
|
|||
|
|
|
|||
|
|
CURL POST → https://crm.clientright.ru/modules/Webforms/capture.php
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🧩 Динамическая логика (JavaScript)
|
|||
|
|
|
|||
|
|
### Возрастная валидация:
|
|||
|
|
```javascript
|
|||
|
|
function getAge(dateString) {
|
|||
|
|
// Преобразование DD-MM-YYYY → Date
|
|||
|
|
var birthDate = new Date(dateString.replace(/(\d{2})-(\d{2})-(\d{4})/, "$2/$1/$3"))
|
|||
|
|
var today = new Date()
|
|||
|
|
var age = today.getFullYear() - birthDate.getFullYear()
|
|||
|
|
|
|||
|
|
// Корректировка если день рождения еще не наступил
|
|||
|
|
var m = today.getMonth() - birthDate.getMonth()
|
|||
|
|
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
|
|||
|
|
age--
|
|||
|
|
}
|
|||
|
|
return age
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Применение
|
|||
|
|
if (getAge(birthday) < 18) {
|
|||
|
|
// Показать поля законного представителя
|
|||
|
|
$("input[data-enableby=birthday]").removeClass('disabled')
|
|||
|
|
$("input[data-disabledby=birthday]").removeClass('disabled')
|
|||
|
|
} else {
|
|||
|
|
// Скрыть
|
|||
|
|
$("input[data-enableby=birthday]").addClass('disabled')
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Динамика типа события:
|
|||
|
|
```javascript
|
|||
|
|
$('select[name="event_type"]').on('change', function() {
|
|||
|
|
const selectedValue = $(this).val()
|
|||
|
|
|
|||
|
|
// Скрыть все доп. поля
|
|||
|
|
$('.connection-fields, .connection-date-fields, .cancel-flight-docs').hide()
|
|||
|
|
|
|||
|
|
switch(selectedValue) {
|
|||
|
|
case 'miss_connection':
|
|||
|
|
// Стыковочный рейс
|
|||
|
|
$('#transport_number_label').text('Укажите номер рейса прибытия')
|
|||
|
|
$('.connection-fields, .connection-date-fields').show()
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
case 'cancel_flight':
|
|||
|
|
// Отмена рейса
|
|||
|
|
$('.cancel-flight-docs').show()
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
default:
|
|||
|
|
// Остальные типы
|
|||
|
|
$('#transport_number_label').text('Номер рейса/поезда/парома')
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔍 Валидация шагов
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
function validate_step(step_index) {
|
|||
|
|
// Найти все обязательные поля на текущем шаге
|
|||
|
|
let inputs = $('.form-step.active').find(
|
|||
|
|
'input[type="text"], input[type="file"], input[type="email"], textarea, input[type="checkbox"]'
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
let res_array = []
|
|||
|
|
|
|||
|
|
inputs.each(function() {
|
|||
|
|
let field_fill = false
|
|||
|
|
|
|||
|
|
// Пропустить disabled и notvalidate
|
|||
|
|
if ($(this).hasClass('disabled') || $(this).hasClass('notvalidate')) {
|
|||
|
|
field_fill = true
|
|||
|
|
}
|
|||
|
|
// Пропустить поля с ошибками
|
|||
|
|
else if ($(this).hasClass('error')) {
|
|||
|
|
field_fill = false
|
|||
|
|
}
|
|||
|
|
// Проверить заполненность
|
|||
|
|
else if ($(this).val() == '') {
|
|||
|
|
$(this).closest('.form-item').find('.form-item__warning')
|
|||
|
|
.text('Пожалуйста, заполните все обязательные поля')
|
|||
|
|
field_fill = false
|
|||
|
|
}
|
|||
|
|
// Email валидация
|
|||
|
|
else if ($(this).attr('type') == 'email') {
|
|||
|
|
if (validateEmail($(this).val())) {
|
|||
|
|
field_fill = true
|
|||
|
|
} else {
|
|||
|
|
$(this).closest('.form-item').find('.form-item__warning')
|
|||
|
|
.text($(this).data('warmes'))
|
|||
|
|
field_fill = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// Checkbox
|
|||
|
|
else if ($(this).attr('type') == 'checkbox') {
|
|||
|
|
field_fill = $(this).is(':checked')
|
|||
|
|
}
|
|||
|
|
// Остальные поля
|
|||
|
|
else {
|
|||
|
|
field_fill = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
res_array.push(field_fill)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
// Проверка на шаге 3: обязательно согласие
|
|||
|
|
if (step_index == 3 &&
|
|||
|
|
$('.form-step[data-step=3]').find('input[type="checkbox"]:checked').length < 1) {
|
|||
|
|
$('.form__warning').text('Необходимо согласие с политикой...')
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Если все поля валидны
|
|||
|
|
if (!res_array.includes(false)) {
|
|||
|
|
$('.form__warning').hide()
|
|||
|
|
return true
|
|||
|
|
} else {
|
|||
|
|
$('.form__warning').show()
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📊 Состояния формы
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
INITIAL STATE
|
|||
|
|
├─ .sms-check (visible)
|
|||
|
|
│ └─ Поле телефона
|
|||
|
|
│ └─ Кнопка "Отправить SMS"
|
|||
|
|
│
|
|||
|
|
├─ .sms-success (hidden, d-none)
|
|||
|
|
│ ├─ .db-validate (проверка полиса)
|
|||
|
|
│ └─ .db-success (hidden, d-none)
|
|||
|
|
│ ├─ .form-step[data-step=1] (персональные данные)
|
|||
|
|
│ ├─ .form-step[data-step=2] (событие)
|
|||
|
|
│ └─ .form-step[data-step=3] (документы)
|
|||
|
|
│
|
|||
|
|
└─ Модалки
|
|||
|
|
├─ #confirm_sms (подтверждение SMS)
|
|||
|
|
└─ #success_modal (успешная отправка)
|
|||
|
|
|
|||
|
|
AFTER SMS VERIFICATION
|
|||
|
|
├─ .sms-check (disabled)
|
|||
|
|
├─ .sms-success (visible)
|
|||
|
|
└─ .db-validate (visible)
|
|||
|
|
|
|||
|
|
AFTER POLICY CHECK
|
|||
|
|
├─ .db-success (visible)
|
|||
|
|
└─ .form-step[data-step=1].active
|
|||
|
|
|
|||
|
|
NAVIGATION
|
|||
|
|
index = 1 (default)
|
|||
|
|
├─ Кнопка "Вперед" → index++, переход на следующий шаг
|
|||
|
|
├─ Кнопка "Назад" → index--, переход на предыдущий шаг
|
|||
|
|
└─ index == 3 → Показать кнопку "Подать обращение"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🌐 Внешние зависимости
|
|||
|
|
|
|||
|
|
### API:
|
|||
|
|
1. **ip-api.com** - Геолокация по IP
|
|||
|
|
```
|
|||
|
|
GET http://ip-api.com/json/{IP}?lang=ru
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. **SigmaSMS** - Отправка SMS
|
|||
|
|
```
|
|||
|
|
POST https://online.sigmasms.ru/api/login
|
|||
|
|
POST https://online.sigmasms.ru/api/sendings
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
3. **DaData** - Автозаполнение реквизитов
|
|||
|
|
```
|
|||
|
|
POST https://suggestions.dadata.ru/suggestions/api/4_1/rs/suggest/party
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
4. **form.clientright.ru** - Обработка файлов и отправка
|
|||
|
|
```
|
|||
|
|
POST https://form.clientright.ru/fileupload_v2.php
|
|||
|
|
POST https://form.clientright.ru/server_webservice2.php
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Системные утилиты:
|
|||
|
|
- **ImageMagick convert** - конвертация изображений в PDF
|
|||
|
|
- **Ghostscript gs** - объединение PDF
|
|||
|
|
- **PHPMailer** - отправка email
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 🔄 Обработка ошибок
|
|||
|
|
|
|||
|
|
### JavaScript AJAX:
|
|||
|
|
```javascript
|
|||
|
|
error: function(jqXHR, exception) {
|
|||
|
|
if (jqXHR.status === 0) {
|
|||
|
|
alert('Not connect. Verify Network.')
|
|||
|
|
} else if (jqXHR.status == 404) {
|
|||
|
|
alert('Requested page not found (404).')
|
|||
|
|
} else if (jqXHR.status == 500) {
|
|||
|
|
alert('Internal Server Error (500).')
|
|||
|
|
} else if (exception === 'parsererror') {
|
|||
|
|
// Парсинг JSON ошибка
|
|||
|
|
} else if (exception === 'timeout') {
|
|||
|
|
alert('Time out error.')
|
|||
|
|
} else if (exception === 'abort') {
|
|||
|
|
alert('Ajax request aborted.')
|
|||
|
|
} else {
|
|||
|
|
alert('Uncaught Error. ' + jqXHR.responseText)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### PHP (пока отсутствует нормальная обработка):
|
|||
|
|
- Только базовые try-catch в PHPMailer
|
|||
|
|
- Нет логирования ошибок
|
|||
|
|
- Нет пользовательских сообщений
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 📁 Структура session storage
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
uploads/{session_id}/
|
|||
|
|
├─ original_file1.jpg
|
|||
|
|
├─ original_file1_timestamp.pdf
|
|||
|
|
├─ original_file2.pdf
|
|||
|
|
├─ ...
|
|||
|
|
└─ Podtverzhdayushchie_dokumenty_23-10-2025_Ivanov_15_CTP.pdf
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
После успешной отправки → удаление всех файлов из `uploads/`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
Документация обновлена: **23.10.2025**
|
|||
|
|
|