Перейти к основному содержимому

Аудит импорта данных из 1С

Документ фиксирует план проверки импорта данных из 1С и рабочую матрицу для последующего аудита.

Раздел не заменяет пользовательскую инструкцию по импорту. Его задача - проверить, что Excel-выгрузки из 1С, backend-обработка, frontend-интерфейс, права доступа и связанные бизнес-сущности работают согласованно и предсказуемо.

Цель

Проверить импорт из 1С как связанный системный сценарий:

  • пользователь понимает, какой файл и в каком порядке нужно загрузить;
  • frontend вызывает правильный endpoint и корректно показывает результат;
  • backend валидирует файл, обязательные колонки и данные строк;
  • импорт не создает дубли при повторной загрузке того же файла;
  • существующие данные обновляются только ожидаемым образом;
  • связанные сущности заказа покупателя, товаров, счетов, оплат, задач и статусов не расходятся;
  • ошибки по отдельным строкам не скрываются и не выглядят как успешный импорт;
  • права доступа соответствуют бизнес-ролям.

Ограничение по объему работ

Функционал импорта из 1С нужен для единственного запуска, максимум для двух запусков. Поэтому аудит и последующие задачи должны быть прагматичными.

Главная цель - безопасно провести импорт и не повредить данные. Не нужно превращать этот сценарий в полноценную долгосрочную подсистему синхронизации, если для этого нет отдельного решения.

Приоритеты:

  1. Найти ошибки, которые могут испортить данные, создать дубли или сломать связи.
  2. Проверить, что повторный запуск того же файла не ухудшит состояние данных.
  3. Проверить, что пользователь увидит критичные ошибки импорта.
  4. Исправлять только то, что реально влияет на безопасный разовый запуск.
  5. Перед боевым импортом сделать backup базы и сохранить исходный файл импорта.

Не тратить время без отдельного решения:

  • на красивый preview-режим импорта;
  • на сложную историю запусков и журналирование исходных файлов;
  • на расширенный UI управления импортами;
  • на универсальный механизм маппинга колонок;
  • на долгосрочную поддержку разных форматов выгрузки из 1С;
  • на глубокую оптимизацию производительности, если объем файла спокойно обрабатывается текущим способом.

Если найденное поведение неудобное, но не опасное для одного-двух запусков, его нужно фиксировать как низкий приоритет или не выносить в задачу.

Область проверки

Текущая документация описывает импорт через Excel-выгрузки из 1С. В первый проход входят:

  1. Импорт заказов покупателя.
  2. Импорт товаров в заказах покупателя.
  3. Импорт счетов на оплату.
  4. Корректность создания задач процесса заказа покупателя для импортированных заказов.
  5. Импорт/синхронизация заказов на производство для импортированных заказов покупателя. Эта часть пока в разработке и проверяется по текущей ветке.
  6. Связанный сценарий банковских выписок и платежей, если при проверке счетов понадобится подтвердить оплату и автозавершение задач.

Не входят в первый проход:

  • Google-таблицы, кроме текущего сценария синхронизации заказов на производство, если он используется для импортированных заказов покупателя;
  • ручное создание заказов, товаров и счетов вне связи с импортом;
  • полная проверка процесса заказа покупателя, кроме точек, на которые импорт влияет напрямую.

Источники

Документация

ФайлНазначение
40. Синхронизация данных/1C.mdКраткое описание импорта из 1С.
2.Заказы/buyerOrder.mdПользовательское описание заказа покупателя.
2.Заказы/good.mdПользовательское описание товара в заказе.
2.Заказы/paymentInvoice.mdПользовательское описание счетов на оплату.
2.Заказы/bankStatement.mdПользовательское описание банковских выписок.
2.Заказы/Внутренние сущности/invoicePayment.mdПлатежи по счетам.
10-architecture/process-audit.mdПроверка влияния импорта на процесс заказа покупателя.

Документация считается ориентиром, но не абсолютной истиной: если она устарела, это фиксируется отдельно.

Backend

ФайлЧто проверить
Controllers/OrderControllers/BuyerOrderController.csEndpoint POST /Order/BuyerOrder/1C, права и входной request.
Controllers/OrderControllers/GoodController.csEndpoint POST /Order/Good/1C, права и входной request.
Controllers/OrderControllers/PaymentInvoiceController.csEndpoint POST /Order/PaymentInvoice/1C, права и входной request.
Controllers/OrderControllers/OrderController.csEndpoint синхронизации заказов на производство из текущей ветки.
Services/Order/Services/BuyerOrderService.csСоздание/обновление заказов покупателя из файла.
Services/Order/Services/GoodService.csСоздание/обновление товаров заказа из файла.
Services/Order/Services/PaymentInvoiceService.csСоздание/обновление счетов на оплату из файла.
Services/Order/Services/OrderService.csСоздание/обновление заказов на производство и привязка к товарам заказа покупателя.
Services/UserTask/Services/TaskService.csСохранение данных задач и смена статусов процесса заказа покупателя.
Services/UserTask/Services/TaskConditionHandler.csФинальные проверки задач процесса заказа покупателя.
Services/UserTask/Services/ProcessService.csСоздание и связность процесса заказа покупателя.
Helpers/FileGenerators/FileBuyerOrderReader.csРазбор Excel-файла заказов покупателя.
Helpers/FileGenerators/FileGoodReader.csРазбор Excel-файла товаров.
Helpers/FileGenerators/FilePaymentInvoiceReader.csРазбор Excel-файла счетов.
Services/Shared/Services/GoogleTableService.csЧтение заказов на производство из Google-таблицы в текущей ветке.
Helpers/SynchronizeHelper.csОбщая обработка результатов синхронизации.
Models/Responses/Shared/SynchronizeResponse.csКонтракт результата импорта и сообщений пользователю.

Frontend

ФайлЧто проверить
src/pages/buyer-orders/buyer-orders.tsxКнопки импорта, права видимости, обновление таблицы после импорта.
src/shared/ui/import/import-1C.tsxДиалог выбора файла, запуск импорта, вывод результата и сообщений.
src/entities/buyer-orders/api/buyer-order.api.tsRTK endpoints импорта и инвалидация кеша.
src/entities/production-ordersОтображение заказов на производство и связь с заказом покупателя.
src/entities/task/ui/specification/specification-creating-orders.tsxСценарий создания/проверки заказов на производство из задачи запуска.
src/entities/task/ui/support-order/support-order.tsxПросмотр заказов на производство на этапе сопровождения.
src/shared/config/field-permissions.config.tsДоступность импорта по ролям и правам.

Методика

Проверка идет по одному формату для каждого вида импорта.

  1. Выписать ожидаемый пользовательский сценарий: кто запускает импорт, какой файл загружает, что должен получить в результате.
  2. Проверить frontend: доступность кнопки, выбор файла, ограничения по формату, вызов endpoint, обработку успеха и ошибок.
  3. Проверить backend-контракт: endpoint, авторизацию, request, формат ответа, коды ошибок.
  4. Проверить парсер Excel: обязательные колонки, типы значений, пустые строки, дубли, некорректные даты и суммы.
  5. Проверить бизнес-логику: создание новых данных, обновление существующих, связи с заказами, товарами, счетами, оплатами и задачами.
  6. Проверить базовую идемпотентность: повторная загрузка того же файла не должна создавать дубли и ломать связи.
  7. Проверить частичные ошибки: одна плохая строка не должна незаметно портить общий результат.
  8. Зафиксировать вывод в матрице: ожидание -> frontend -> backend -> данные -> риск -> рекомендация -> тест.

Рекомендации формулировать с учетом разового характера импорта: сначала предлагать быстрые защитные проверки и ручной контроль, а полноценные архитектурные доработки выносить только для критичных рисков.

Тестовый прогон на копии базы не предполагается: файл с заказами будет загружаться сразу на прод. Поэтому контроль переносится в три точки:

  1. Предварительная ручная проверка файла до загрузки.
  2. Backup базы непосредственно перед импортом.
  3. Контрольная сверка результата сразу после импорта.

Классификация результатов

ТипКогда использовать
БагИмпорт создает неверные данные, дубли, ломает связи или ошибочно меняет статус.
Рассинхрон frontend/backendFrontend показывает действие или успех иначе, чем реально отработал backend.
Устаревшая документацияКод и интерфейс согласованы, но документация описывает старый порядок.
Спорное поведениеНужен продуктовый выбор: например, перетирать поле импортом или сохранять ручное изменение.
Технический долгРаботает сейчас, но хрупко к изменению формата 1С или расширению импорта.
Нужен тестПоведение критично и должно быть закреплено автоматической проверкой.

Порядок аудита

Шаг 1. Карта текущего импорта

Цель: зафиксировать фактические endpoint, роли, frontend-кнопки, request/response и типы файлов.

Проверить:

  • какие импорты доступны пользователю;
  • где расположены кнопки импорта;
  • какие роли видят кнопки;
  • какие backend endpoints вызываются;
  • какой response возвращается пользователю;
  • какие счетчики и сообщения показывает интерфейс.

Результат: таблица фактических импортов и точек входа.

Результат шага 1, выполнено 09.07.2026:

СценарийFrontend-точка входаFrontend APIBackend endpointПрава на frontendПрава на backendResponseОбновление данных на frontend
Импорт заказов покупателя из 1ССтраница заказов покупателя, кнопка Импорт заказов из 1СuseImportBuyerOrders1CMutationPOST /Order/BuyerOrder/1CPermissionContext.BUYER_ORDERS, поле import1C, роль ChiefSalesManagerEnRole.ChiefSalesManagerSynchronizeResponseИнвалидируется BuyerOrders
Импорт товаров из 1ССтраница заказов покупателя, кнопка Импорт товаров из 1СuseImportGoods1CMutationPOST /Order/Good/1CPermissionContext.BUYER_ORDERS, поле import1C, роль ChiefSalesManagerEnRole.ChiefSalesManagerSynchronizeResponseИнвалидируются Goods, BuyerOrders, Task/LIST
Импорт счетов на оплату из 1ССтраница заказов покупателя, кнопка Импорт счетов для оплаты из 1СuseImportPaymentInvoice1CMutationPOST /Order/PaymentInvoice/1CPermissionContext.BUYER_ORDERS, поле import1C, роль ChiefSalesManagerEnRole.ChiefSalesManagerSynchronizeResponseИнвалидируется BuyerOrders
Синхронизация заказов на производствоFrontend-точки запуска не будет: endpoint запускает внешняя программа по расписаниюНе используетсяPOST /Order/Order/googleНе требуетсяEnRole.ChiefSalesManagerSynchronizeResponseНе требуется, запуск выполняется вне frontend

Фактический SynchronizeResponse:

  • readed / Readed - количество считанных строк;
  • updated / Updated - количество обновленных сущностей;
  • added / Added - количество добавленных сущностей;
  • syncMessages / SyncMessages - сообщения с уровнями Log = 1, Warning = 2, Error = 3.

Диалог импорта из 1С:

  • принимает только .xlsx;
  • после успешного ответа показывает строку Считано: ..., обновлено: ..., добавлено: ...;
  • показывает каждое сообщение syncMessages отдельной строкой с иконкой по уровню;
  • после успешного HTTP-ответа дополнительно показывает toast об успешном импорте;
  • не закрывает автоматически результат импорта, пока пользователь не закроет диалог.

Наблюдения для следующих шагов:

  • frontend и backend по трем Excel-импортам из 1С согласованы по роли ChiefSalesManager;
  • синхронизация заказов на производство запускается не из frontend, а внешней программой по расписанию один раз в день; на шаге синхронизации заказов на производство нужно проверить безопасность ежедневного повторного вызова endpoint;
  • success-toast показывается по факту успешного HTTP-ответа, даже если внутри syncMessages есть предупреждения или ошибки. На шаге UX нужно проверить, не вводит ли это пользователя в заблуждение при частично проблемном импорте.

Шаг 2. Импорт заказов покупателя

Цель: проверить создание и обновление заказов покупателя из 1С.

Проверить:

  • обязательные колонки файла;
  • ключ, по которому определяется существующий заказ;
  • создание нового заказа;
  • обновление существующего заказа;
  • поведение при изменении покупателя, организации, номера, даты, суммы, валюты и ответственного;
  • что происходит с заказом, у которого уже есть активный рабочий процесс;
  • что происходит с заказом, который был изменен вручную после предыдущего импорта;
  • повторный импорт того же файла;
  • импорт файла с дублями строк по одному заказу;
  • сообщения пользователю по добавленным, обновленным и ошибочным строкам.

Особое внимание:

  • не должен создаваться второй процесс по тому же заказу покупателя, если процесс уже есть;
  • для нового импортированного заказа должен создаваться ожидаемый процесс BuyerOrder и стартовая задача;
  • повторный импорт того же заказа не должен создавать повторный процесс или повторную стартовую задачу;
  • импорт не должен незаметно очищать поля, которые отсутствуют в выгрузке;
  • ручные данные должны перетираться только по заранее определенным правилам.

Результат шага 2, выполнено 09.07.2026:

Фактическая схема импорта:

  • файл читается через FileBuyerOrderReader;
  • заголовки ищутся в строке 7, данные начинаются со строки 8;
  • обязательные колонки проверяются по точному названию;
  • заказ определяется по ссылке вида Заказ покупателя N от dd.MM.yyyy;
  • существующий заказ ищется по ключу Number + OurOrganizationId;
  • в БД есть уникальный индекс по Number + OurOrganizationId для неархивных заказов;
  • новые заказы добавляются через AddBuyerOrders;
  • существующие заказы обновляются через UpdateBuyerOrders;
  • для новых не завершенных и не отмененных заказов создается процесс BuyerOrder и стартовая задача BeginBuyerOrder;
  • повторный импорт уже созданного заказа не должен создавать новый процесс, так как заказ попадает в ветку обновления.

Как обрабатываются строки файла:

СитуацияПоведение
Не найден номер заказаСтрока пропускается.
Не указан или не разобран авторСтрока пропускается.
Не указан ИНН покупателяСтрока пропускается.
Не указана или не распознана наша организацияСтрока пропускается.
Не найден покупатель по ИНН/КППСтрока пропускается. Если по ИНН найден ровно один покупатель, он используется с предупреждением.
Контрагент найден, но не является покупателемСтрока пропускается.
Не указан адрес доставкиЗаказ не пропускается, адрес заменяется на ???, в примечание добавляется сообщение.
Не указана дата отгрузкиЗаказ не пропускается, добавляется предупреждение.
Не указана валютаИспользуется рубль, добавляется предупреждение.
Не указано контактное лицоЗаказ не пропускается, контактное лицо заменяется на ???.
Не указан или не разобран ответственныйЗаказ не пропускается, задача может быть создана без исполнителя.

Фактическое обновление существующего заказа:

  • всегда обновляются автор, ответственный, контактное лицо, валюта, наша организация;
  • договор обновляется только если в импортированной строке он найден;
  • адрес доставки перезаписывается всегда;
  • плановая дата отгрузки перезаписывается только если она есть в импортированной строке;
  • примечание перезаписывается только если оно есть в импортированной строке;
  • состояние заказа обновляется только при наличии причины отмены: заказ переводится в Cancelled;
  • остальные статусы из 1С для существующего заказа не переносятся в StateId.

Найденные риски:

РискКритичностьПочему важно для разового запускаРекомендация
Дубли заказов внутри одного файла не отфильтровываются до добавления.ВысокаяЕсли в одном файле есть две новые строки с одинаковым Number + OurOrganizationId, импорт может упасть на уникальном индексе и оставить уже сохраненные подготовительные сущности.Перед запуском проверить файл на дубли. На backend желательно добавить быстрый guard: дубли в файле отдавать в syncMessages и не запускать сохранение.
Импорт не выполняется одной транзакцией.СредняяКонтактные лица, телефоны, сотрудники, подписанты или договоры могут сохраниться до того, как создание заказов упадет. Для одного запуска это терпимо, но повторный запуск будет идти уже по измененной базе.Перед боевым запуском сделать backup базы. Критичные ошибки файла лучше ловить до сохранения.
Если в файле указан подписант покупателя, у SignerEntity не заполняется PartnerId.ВысокаяPartnerId обязателен. Строки с подписантом могут привести к ошибке сохранения подписантов или создать некорректную подготовительную сущность, если в базе есть неожиданные данные.Перед запуском проверить строки с колонкой Контактное лицо подписант. Быстрое исправление: при импорте ставить BuyerSigner.PartnerId равным покупателю заказа.
Банковские реквизиты нашей организации из договора фактически могут не привязаться к договору.СредняяВ SetContracts договор создается без банковских реквизитов, а последующее обновление реквизитов построено хрупко и, судя по коду, не сработает для нового договора.Для разового запуска решить, нужны ли банковские реквизиты договора сразу после импорта. Если нужны - исправить привязку или проверить вручную после импорта.
Дата договора из файла при создании нового договора не используется.СредняяНовый договор создается как импортированный, но дата из 1С не переносится в создаваемый ContractEntity.Проверить на тестовом запуске, какая дата оказывается в договоре. Если дата нужна для дальнейших документов - исправить перед боевым импортом.
При повторном импорте отмененного заказа каждый раз добавляется новая причина отмены.СредняяПовторная загрузка файла может засорить историю причин отмены и изменить PreviousStateId на уже отмененный статус.Добавить guard: не добавлять такую же причину повторно для уже отмененного заказа. Минимум - не загружать повторно файл отмен после успешного импорта.
Новая активная строка с отсутствующим ответственным не блокируется.ВысокаяДля такого заказа создается стартовая задача без исполнителя, и процесс может зависнуть сразу после импорта.Перед запуском проверить, что у всех активных заказов есть распознанный ответственный. Лучше сделать отсутствие ответственного блокирующей ошибкой для активных заказов.
Статус заказа из 1С и созданная стартовая задача могут расходиться.СредняяНапример, строка со статусом В работе получит состояние ProductionStarted, но процесс будет создан со стартовой задачей BeginBuyerOrder.На следующем шаге отдельно проверить правила создания задач для импортированных заказов. Для разового запуска решить: импортировать только заказы, которые должны стартовать с первой задачи, или принудительно нормализовать статус.
Возможен пропуск последней строки файла, если sheet.LastRow в Spire означает номер последней непустой строки.СредняяЦикл читает rowNumber < sheet.LastRow. Если библиотека возвращает именно последнюю строку, последняя строка выгрузки не попадет в импорт.Проверить на тестовом файле с одной контрольной последней строкой. Если строка пропускается - заменить условие на <= sheet.LastRow.

Вывод по шагу:

  • базовый повторный импорт уже существующих заказов защищен ключом Number + OurOrganizationId и не должен создавать повторные процессы;
  • для боевого разового запуска главный риск не в долгой архитектуре, а в качестве файла: дубли, отсутствующий ответственный, строки с подписантом и договорными реквизитами;
  • перед запуском обязательно сделать backup базы, сохранить исходный файл импорта и вручную проверить файл на опасные случаи;
  • сразу после импорта нужна ручная сверка количества строк: сколько заказов прочитано, сколько добавлено, сколько обновлено, сколько пропущено;
  • быстрые исправления, которые стоит рассмотреть до запуска: guard на дубли в файле, блокировка активных заказов без ответственного, корректное заполнение PartnerId подписанта, защита от повторного добавления причины отмены.

Шаг 3. Задачи процесса заказа покупателя после импорта

Цель: проверить, что импортированные заказы покупателя корректно попадают в рабочий процесс.

Проверить:

  • создается ли процесс BuyerOrder для нового импортированного заказа;
  • создается ли стартовая задача процесса;
  • корректно ли заполнены автор, исполнитель, наблюдатели, BuyerOrderId, ProcessId, PreviousTaskId и NextTaskId;
  • соответствует ли стартовый статус задачи ожидаемому сценарию;
  • не создается ли дубль процесса при повторном импорте того же заказа;
  • не создается ли дубль задачи при повторном импорте или обновлении существующего заказа;
  • можно ли открыть импортированный заказ и его задачу на frontend;
  • не теряются ли импортированные поля заказа при первом сохранении задачи;
  • корректно ли процесс проходит хотя бы до этапа, на котором должны быть созданы или импортированы заказы на производство.

Особое внимание:

  • для разового запуска достаточно проверить основной путь и повторный импорт, не нужно полностью заново аудировать весь процесс заказа покупателя;
  • критичны только ошибки, которые оставляют импортированный заказ без задачи, создают дубли процесса или ломают переход к этапу запуска.

Результат шага 3, выполнено 09.07.2026:

Фактическая схема создания процесса:

  • процесс и стартовая задача для импортированного заказа создаются в BuyerOrderService.AddBuyerOrders, а не через общий метод обычного создания заказа;
  • процесс создается только для нового заказа, если состояние заказа не Cancelled и не Completed;
  • тип процесса: BuyerOrder;
  • стартовая задача: BeginBuyerOrder;
  • стартовый статус задачи: FillingOrderInformation;
  • BuyerOrderId заполняется через связь BuyerOrder = buyerOrder;
  • ProcessId заполняется через связь Process = process;
  • PreviousTaskId у стартовой задачи пустой, что корректно для первой задачи процесса;
  • ExecutorId равен buyerOrder.ResponsibleId;
  • запись истории статуса создается сразу, EmployeeId берется из ResponsibleId, а если его нет - из AuthorId;
  • повторный импорт уже существующего заказа идет через ветку обновления и не создает повторный процесс или повторную стартовую задачу.

Отличия импортной стартовой задачи от обычной:

ПолеОбычное создание заказаИмпорт из 1СРиск
AuthorIdОтветственный менеджерНе заполняетсяНиже информативность задачи; автор не участвует в доступе к задаче.
DeadlineЗаполняется настройкойНе заполняетсяИмпортированные стартовые задачи могут выпадать из контроля сроков.
ExecutorIdОтветственный менеджерОтветственный из файла 1СЕсли ответственный не распознан, задача создается без исполнителя.
TaskStatusIdFillingOrderInformationFillingOrderInformationСовпадает.
DateOfStatusChangesСоздается записьСоздается записьПри пустом ответственном история статуса записывается на автора заказа, не на исполнителя.

Найденные риски:

РискКритичностьПочему важно для разового запускаРекомендация
Активный импортированный заказ может получить задачу без исполнителя.ВысокаяЕсли ответственный в файле пустой или не распознан, ExecutorId у BeginBuyerOrder будет null. Доступ к редактированию задачи проверяется через исполнителя.Перед боевым импортом проверить всех ответственных. Быстрое backend-исправление: для активных заказов отсутствие распознанного ответственного делать блокирующей ошибкой строки.
Импортная стартовая задача создается без AuthorId и Deadline.СредняяОбычная задача имеет автора и дедлайн, а импортная - нет. Это может ухудшить отображение, фильтрацию и контроль сроков импортированных задач.Использовать для импорта тот же helper создания стартовой задачи или синхронизировать поля: AuthorId = ResponsibleId, Deadline = GetTaskDeadline(BeginBuyerOrder).
Состояние заказа из 1С может не соответствовать стартовой задаче процесса.СредняяСтроки со статусами В работе или Отгрузка получают состояние ProductionStarted, но процесс все равно стартует с BeginBuyerOrder.Для разового запуска заранее решить допустимые статусы файла. Надежнее импортировать активные незавершенные заказы в состояние BeginBuyerOrder или явно пропускать поздние этапы.
Повторный импорт не восстанавливает процесс, если заказ уже существует, но процесс был утерян.НизкаяВетка обновления не создает недостающую задачу. Для штатного повторного импорта это нормально, но ручная правка БД или старые данные останутся без процесса.Для одного запуска достаточно контрольной сверки: у каждого добавленного активного заказа есть BeginBuyerOrder. Полноценный repair-механизм не обязателен.

Вывод по шагу:

  • основной путь создания процесса для нового активного заказа есть;
  • дубль процесса и стартовой задачи при повторном импорте того же заказа не создается;
  • самый опасный крайний случай - активная строка без распознанного ответственного: заказ будет создан, но задача окажется без исполнителя;
  • перед прод-импортом нужен ручной контроль ответственных и статусов 1С;
  • быстрые исправления, которые стоит рассмотреть до запуска: блокировать активные строки без ответственного и заполнять у импортной стартовой задачи AuthorId/Deadline так же, как при обычном создании заказа.

Шаг 4. Импорт товаров заказов покупателя

Цель: проверить создание и обновление товаров внутри заказов.

Проверить:

  • как строка товара связывается с заказом покупателя;
  • как определяется существующий товар;
  • создание нового товара;
  • обновление количества, цены, номенклатуры, характеристик и сроков;
  • поведение, если заказ покупателя не найден;
  • поведение, если товар уже участвует в задачах, заказах на производство, отгрузках или документах;
  • повторный импорт того же файла;
  • импорт с дублями строк товара;
  • блокирующее ограничение на дубли изделий внутри одного заказа покупателя;
  • влияние на расчет стоимости, КП, спецификацию и запуск.

Особое внимание:

  • импорт товара не должен ломать уже согласованные данные без явного правила;
  • изменения товаров должны быть согласованы с текущим этапом процесса заказа покупателя;
  • дубли строк допускаются только для складских единиц, которые не являются изделиями; если внутри одного заказа покупателя есть несколько строк одного изделия, товары этого заказа нельзя импортировать, нужно вернуть ошибку;
  • пользователь должен видеть строки, которые не удалось импортировать.

Результат шага 4, выполнено 09.07.2026:

Фактическая схема импорта:

  • endpoint: POST /Order/Good/1C, доступен роли ChiefSalesManager;
  • файл читается через FileGoodReader;
  • заголовки ищутся в строке 7, данные начинаются со строки 8;
  • обязательные колонки: Ссылка.Номер, Тип номенклатуры: запас, Номенклатура, Дата отгрузки, Цена, Количество, РРЦ;
  • заказ покупателя определяется по значению Ссылка.Номер: из префикса берется наша организация, из второй части - номер заказа;
  • заказ ищется по ключу Number + OurOrganization.Name;
  • складская единица ищется по точному StockKeepingUnit.Name;
  • существующий товар определяется по ключу BuyerOrderId + StockKeepingUnitId;
  • одинаковые SKU в одном заказе могут быть отдельными позициями 1С с разным количеством и ценой, но безопасно допускать такие дубли только для складских единиц, которые не являются изделиями;
  • дубли изделий внутри одного заказа покупателя должны быть блокирующей ошибкой: товары такого заказа не импортируются, пользователю возвращается сообщение с номером заказа и номенклатурой изделия;
  • текущий код при первом импорте может сохранить одинаковые SKU отдельными строками, так как уникального индекса на BuyerOrderId + StockKeepingUnitId нет;
  • для существующего товара обновляются Count, Price, а RecommendedRetailPrice обновляется только если в файле есть непустое значение;
  • для нового товара создается запись Good;
  • если в файле указана дата отгрузки товара, импорт обновляет у заказа покупателя PlannedShipmentDate и ActualShipmentDate;
  • если тип складской единицы из файла отличается от текущего типа SKU, импорт может обновить тип складской единицы;
  • frontend после импорта инвалидирует Goods, BuyerOrders и список задач.

Как обрабатываются строки файла:

СитуацияПоведение
Не указана номенклатураСтрока пропускается.
Не указан номер заказа покупателяСтрока пропускается.
Не указана или не распознана наша организацияСтрока пропускается.
Не указано количествоСтрока пропускается.
Не указан тип номенклатурыСтрока пропускается.
Не найден заказ покупателяСтрока удаляется из импорта, добавляется предупреждение.
Не найдена складская единицаСтрока удаляется из импорта, добавляется предупреждение.
Не найден подходящий тип складской единицыСтрока удаляется из импорта, добавляется предупреждение.
В одном заказе покупателя есть несколько строк одного изделияТребуемое поведение: товары этого заказа не импортируются, возвращается ошибка с номером заказа и изделием.
В одном заказе покупателя есть несколько строк одной складской единицы, которая не является изделиемДопускается, строки импортируются как отдельные позиции.
Цена пустая или не распознанаТовар не пропускается, Price становится null; позднее задача расчета стоимости заблокирует финал.
РРЦ пустая или не распознанаТовар не пропускается, существующая RecommendedRetailPrice не перетирается пустым значением.

Найденные риски:

РискКритичностьПочему важно для разового запускаРекомендация
Повторный импорт товаров с несколькими одинаковыми SKU в одном заказе работает хрупко.ВысокаяДубли не-изделий должны сохраниться отдельными позициями, но обновление ищет существующий товар только по BuyerOrderId + StockKeepingUnitId и берет первый найденный товар. При повторном импорте несколько строк файла могут обновлять одну и ту же запись.Дубли изделий сделать блокирующей ошибкой на уровне заказа. Для дублей не-изделий разовый запуск лучше выполнять один раз и после этого сверять строки. Если нужен повторный импорт, нужен устойчивый ключ позиции: идентификатор строки 1С, номер строки или порядковый номер внутри группы BuyerOrder + SKU.
Дубли изделий внутри одного заказа покупателя могут сломать дальнейший импорт заказов на производство.ВысокаяЗаказ на производство должен быть привязан к конкретному изделию. Если в заказе покупателя несколько строк одного изделия, дальнейшая синхронизация по номенклатуре не сможет выбрать правильную позицию.Добавить предварительную валидацию файла товаров: сгруппировать строки по BuyerOrder + StockKeepingUnit, определить категорию SKU и, если это изделие и строк больше одной, не импортировать товары этого заказа, вернуть ошибку.
У товаров, созданных или обновленных импортом, не пересчитывается FinalPrice.ВысокаяРучное добавление/изменение товара вызывает RecalculateGoodPrices, а импорт меняет только Price и Count. Суммы заказа, КП и планы оплат используют FinalPrice.После добавления/обновления товаров импортом пересчитать FinalPrice по каждому затронутому заказу тем же методом, что ручной сценарий, либо после импорта выполнить контрольную сверку сумм.
Импорт может менять товары независимо от текущего этапа процесса заказа покупателя.СредняяРучной сценарий проверяет CanModifyOrderGoods, а импорт эту проверку не использует. Повторная загрузка файла после согласований может изменить количество и цену.Для разового запуска зафиксировать порядок: товары импортировать до активной работы по задачам и не перезагружать файл после согласования без ручного решения. Backend-guard можно добавить позже.
Импорт товаров обновляет дату отгрузки заказа покупателя без проверки этапа процесса.СредняяФайл товаров может перезаписать PlannedShipmentDate и ActualShipmentDate, даже если дата уже была уточнена в системе.Перед загрузкой проверить колонку даты отгрузки. Если данные из 1С не считаются источником истины после старта работы, отключить это обновление или делать его только для новых заказов.
Импорт может менять тип существующей складской единицы.СредняяТип SKU является общей справочной характеристикой, а не свойством товара в конкретном заказе. Ошибка в файле может повлиять не только на импортируемый заказ.Для разового запуска проверить строки, где тип номенклатуры из файла отличается от типа SKU. Без отдельного решения лучше не менять типы SKU автоматически из файла товаров.
Возможен пропуск последней строки файла.СредняяFileGoodReader использует цикл rowNumber < sheet.LastRow, как и импорт заказов. Если LastRow - номер последней строки, последняя строка не импортируется.Проверить контрольную последнюю строку в файле. Если проблема подтверждается - заменить условие на <= sheet.LastRow во всех Excel-reader импортах.

Вывод по шагу:

  • базовая привязка товара к заказу и складской единице есть;
  • одинаковые SKU в одном заказе нужно разделить по типу: дубли не-изделий переносить как отдельные позиции, дубли изделий блокировать ошибкой по заказу;
  • повторный импорт обычного товара обновляет его по ключу BuyerOrderId + StockKeepingUnitId, но для нескольких одинаковых SKU этот ключ недостаточен;
  • для безопасного запуска критично вручную сверить количество строк товаров по заказам и соответствие существующим SKU;
  • главный backend-риск - отсутствие пересчета FinalPrice после импорта;
  • до запуска нужна backend-валидация дублей изделий, чтобы заказ с несколькими одинаковыми изделиями не попал в дальнейший процесс и синхронизацию заказов на производство;
  • порядок запуска должен быть строгим: сначала импорт заказов покупателя, затем импорт товаров, затем сверка количества товаров и сумм, и только после этого продолжение задач процесса.

Шаг 5. Синхронизация заказов на производство для импортированных заказов

Цель: проверить сценарий текущей ветки, где заказы на производство подтягиваются для уже импортированных заказов покупателя.

Проверить:

  • откуда берутся заказы на производство в текущей ветке и какой endpoint запускает синхронизацию;
  • как внешняя программа авторизуется и вызывает endpoint по расписанию;
  • что ежедневный повторный запуск не создает дубли и не затирает ручные уточнения;
  • обновляются ли статус заказа на производство и дата согласования чертежа так же, как в PUT /Order/Order/google/{number};
  • какой ключ используется для поиска заказа покупателя;
  • какой ключ используется для поиска товара внутри заказа покупателя;
  • что происходит, если заказ покупателя еще не импортирован;
  • что происходит, если товар заказа покупателя еще не импортирован;
  • что происходит, если товар найден, но это не изделие;
  • что синхронизация запускается только после проверки отсутствия дублей изделий внутри заказов покупателя;
  • создается ли заказ на производство только один раз;
  • обновляются ли существующие заказы на производство без потери важных данных;
  • корректно ли заполняются ссылка на Google-документ, примечание и местоположение производства;
  • показывает ли SynchronizeResponse предупреждения по пропущенным строкам;
  • видны ли созданные заказы на производство в карточке заказа покупателя и на этапе сопровождения;
  • не конфликтует ли импорт заказов на производство с ручным созданием заказа на производство из задачи запуска.

Особое внимание:

  • порядок запуска важен: сначала импорт заказов покупателя, затем импорт товаров, затем синхронизация заказов на производство;
  • перед синхронизацией заказов на производство импорт товаров должен заблокировать заказы с дублями изделий; дубли не-изделий не должны участвовать в создании заказов на производство;
  • синхронизация заказов на производство будет запускаться каждый день внешней программой, поэтому идемпотентность этого endpoint критична даже при разовом импорте из 1С;
  • если строка заказа на производство пропущена из-за отсутствующего заказа покупателя или товара, это должно быть явно видно пользователю;
  • для одного-двух запусков допустим ручной контроль пропущенных строк, но недопустимо молчаливое создание заказов без связанного товара.

Результат шага 5, выполнено 09.07.2026:

Фактическая схема синхронизации:

  • синхронизация запускается через POST /Order/Order/google, доступна роли ChiefSalesManager;
  • в логе метода указано Order/Order/google/synchronize, поэтому внешней программе запуска нужно ориентироваться на фактический маршрут контроллера, а не на строку лога;
  • frontend-точки запуска не планируется: endpoint будет вызывать внешняя программа по расписанию;
  • данные читаются из Google Sheets через service account, используются GoogleConfig.OrdersSpreadsheetId и GoogleConfig.OrdersSheetName;
  • из таблицы читаются номер заказа на производство, номенклатура, номер заказа покупателя, ссылка на Google-документ, примечание и местоположение производства;
  • ключ идемпотентности для заказа на производство - Order.Number;
  • существующие заказы на производство в массовой синхронизации сейчас обновляют только GoogleDocumentLink, Note и LocationManufactureId;
  • отдельно существует PUT /Order/Order/google/{number} для вызова из Google Script: он обновляет StatusId по Status и Dates.DateOfApprovalOfDrawing по DateOfApprovalOfDrawing;
  • для полной синхронизации массовый endpoint должен обновлять статус и дату согласования чертежа так же, как PUT /Order/Order/google/{number};
  • новые заказы на производство проходят через FilterAndSetGoods, где им пытаются найти GoodId, после чего сохраняются через AddOrders;
  • предупреждения по пропущенным или подозрительным строкам возвращаются как SyncMessage с уровнем Warning.

Как обрабатываются строки Google-таблицы:

СитуацияПоведение
Не указан или не разобран номер заказа на производствоСтрока пропускается, добавляется предупреждение.
Не указана номенклатураСтрока пропускается, добавляется предупреждение.
Не указан или не разобран номер заказа покупателяСтрока пропускается, добавляется предупреждение.
Не указана ссылка на Google-документДобавляется предупреждение, но строка продолжает обрабатываться.
Не найдено местоположение производстваДобавляется предупреждение, LocationManufactureId остается пустым, строка продолжает обрабатываться.
В таблице есть несколько строк с одним номером заказа на производствоДобавляется предупреждение, но в обработку попадает последняя строка с этим номером.
Заказ покупателя не найденЗаказ на производство пропускается с предупреждением.
Товар заказа покупателя не найденЗаказ на производство пропускается с предупреждением.
Товар найден, но SKU не является изделиемЗаказ на производство пропускается с предупреждением.
Заказ на производство уже есть в базеСейчас массово обновляются только ссылка на документ, примечание и местоположение производства; статус и дата согласования чертежа не подтягиваются.
Заказа на производство еще нет в базеТекущий код пытается добавить новый OrderEntity, но не заполняет часть обязательных полей.

Найденные риски:

РискКритичностьПочему важно для разового запускаРекомендация
Новые заказы на производство из Google-таблицы могут не создаться.ВысокаяПри ручном создании заказа на производство заполняются ProductId, StatusId, TypeId, Dates и дефолтное местоположение. В ветке AddOrders для Google-синхронизации эти поля не заполняются, хотя OrderEntity требует StatusId, DatesId, TypeId и ProductId. Сохранение новых строк может упасть на ограничениях БД.Перед запуском исправить AddOrders: заполнять заказ теми же обязательными полями, что и ручное создание (ProductId, StatusId = New, TypeId = External, Dates = new OrderDatesEntity(), дефолтное местоположение при необходимости).
Массовая синхронизация не обновляет статус и дату согласования чертежа.ВысокаяPUT /Order/Order/google/{number} обновляет StatusId и Dates.DateOfApprovalOfDrawing, а POST /Order/Order/google сейчас обновляет только ссылку, примечание и местоположение. Если ежедневный endpoint должен заменить или дополнить работу Google Script, заказы могут остаться с устаревшим статусом и датой согласования чертежа.В чтение Google-таблицы и UpdateOrders добавить те же поля и правила, что в UpdateOrderGoogle: парсинг Status через OrderStatusExt.FromText, парсинг DateOfApprovalOfDrawing, понятные warnings/errors при некорректных значениях.
Дубли изделий внутри одного заказа покупателя ломают поиск товара для заказа на производство.ВысокаяЗаказ на производство создается только для изделия. Если в заказе покупателя есть несколько строк одного изделия, FilterAndSetGoods не может однозначно выбрать позицию по StockKeepingUnit.Name + BuyerOrderId, а ToDictionaryAsync может упасть до формирования понятного предупреждения.В импорте товаров запретить дубли изделий на уровне заказа: товары такого заказа не импортировать и возвращать ошибку. Дубли не-изделий можно оставить, так как они не должны превращаться в заказы на производство.
Заказ покупателя ищется только по номеру без учета нашей организации.ВысокаяИмпорт заказов покупателя использует ключ Number + OurOrganizationId, а синхронизация заказов на производство строит словарь только по BuyerOrder.Number. Если одинаковый номер встречается у разных наших организаций, ToDictionaryAsync упадет или будет невозможно однозначно выбрать заказ.Добавить в Google-таблицу и синхронизацию нашу организацию или внутренний BuyerOrderId. Минимум перед запуском проверить, что в импортируемом наборе нет одинаковых номеров заказов покупателя по разным нашим организациям.
Существующий заказ на производство с тем же номером, но другой позицией товара, будет обновлен молча.СредняяДля существующих заказов ключом является только номер заказа на производство. Если в таблице номер совпал, но строка указывает на другой заказ покупателя или другой товар, код обновит ссылку, примечание и местоположение существующего заказа, не проверяя соответствие GoodId.При обновлении сверять найденный GoodId с existsOrder.GoodId. При расхождении не обновлять заказ, а возвращать предупреждение или ошибку.
Дубли номеров заказов на производство в Google-таблице не блокируют синхронизацию.СредняяParser добавляет предупреждение, но затем перезаписывает значение в Dictionary<int, OrderEntity>, поэтому в обработку попадет последняя строка. Для ежедневного запуска это может незаметно менять ссылку, примечание или местоположение производства.Перед сохранением считать дубли номеров блокирующей ошибкой для этих строк или для всей синхронизации. Минимум перед запуском вручную проверить таблицу на дубли номеров заказов на производство.
В БД не видно уникального индекса по номеру заказа на производство.СредняяКод считает Order.Number уникальным и строит ToDictionary. Если в БД окажутся два заказа с одним номером, синхронизация упадет.Проверить фактическую схему БД. Если номер заказа на производство должен быть уникальным, добавить уникальный индекс для непустого Number или предварительную проверку дублей перед запуском синхронизации.

Вывод по шагу:

  • ежедневный запуск безопасен только для уже существующих заказов на производство с уникальными номерами и при отсутствии дублей изделий внутри заказа покупателя;
  • для импортированных из 1С заказов с одинаковыми изделиями текущий механизм привязки заказа на производство к товару недостаточен;
  • перед боевым запуском нужно добавить в импорт товаров блокировку дублей изделий; дубли не-изделий можно оставить как отдельные позиции;
  • создание новых заказов на производство из Google-таблицы требует backend-исправления обязательных полей, иначе endpoint может упасть на сохранении;
  • массовую синхронизацию нужно довести до поведения PUT /Order/Order/google/{number} по статусу и дате согласования чертежа;
  • после синхронизации нужна сверка: количество строк Google-таблицы, количество добавленных/обновленных заказов, предупреждения, связь каждого заказа на производство с конкретным товаром заказа покупателя.

Шаг 6. Импорт счетов на оплату

Цель: проверить создание и обновление счетов на оплату из 1С.

Проверить:

  • как счет связывается с заказом покупателя и планом оплат;
  • как определяется существующий счет;
  • создание нового счета;
  • обновление существующего счета;
  • поведение при изменении суммы, даты, покупателя, организации, статуса и номера;
  • поведение при отсутствии плана оплат;
  • поведение, если по счету уже есть платежи;
  • повторный импорт того же файла;
  • импорт с дублями счетов.

Особое внимание:

  • импорт не должен отвязывать счет от плана оплат без явного правила;
  • счет с оплатами нельзя изменять так, чтобы платежи стали некорректными;
  • изменение счета не должно повторно запускать побочные эффекты, которые уже выполнены.

Результат шага 6, выполнено 09.07.2026:

Фактическая схема импорта:

  • endpoint: POST /Order/PaymentInvoice/1C, доступен роли ChiefSalesManager;
  • frontend запускает импорт со страницы заказов покупателя через кнопку Импорт счетов для оплаты из 1С и общий диалог 1С; диалог показывает readed, updated, added, syncMessages;
  • файл читается через FilePaymentInvoiceReader;
  • заголовки ищутся в строке 7, данные начинаются со строки 8;
  • обязательные колонки: Номер, Дата, Автор, Банковский счет.Номер счета, Банковский счет.Банк.БИК, Договор.№ договора, Договор.Дата, Основание, Комментарий, Покупатель.ИНН, Покупатель.КПП, Организация, Сумма;
  • номер счета формируется как {год из даты счета % 100}-{номер из 1С};
  • существующий счет определяется по ключу Number + OurOrganizationId;
  • заказ покупателя берется из колонки Основание через ParseBuyerOrderLink;
  • покупатель определяется по ИНН + КПП; если точного совпадения нет, но по ИНН найден ровно один покупатель, он используется с предупреждением;
  • наши банковские реквизиты ищутся по AccountNumber + BIC, новые реквизиты могут добавляться через DaData;
  • для нового счета создается новый PaymentSchedule с этапом Other, датой счета и суммой счета;
  • для существующего счета PaymentSchedule не меняется;
  • статус из файла не импортируется: новый счет остается Created, существующий сохраняет текущий StatusId;
  • предупреждения возвращаются как SyncMessage.Warning, служебные сообщения о добавленных сотрудниках/реквизитах - как SyncMessage.Log.

Как обрабатываются строки файла:

СитуацияПоведение
Не указан или не распознан номер счетаСтрока пропускается.
Не указана или не распознана наша организацияСтрока пропускается.
Не указана дата счетаСтрока пропускается.
В Основание не найден номер заказа покупателяСтрока пропускается.
Не указан ИНН покупателяСтрока пропускается.
Не указан или не разобран авторСтрока пропускается.
Не указана суммаСтрока пропускается.
Не указан счет или БИК наших банковских реквизитовСтрока пропускается.
Покупатель не найден по ИНН/КППСтрока удаляется из импорта, добавляется предупреждение.
По ИНН найден ровно один покупатель, но КПП другойИспользуется найденный покупатель, добавляется предупреждение.
Заказ покупателя не найден по номеру и организацииСтрока удаляется из импорта, добавляется предупреждение.
Новые банковские реквизиты не удалось получитьСчета с этими реквизитами удаляются из импорта, добавляется предупреждение.
Счет уже есть в БДОбновляются дата, банковские реквизиты, основание, сумма, НДС, покупатель, договор, автор и непустая заметка.
Счета еще нет в БДСоздается новый счет и новый план оплаты Other.

Найденные риски:

РискКритичностьПочему важно для разового запускаРекомендация
Импорт обновляет существующие счета без ограничений ручного сценария.ВысокаяРучное обновление запрещено для счетов не в статусах Created/Sent, а импорт меняет Total, BuyerId, ContractId, OurBankingDetailId, AuthorId, Reason, InvoiceDate независимо от статуса и наличия оплат.Для существующих счетов со статусами Paid, PartiallyPaid, Overpaid, Cancelled не менять финансовые и связующие поля. Минимум - пропускать такие строки с предупреждением.
Изменение суммы существующего счета не пересчитывает статус и не сверяет уже привязанные платежи.ВысокаяСтатус счета рассчитывается в сервисах платежей от Total и суммы связей InvoicePaymentPaymentInvoice.InvoiceAmount. Если импорт изменит Total уже оплаченного счета, статус может остаться старым и стать неверным.При импорте существующего счета с платежами блокировать изменение Total, BuyerId, OurBankingDetailId, PaymentPercentage/смысла оплаты. Если изменение разрешено, сразу пересчитывать статус тем же правилом, что платежи.
Для существующего счета не проверяется соответствие PaymentSchedule новому основанию.ВысокаяСчет ищется только по Number + OurOrganizationId. Если строка файла с тем же номером указывает на другой заказ покупателя, импорт обновит покупателя/сумму/договор, но оставит старый PaymentScheduleId, а значит счет останется привязан к старому заказу.При обновлении сверять заказ покупателя из файла с existsInvoice.PaymentSchedule.BuyerOrderId. При расхождении не обновлять счет, а возвращать ошибку/предупреждение.
Дубли счетов внутри одного файла не блокируются до сохранения.ВысокаяЕсли в файле две новые строки с одинаковым Number + OurOrganizationId, AddRange может упасть на уникальном индексе. Если счет уже есть в БД, одна и та же запись будет обновлена несколько раз последней строкой.До сохранения валидировать дубли Number + OurOrganizationId внутри файла. Для разового запуска сделать дубли блокирующей ошибкой или хотя бы пропускать все повторяющиеся строки.
Новый импортированный счет всегда создает новый план оплаты Other.СредняяИмпорт не пытается связать счет с существующим планом предоплаты/оплаты перед отгрузкой/финальной оплаты. В результате в заказе могут появиться дополнительные планы Other, не совпадающие с исходным планом оплат.Для разового импорта решить правило: либо импортированные счета сознательно создают Other, либо нужно подбирать существующий план по заказу, этапу/сумме/дате. После импорта сверить планы оплат по заказам.
У нового импортированного счета DueDate остается 0.СредняяВ entity поле обязательное, но парсер его не заполняет. Счет сохранится со сроком оплаты 0 дней, тогда как ручное создание использует значение по умолчанию 10 дней.В импорте выставлять DueDate = 10 или брать срок из файла, если такая колонка появится.
Наши банковские реквизиты могут не соответствовать нашей организации.СредняяSetOurBankingDetails добавляет предупреждение, если найденные реквизиты принадлежат другой нашей организации, но счет не блокирует и все равно получает OurBankingDetailId.Сделать несоответствие банковских реквизитов нашей организации блокирующей ошибкой строки.
Договор ищется только по номеру.СредняяcontractsDb.ToDictionary(c => c.Number) упадет при дублях номеров договоров или выберет недостаточно точный ключ для разных покупателей/организаций.Искать договор по более точному ключу: номер + покупатель + наша организация/дата, либо при дублях не привязывать договор и возвращать предупреждение.
Возможен пропуск последней строки файла.СредняяFilePaymentInvoiceReader использует цикл rowNumber < sheet.LastRow, как и другие reader'ы. Если LastRow - номер последней строки, последняя строка не импортируется.Проверить контрольную последнюю строку в файле. Если проблема подтверждается - заменить условие на <= sheet.LastRow во всех Excel-reader импортах.
Frontend после импорта инвалидирует только BuyerOrders.НизкаяТаблицы счетов и планов оплат живут в отдельном redux-slice и могут остаться со старыми данными, если были открыты до импорта.После успешного импорта очищать/перезагружать paymentInvoices и paymentSchedules либо инвалидировать соответствующие данные, если их перевести на RTK Query tags.

Вывод по шагу:

  • базовая идемпотентность по ключу Number + OurOrganizationId есть, и в БД есть уникальный индекс;
  • самый опасный сценарий - повторный импорт уже оплаченного или частично оплаченного счета: импорт может изменить сумму/покупателя/реквизиты без пересчета статуса и без проверки платежей;
  • второй критичный сценарий - тот же номер счета у той же нашей организации, но другое основание: PaymentScheduleId останется старым, а остальные поля могут обновиться по новой строке;
  • перед боевым запуском стоит добавить guards для существующих счетов с оплатами, дублей счетов внутри файла и несоответствия заказа покупателя существующему PaymentSchedule;
  • после импорта нужна сверка: количество считанных/добавленных/обновленных счетов, список предупреждений, планы оплат Other, суммы счетов против платежей и статусы счетов.

Шаг 7. Связь счетов, платежей и задач

Цель: проверить, что импорт счетов корректно работает вместе с оплатами и процессом заказа покупателя.

Проверить:

  • создание платежей из банковской выписки;
  • автоматическую привязку платежей к счетам;
  • пересчет статусов счетов;
  • влияние оплаты на задачу запуска;
  • повторную обработку оплаты или счета;
  • частичную оплату;
  • переплату;
  • оплату без найденного счета;
  • оплату по нескольким счетам.

Особое внимание:

  • автоматические переходы задач должны быть идемпотентными;
  • повторный импорт или повторная обработка не должны повторно завершать задачу или создавать дубли планов оплат.

Результат шага 7, выполнено 09.07.2026:

Фактическая схема работы:

  • банковская выписка загружается через POST /Order/BankStatement, endpoint доступен бухгалтеру;
  • файл читается как Windows-1251, платежи выделяются из секций СекцияДокумент ... КонецДокумента;
  • дубли уже загруженных платежей фильтруются по ключу Number + Date + PayerAccountNumber;
  • счет ищется по номеру из назначения платежа и ИНН покупателя;
  • если счет найден, платеж связывается через InvoicePaymentPaymentInvoice, а статус счета пересчитывается по сумме всех связей;
  • если счет не найден или есть ошибка по счету, платеж все равно сохраняется с текстом ошибки;
  • после сохранения выписки для счетов, которые стали Paid или Overpaid, вызывается HandleSigningSpecificationTaskDone;
  • ручная перепривязка платежа к счету также пересчитывает статус счета и при полной оплате вызывает HandleSigningSpecificationTaskDone.

Как обрабатываются платежи:

СитуацияПоведение
Файл без документовИмпорт отклоняется с ошибкой В файле нет документов.
Платеж уже был загруженПлатеж отфильтровывается; если новых платежей нет, импорт отклоняется с ошибкой Данная выгрузка уже добавлена.
В назначении платежа не найден номер счетаПлатеж сохраняется без связи со счетом и с ошибкой.
Счет с таким номером не найденПлатеж сохраняется без связи со счетом и с ошибкой.
ИНН плательщика не совпадает с покупателем в счетеПлатеж сохраняется без связи со счетом и с ошибкой.
Банковский счет получателя не совпадает со счетомПлатеж привязывается к найденному счету, но сохраняется ошибка.
Счет отмененПлатеж привязывается к найденному счету, но сохраняется ошибка.
Сумма оплат меньше суммы к оплатеСчет получает статус PartiallyPaid.
Сумма оплат равна сумме к оплатеСчет получает статус Paid.
Сумма оплат больше суммы к оплатеСчет получает статус Overpaid; в таблице платежей дополнительно показывается ошибка о превышении суммы.
Оплачен счет предоплатыBackend пытается автоматически перевести задачу SigningSpecification в запуск и завершить ее.
Оплачен счет не по предоплатеАвтозавершение задачи подписания спецификации не выполняется.

Повторная проверка ветки stage:

  • основная проблема идемпотентности автозавершения по предоплате закрыта;
  • HandleSigningSpecificationTaskDone не выполняет автопереход для счетов не-предоплаты;
  • автопереход выполняется только когда все активные счета предоплаты по заказу оплачены;
  • если задача SigningSpecification уже завершена, повторная обработка пропускается;
  • перевод в CreatingOrders выполняется только из состояний AwaitingCurrent или InProgress;
  • перед завершением SigningSpecification проверяется, что задача SupportOrder еще не создана;
  • планы BeforeShipping и Final создаются только если активного плана такого этапа еще нет;
  • добавлено уведомление исполнителю/ассистентам об автоматической смене статуса задачи.

Остаточные риски:

РискКритичностьПочему важно для разового запускаРекомендация
Результат автозавершения игнорируется вызывающими сервисами.СредняяBankStatementService и InvoicePaymentService вызывают HandleSigningSpecificationTaskDone, но не проверяют OperationResult. Платеж или выписка могут сохраниться успешно, а пользователь не увидит, что автопереход задачи не выполнен.Проверять результат HandleSigningSpecificationTaskDone. Для выписки можно не откатывать платежи, но нужно вернуть/показать предупреждение о том, что оплата сохранена, а задача не переведена автоматически.
Проверка существования SupportOrder и создание следующей задачи не защищены от параллельной гонки.СредняяПри обычном повторном вызове дубль не создается. Но два параллельных вызова могут одновременно увидеть отсутствие SupportOrder и оба перейти к созданию следующей задачи.Для надежности добавить уникальную защиту на уровне данных или транзакционную проверку при создании следующей задачи SupportOrder по заказу покупателя. Для разового запуска риск ниже, но тест на параллельность полезен.
Результат paymentScheduleService.AddByStage при создании BeforeShipping и Final не проверяется.СредняяПовторные планы теперь не создаются за счет предварительной проверки существующих этапов. Но если создание нового плана упадет по другой причине, метод может продолжить и создать SupportOrder.Проверять результат AddByStage и прекращать завершение задачи, если обязательный план оплаты не создан.
Импорт выписки сохраняет проблемные платежи как успешный импорт банковской выписки.СредняяПлатежи без найденного счета или с ошибкой по счету остаются в системе, а сама выписка создается. Это правильно для ручной разборки, но для разового запуска легко пропустить строки с ошибками, если пользователь смотрит только общий успех.После загрузки выписки обязательно открыть список платежей по выписке и проверить поле Error. Для UI шага 8 отдельно проверить, что ошибки платежей хорошо заметны.
Повторный импорт того же платежа не повторяет автозавершение задачи.НизкаяДубли платежей фильтруются до привязки. Если первый запуск сохранил оплату и пересчитал счет, но автопереход задачи не выполнился, повторная загрузка той же выписки не станет повторной попыткой автозавершения.После загрузки выписки сверять состояние задачи SigningSpecification. Если нужен ручной повтор автоперехода, лучше делать его отдельной идемпотентной операцией по счету/заказу.
Импортированные из 1С новые счета создаются на плане Other, поэтому их оплата не запускает задачу по предоплате.СредняяАвтозавершение работает только для счетов, чей PaymentSchedule.PaymentStageId = Prepayment. Если счет предоплаты пришел из 1С как новый счет и получил план Other, оплата такого счета не переведет задачу запуска автоматически.До боевого сценария определить правило: счета предоплаты должны создаваться из задачи/плана предоплаты или импорт должен уметь привязать их к существующему плану Prepayment. После импорта счетов сверить, что предоплатные счета не в Other.
Поиск номера счета в назначении платежа поддерживает только один шаблон число-число.НизкаяЕсли банк/1С выгрузит назначение платежа с другим форматом номера или несколькими номерами счетов, платеж останется без связи или будет связан только с первым найденным номером.Для разового запуска заранее проверить несколько реальных строк назначения платежа. Не расширять парсер без необходимости, если формат файла стабилен.

Покрытие тестами:

  • есть интеграционные проверки загрузки выписки, дубля платежа, частичной оплаты, полной оплаты, переплаты, отвязки/перепривязки платежей и платежа без найденного счета;
  • есть сценарий, где банковская выписка оплачивает предоплату и завершает задачу SigningSpecification;
  • не найден тест повторного вызова автозавершения по уже завершенной задаче и проверки, что не создается дубль SupportOrder;
  • не найден тест параллельной обработки одной оплаченной предоплаты;
  • не найден тест, что ошибка автоперехода возвращается пользователю при загрузке выписки или ручной перепривязке платежа;
  • не найден тест уведомления исполнителю при автоматическом изменении статуса задачи.

Вывод по шагу:

  • механизм привязки платежей к счетам и пересчета статусов в целом согласован и уже покрыт интеграционными тестами;
  • в ветке stage основная идемпотентность автозавершения по оплате предоплаты закрыта: повторная обработка завершенной задачи пропускается, существующая SupportOrder проверяется, планы оплат не создаются повторно;
  • перед боевым импортом и загрузкой оплат стоит доработать/проверить возврат ошибок автоперехода из BankStatementService и InvoicePaymentService, а также добавить тест повторной и, при необходимости, параллельной обработки;
  • после загрузки выписки обязательно сверить платежи с ошибками, статусы счетов, состояние задачи SigningSpecification и отсутствие дублей задачи SupportOrder.

Шаг 8. Frontend UX и сообщения пользователю

Цель: проверить, что пользователь понимает результат импорта и может исправить ошибки.

Проверить:

  • запрет загрузки неподдерживаемых файлов;
  • поведение при ошибке сети или backend-ошибке;
  • отображение readed, updated, added;
  • отображение syncMessages;
  • разделение логов, предупреждений и ошибок;
  • возможность повторить импорт после исправления файла;
  • обновление таблиц после успешного импорта;
  • не вводит ли успех toast в заблуждение, если часть строк завершилась ошибками.

Результат шага 8, выполнено 09.07.2026:

Фактическая схема frontend:

  • импорты заказов, товаров и счетов из 1С запускаются с таблицы заказов покупателя через общий диалог ImportDialog;
  • диалог принимает только .xlsx; при выборе другого файла показывает ошибку Пожалуйста, выберите файл excel в формате .xlsx;
  • кнопка импорта заблокирована, пока файл не выбран или идет загрузка;
  • после успешного HTTP-ответа диалог показывает счетчики Считано, обновлено, добавлено и список syncMessages;
  • сообщения показываются отдельными строками с иконками уровней Log, Warning, Error;
  • после успешного HTTP-ответа дополнительно показывается success-toast, даже если в syncMessages есть предупреждения или ошибки;
  • при backend-ошибке RTK Query возвращает текст ошибки через общий error-listener и showError;
  • после успешного импорта заказов инвалидируются BuyerOrders;
  • после успешного импорта товаров инвалидируются Goods, BuyerOrders, список задач;
  • после успешного импорта счетов инвалидируются только BuyerOrders.

Фактическая схема банковских выписок:

  • банковская выписка загружается на отдельной странице через .txt;
  • при выборе файла другого формата показывается ошибка Недопустимый формат файла. Загрузите файл в формате .txt.;
  • после успешного создания выписки показывается success-toast Банковская выгрузка успешно создана!;
  • таблица выписок показывает флаг Требуется корректировка;
  • подробные ошибки конкретных платежей видны только после перехода в платежи по выписке;
  • в таблице платежей есть колонка Ошибка, ячейка с ошибкой подсвечивается красным текстом;
  • бухгалтер может открыть редактирование платежа и перепривязать его к другому счету.

Отдельно по обходному сценарию с импортными счетами на Other:

  • если импорт создал счет и план Other, а в процессе нужен счет предоплаты, можно позже создать нормальный счет на этапе Prepayment;
  • затем оплату можно вручную перепривязать с импортного счета Other на счет Prepayment через редактирование платежа;
  • это рабочий обходной путь, но он требует ручной сверки: старый счет/план Other сам по себе не исчезнет и может остаться лишним в картине оплат.

Повторная проверка сценария Импорт счетов для оплаты из 1С:

  • сценарий начинается на странице заказов покупателя, кнопка доступна только ChiefSalesManager;
  • это импорт счетов из Excel-файла 1С, а не загрузка платежей бухгалтером;
  • импорт вызывает POST /Order/PaymentInvoice/1C, счет связывается с заказом через номер заказа в колонке Основание и нашу организацию;
  • новый импортированный счет всегда получает новый план оплаты с этапом Other;
  • существующий счет определяется по Number + OurOrganizationId, а его существующий PaymentScheduleId не меняется;
  • импорт сам не создает платежи, не пересчитывает задачу и не завершает SigningSpecification;
  • если импортированный счет фактически является счетом предоплаты, автоматическое продвижение задачи после оплаты не сработает, пока счет/платеж не будут приведены к этапу Prepayment;
  • после импорта менеджер должен сверить созданные счета в карточке заказа и планы оплат; если вкладки уже были открыты, их нужно обновить вручную, потому что frontend очищает только BuyerOrders.

Найденные UX-риски:

РискКритичностьПочему важно для разового запускаРекомендация
Success-toast показывается при частичных ошибках импорта.СредняяBackend может вернуть SynchronizeResponse с syncMessages уровня Error, но HTTP-ответ успешный, поэтому пользователь видит сообщение об успешном импорте.Для разового запуска в чек-листе явно требовать читать все syncMessages. В интерфейсе лучше показывать warning/error-toast, если в ответе есть ошибки.
Диалог импорта не выделяет итоговый статус есть ошибки.СредняяКрасная иконка у строки есть, но общий заголовок результата остается нейтральным. При большом списке сообщений пользователь может не понять, что импорт завершился частично.Добавить сверху краткий итог: Есть ошибки, Есть предупреждения, Без ошибок; для ошибок можно не скрывать кнопку закрытия до подтверждения.
После импорта счетов обновляется только список заказов покупателя.СредняяСценарий запускается со страницы заказов покупателя, и менеджер ожидает увидеть созданные счета/планы в карточке заказа. Если вкладки счетов или планов оплат уже открыты, они могут остаться со старым состоянием до ручного обновления.Инвалидировать/очищать данные счетов и планов оплат после импорта счетов. Для разового запуска включить в чек-лист ручное обновление карточки заказа после импорта.
Ошибки платежей по выписке видны не сразу на странице выписки.СредняяСтраница выписок показывает только Требуется корректировка, но не раскрывает список проблемных платежей. После success-toast пользователь может не открыть детали.После загрузки выписки обязательно открыть платежи по выписке и проверить колонку Ошибка. В UI можно добавить быстрый переход/счетчик проблемных платежей.
Ручная перепривязка оплаты с Other на Prepayment не оформлена как сценарий.СредняяТехнически платеж можно перепривязать, но пользователь должен понимать, какой новый счет создать и какой старый импортный счет останется как след от импорта.Для боевого запуска описать ручной порядок: создать счет предоплаты, открыть платеж, перепривязать оплату, проверить статус счета и задачу SigningSpecification.
Диалог импорта очищает выбранный файл после попытки импорта.НизкаяПосле backend-ошибки пользователь должен выбрать файл заново. Для одного запуска это неудобство, но не риск порчи данных.Можно оставить как есть; если импорт будут повторять часто, сохранять выбранный файл при ошибке.

Вывод по шагу:

  • frontend показывает основные счетчики и сообщения импорта достаточно прозрачно для ручной сверки;
  • критичных UX-блокеров для одного-двух запусков не найдено;
  • главный риск - пользователь может принять success-toast за полный успех и не разобрать syncMessages;
  • для сценария счетов главный пользовательский контроль: после импорта открыть карточки нескольких заказов из файла и сверить вкладки счетов и планов оплат;
  • перед боевым импортом нужен короткий ручной чек-лист: прочитать все сообщения диалога, отдельно проверить строки с error/warning, после импорта счетов обновить открытые карточки заказов и сверить счета/планы; если отдельно загружается банковская выписка, после нее открыть платежи и проверить колонку Ошибка.

Шаг 9. Права доступа

Цель: проверить согласованность frontend-видимости и backend-авторизации.

Проверить:

  • кто видит кнопки импорта;
  • кто может вызвать endpoint напрямую;
  • совпадают ли frontend permissions с backend [AuthorizeRoles];
  • есть ли пользователи, которым импорт нужен по бизнес-сценарию, но endpoint недоступен;
  • есть ли пользователи, которым импорт показывается на frontend, но backend его запрещает.

Результат шага 9, выполнено 09.07.2026:

Фактическая схема прав:

СценарийFrontendBackendВывод
Импорт заказов покупателя из 1СКнопка видна только ChiefSalesManagerPOST /Order/BuyerOrder/1C доступен только ChiefSalesManagerСогласовано.
Импорт товаров из 1СКнопка видна только ChiefSalesManagerPOST /Order/Good/1C доступен только ChiefSalesManagerСогласовано.
Импорт счетов на оплату из 1ССтраница заказов покупателя, кнопка Импорт счетов для оплаты из 1С видна только ChiefSalesManagerPOST /Order/PaymentInvoice/1C доступен только ChiefSalesManagerСогласовано. Это менеджерский сценарий импорта счетов, не загрузка платежей бухгалтером.
Просмотр банковских выписокМаршрут /bank-statements доступен Accountant, AdminGET /Order/BankStatement/table доступен Accountant, AdminСогласовано.
Загрузка банковской выпискиКнопка Добавить видна только AccountantPOST /Order/BankStatement доступен только AccountantСогласовано. Это отдельный сценарий загрузки оплат, а не импорт счетов из 1С.
Просмотр платежей по конкретной выпискеМаршрут доступен Accountant, AdminGET /BankStatement/{id}/InvoicePayment/table доступен Accountant, AdminСогласовано.
Страница всех платежейМаршрут /invoice-payments доступен Accountant, ChiefSalesManager, ProductionManager, AdminGET /Order/InvoicePayment/table доступен ChiefSalesManager, Accountant, AdminРассинхрон: ProductionManager видит маршрут, но получит ошибку доступа при загрузке таблицы.
Перепривязка платежа к счетуВ общих платежах кнопка редактирования только у Accountant; в планах оплат поле changeInvoicePayment доступно Accountant, ChiefSalesManager, ProductionManager, AdminPATCH /Order/InvoicePayment/{id} доступен ChiefSalesManager, SalesManager, AssistantSalesManager, ProductionManager, AccountantРассинхрон: frontend может показать действие Admin, но backend его запретит; backend разрешает SalesManager/AssistantSalesManager, но frontend в планах оплат им действие не дает.
Просмотр счетов на оплатуСтраницы/вкладки доступны по контекстным permissionsТаблицы счетов доступны разным наборам ролей; общий список GET /PaymentInvoice/table не доступен ProductionManagerВ основном согласовано, но нужно отдельно проверить, нужен ли ProductionManager общий список счетов.
Daily/внешний запуск синхронизации заказов на производствоFrontend-точки нет, endpoint вызывает внешняя программа по расписаниюВ ветке разработки есть массовый endpoint POST /Order/Order/google с ролью ChiefSalesManager, но рядом оставлен старый POST /Order/Order/google для создания пустой таблицы с ролью TesterСценарий по правам понятен, но маршруты конфликтуют: два метода имеют один HTTP-метод и один route.
Обновление заказа на производство из GoogleFrontend-точки нетPUT /Order/Order/google/{number} анонимный, но проверяет AccessCodeДля Google script сценария отдельная защита через код доступа есть.

Найденные риски:

РискКритичностьПочему важно для разового запускаРекомендация
ProductionManager видит страницу всех платежей, но backend не дает общий список оплат.СредняяПользователь может открыть раздел Платежи, получить ошибку загрузки и не понять, что это проблема прав, а не данных.Либо убрать ProductionManager из RouteRoles.invoicePayment, либо добавить его в GET /Order/InvoicePayment/table, если доступ нужен.
Права на перепривязку платежа различаются между frontend и backend.СредняяДля обходного сценария Other -> Prepayment важно, кто реально может перепривязать оплату. Сейчас Admin может увидеть действие в некоторых местах, но backend запретит; sales-роли наоборот разрешены backend, но не всегда frontend.Согласовать один список ролей для changeInvoicePayment и PATCH /Order/InvoicePayment/{id}. Для боевого запуска определить ответственного за перепривязку, лучше Accountant.
В ветке разработки конфликтуют два POST /Order/Order/google.ВысокаяASP.NET Core не выбирает action по роли пользователя. При двух одинаковых маршрутах POST /Order/Order/google возможна неоднозначная маршрутизация вместо запуска массовой синхронизации.Развести маршруты: например, массовую синхронизацию сделать POST /Order/Order/google/synchronize, а создание пустой таблицы оставить отдельным tester/dev endpoint или удалить, если он больше не нужен.
Импорт из 1С доступен только ChiefSalesManager.НизкаяЭто согласовано frontend/backend и подходит для контролируемого разового запуска, но импорт не сможет выполнить бухгалтер или админ без смены роли/токена.Для боевого запуска заранее определить пользователя с ролью ChiefSalesManager, который выполнит Excel-импорты.
Загрузить банковскую выписку может только Accountant, не Admin.НизкаяЭто не относится к импорту счетов из 1С, но важно для отдельного сценария подтверждения оплат: админ не сможет заменить бухгалтера при загрузке выписки.Если после импорта счетов планируется загружать оплаты, заранее определить бухгалтера или временно выдать нужную роль ответственному пользователю.

Вывод по шагу:

  • основные Excel-импорты из 1С по правам согласованы: frontend показывает кнопки на странице заказов покупателя только ChiefSalesManager, backend принимает только ChiefSalesManager;
  • импорт счетов из 1С - это менеджерский сценарий через кнопку Импорт счетов для оплаты из 1С, а не бухгалтерская загрузка платежей;
  • банковские выписки по правам согласованы как отдельный сценарий оплат: просмотр доступен Accountant/Admin, загрузка только Accountant;
  • для основного разового импорта нужен пользователь/токен ChiefSalesManager; Accountant нужен только если в этом же прогоне будут загружать банковскую выписку или вручную перепривязывать оплаты;
  • нужно исправить или хотя бы учесть рассинхроны вокруг страницы всех платежей и перепривязки платежа;
  • для daily-сценария заказов на производство нужно развести конфликтующие маршруты POST /Order/Order/google и заранее подготовить пользователя/токен с ролью ChiefSalesManager для внешней программы запуска.

Шаг 10. Матрица тестов

Цель: сформировать набор ручных и автоматических проверок.

Для разового импорта основной упор делается на ручные сценарные проверки и несколько точечных backend-тестов для самых опасных мест. Полный набор автотестов нужен только там, где ошибка может незаметно испортить данные.

Минимальные сценарии:

  • успешный импорт новых заказов;
  • повторный импорт тех же заказов;
  • импорт заказов с ошибочной строкой;
  • проверка, что для нового импортированного заказа создан ровно один процесс и ровно одна стартовая задача;
  • повторный импорт заказа не создает дубль процесса и задачи;
  • успешный импорт товаров к существующим заказам;
  • импорт товара без найденного заказа;
  • повторный импорт товаров;
  • успешная синхронизация заказа на производство к импортированному заказу и товару;
  • синхронизация заказа на производство до импорта заказа покупателя дает понятное предупреждение;
  • синхронизация заказа на производство до импорта товара дает понятное предупреждение;
  • повторная синхронизация заказа на производство не создает дубль;
  • успешный импорт счетов к существующим заказам;
  • импорт счета с основанием на заказ покупателя, запущенный кнопкой Импорт счетов для оплаты из 1С на странице заказов покупателя;
  • импорт счета без найденного заказа покупателя в Основание;
  • повторный импорт счетов;
  • импорт счета, по которому уже есть платеж;
  • импорт счета предоплаты из 1С и проверка, что он попал в Other и не продвигает задачу без ручного сценария;
  • проверка прав доступа на frontend и backend;
  • проверка отображения ошибок и предупреждений в диалоге импорта.

Для одного-двух запусков допустимо заменить часть автоматических тестов чек-листом ручной проверки, если сценарий легко воспроизводится и не будет поддерживаться постоянно.

Матрица проверки

УчастокОжиданиеFrontendBackendДанныеРискРекомендацияТест
Заказы покупателяИмпорт должен создать или обновить заказ без дублей, не теряя важные ручные данные.Три кнопки импорта доступны начальнику менеджеров по продажам через общий диалог.POST /Order/BuyerOrder/1C, ключ Number + OurOrganizationId, новые заказы создают процесс и стартовую задачу.Есть уникальный индекс по Number + OurOrganizationId; подготовительные сущности сохраняются до финального создания заказов.Дубли в файле, отсутствие ответственного, подписант без PartnerId, повторные причины отмены, возможный пропуск последней строки.Перед боевым запуском проверить файл на дубли и ответственных, сделать backup базы, сохранить исходный файл, рассмотреть быстрые guards.Нужен ручной чек-лист перед прод-импортом и контрольная сверка результата после импорта.
Задачи процесса заказа покупателяНовый активный импортированный заказ должен получить один процесс BuyerOrder и одну стартовую задачу BeginBuyerOrder.Открытие задачи идет через CreateBuyerOrderTaskId; редактирование зависит от доступа к задаче и исполнителя.AddBuyerOrders создает процесс и задачу только для новых не завершенных и не отмененных заказов; повторный импорт идет через обновление.ExecutorId берется из ResponsibleId; AuthorId и Deadline у импортной стартовой задачи не заполняются.Активный заказ без распознанного ответственного получает задачу без исполнителя; состояние ProductionStarted может сочетаться со стартовой задачей.Перед запуском проверить ответственных и статусы 1С; на backend желательно блокировать активные строки без ответственного и заполнять AuthorId/Deadline.Контрольная сверка после импорта: у каждого добавленного активного заказа есть одна задача BeginBuyerOrder с исполнителем.
Товары заказовИмпорт должен сохранить дубли не-изделий как отдельные позиции, но блокировать заказ с дублями изделий.Кнопка импорта доступна через общий диалог; после успеха инвалидируются Goods, BuyerOrders и список задач.POST /Order/Good/1C; нужен guard по BuyerOrder + StockKeepingUnit: дубли изделий делают заказ ошибочным, дубли не-изделий допускаются.Файл может обновить Count, Price, RecommendedRetailPrice, даты отгрузки заказа и тип SKU; уникального индекса нет.Повторный импорт одинаковых SKU хрупкий; дубли изделий ломают дальнейшую привязку заказов на производство; нет пересчета FinalPrice; возможна перезапись дат отгрузки.Добавить предварительную валидацию дублей изделий, для дублей не-изделий при повторном импорте нужен ключ позиции; пересчитывать FinalPrice после импорта.Контрольная сверка: дубли изделий возвращают ошибку и не импортируют заказ; дубли не-изделий сохраняются отдельными позициями; суммы и последняя строка файла корректны.
Заказы на производствоСинхронизация должна создать или обновить заказ на производство один раз и привязать его к конкретной позиции изделия.Frontend-точки запуска нет; endpoint вызывает внешняя программа по расписанию.POST /Order/Order/google; ключ заказа на производство - Number; заказ покупателя ищется по номеру, изделие - по SKU name + BuyerOrderId.Новые заказы требуют GoodId, ProductId, StatusId, TypeId, Dates; дубли изделий должны быть заблокированы раньше.Новые заказы могут не сохраниться из-за незаполненных обязательных полей; массово не обновляются статус и дата согласования чертежа; без guard дубли изделий ломают ToDictionary.Добавить guard дублей изделий в импорт товаров, заполнение обязательных полей в AddOrders, обновление статуса/даты чертежа как в PUT /Order/Order/google/{number}.Проверить таблицу на дубли номеров; прогнать синхронизацию после импорта без дублей изделий; сверить статус, дату чертежа и связи с товарами.
Счета на оплатуИмпорт должен создать или обновить счет из файла 1С со страницы заказов покупателя и не ломать план оплат заказа.Кнопка Импорт счетов для оплаты из 1С доступна на странице заказов покупателя; общий диалог показывает readed/updated/added и сообщения; после импорта очищается только BuyerOrders.POST /Order/PaymentInvoice/1C; ключ счета - Number + OurOrganizationId; заказ ищется по номеру из Основание и нашей организации; новый счет создает план оплаты Other, существующий план не меняет.Есть уникальный индекс по Number + OurOrganizationId; новые счета получают PaymentStage = Other; платежи связаны через InvoicePaymentPaymentInvoice.InvoiceAmount.Импорт обновляет оплаченные счета без ручных guards; изменение суммы не пересчитывает статус; при новом основании старый PaymentScheduleId сохраняется; счет предоплаты из 1С попадает в Other; дубли в файле опасны.Добавить guards для оплаченных/частично оплаченных счетов, сверку заказа с PaymentSchedule, проверку дублей файла, DueDate = 10 для новых импортных счетов; для предоплаты определить ручной или автоматический перевод из Other в Prepayment.Запустить импорт именно кнопкой на buyer-orders; повторный импорт того же файла; файл с дублем счета; счет без найденного заказа; существующий оплаченный счет с измененной суммой; счет предоплаты из 1С и сверка планов Other.
Платежи и выпискиВыписка должна быть отдельным сценарием после импорта счетов: создать платежи, связать их со счетами, пересчитать статус счета и безопасно продвинуть задачу по оплаченной предоплате.Страница банковских выписок загружает файл и обновляет таблицу; ошибки отдельных платежей видны в таблице платежей по выписке.POST /Order/BankStatement; дубли платежей фильтруются по Number + Date + PayerAccountNumber; оплата Prepayment вызывает HandleSigningSpecificationTaskDone; в stage автопереход защищен guard'ами.Платежи связаны через InvoicePaymentPaymentInvoice; статус счета зависит от суммы связей и PaymentPercentage; задача ищется по BuyerOrderId + SigningSpecification; повторные планы оплат не создаются.Остаточный риск: результат автоперехода игнорируется вызывающими сервисами; возможна параллельная гонка при создании SupportOrder; оплата счета на плане Other не запускает предоплату; ошибки платежей легко пропустить.Проверять результат HandleSigningSpecificationTaskDone, добавить тест повторной/параллельной обработки, ручную сверку платежей с ошибками после выписки, сверку предоплатных счетов не на Other перед загрузкой оплат.Тест повторной обработки оплаченной предоплаты: не создаются дубли SupportOrder и планов оплат; тест ошибки автоперехода; тест уведомления; ручная сверка ошибок платежей после загрузки выписки; тест оплаты импортного счета Other.
Права доступаПользователь должен видеть только те действия, которые backend реально разрешает, а ответственные роли должны покрывать боевой запуск.Excel-импорты заказов, товаров и счетов видны ChiefSalesManager на странице заказов покупателя; выписки видны Accountant/Admin, загрузка только Accountant; /invoice-payments доступен также ProductionManager; frontend-точки daily-синхронизации заказов на производство нет.Excel-импорты доступны только ChiefSalesManager; выписку загружает только Accountant; общий список оплат не доступен ProductionManager; перепривязка платежа не доступна Admin; массовая синхронизация заказов на производство доступна ChiefSalesManager, но конфликтует маршрутом со старым tester endpoint.Для основного импорта нужен ChiefSalesManager; Accountant нужен только для отдельного сценария выписки/перепривязки оплат; внешней программе нужен токен пользователя с ролью ChiefSalesManager.Рассинхрон страницы всех платежей для ProductionManager; рассинхрон ролей перепривязки платежа; конфликт двух POST /Order/Order/google может сломать внешний daily-запуск.Согласовать роли invoicePayment и changeInvoicePayment; заранее подготовить пользователя/токен ChiefSalesManager; для выписки отдельно подготовить Accountant; развести маршруты endpoint заказов на производство.Ручная проверка входа под ChiefSalesManager, Accountant, ProductionManager, Admin; прямой вызов endpoints импорта/выписки; проверка перепривязки платежа; прямой вызов daily endpoint после разведения маршрутов.
UX результата импортаПользователь должен понять, какие строки импортированы, какие пропущены и какие требуют ручной проверки.Диалог показывает счетчики и syncMessages; success-toast появляется при любом успешном HTTP-ответе; после импорта счетов карточка заказа может требовать ручного обновления вкладок счетов/планов.Backend возвращает SynchronizeResponse; HTTP-ошибки показываются через общий error-listener; частичные ошибки остаются внутри успешного ответа.После импорта счетов инвалидируется только BuyerOrders; ошибки платежей хранятся в InvoicePayment.Error; импортные счета на Other можно исправлять ручной перепривязкой оплаты.Пользователь может принять частично проблемный импорт за полный успех; открытые таблицы счетов/планов могут быть не обновлены; ошибки платежей по выписке нужно открывать отдельно, если выписка используется отдельным шагом.Для разового запуска сделать чек-лист сверки; в UI желательно показывать общий статус есть ошибки/предупреждения, инвалидировать счета/планы после импорта счетов, добавить быстрый контроль ошибок выписки.Ручной сценарий: импорт с warning/error в syncMessages; импорт счетов при открытой карточке заказа; сверка вкладок счетов/планов после обновления; загрузка выписки с ошибочным платежом; перепривязка оплаты с Other на Prepayment.

Шаг 11. Итоговая приоритизация

Цель: превратить найденные риски в рабочий набор задач и предбоевой чек-лист.

Для одного-двух запусков не все найденные проблемы нужно исправлять кодом. В код стоит выносить только то, что может испортить данные, создать дубли, сломать связи или остановить запуск без понятной ошибки. Остальное можно закрыть ручной проверкой файла, backup базы и контрольной сверкой результата.

Задачи, которые стоит выполнить до боевого запуска:

ЗаголовокТипКритичностьОписание
Защитить импорт заказов покупателя от опасных строк файлаБекВысокаяДобавить guard на дубли Number + OurOrganizationId внутри файла, блокировать активные заказы без распознанного ответственного, заполнить BuyerSigner.PartnerId для подписанта покупателя.
Привести импортную стартовую задачу к обычному созданию задачиБекСредняяДля BeginBuyerOrder, созданной импортом, заполнять AuthorId и Deadline; для активного заказа без исполнителя возвращать ошибку строки, а не создавать задачу без ExecutorId.
Защитить импорт товаров от дублей изделий и пересчитать суммыБекВысокаяПри импорте товаров блокировать заказ, если в нем есть дубли изделий; дубли не-изделий оставить допустимыми. После создания/обновления товаров пересчитать FinalPrice по затронутым заказам.
Исправить синхронизацию заказов на производство из Google-таблицыБекВысокаяРазвести конфликтующие POST /Order/Order/google, заполнить обязательные поля новых заказов на производство, обновлять статус и дату согласования чертежа так же, как PUT /Order/Order/google/{number}.
Защитить импорт счетов на оплату от порчи существующих связейБекВысокаяНе обновлять финансовые и связующие поля оплаченных/частично оплаченных/отмененных счетов без явного правила; при обновлении сверять заказ из файла с existsInvoice.PaymentSchedule.BuyerOrderId; блокировать дубли счетов в файле.
Определить правило для импортных счетов предоплатыБек/процессСредняяРешить, остаются ли счета из 1С всегда на Other или предоплатные счета нужно привязывать к Prepayment. Без этого оплата импортного счета Other не запустит автопереход задачи.
Обновлять видимые данные после импорта счетовФронтСредняяПосле успешного Импорт счетов для оплаты из 1С очищать/перезагружать не только BuyerOrders, но и открытые данные счетов/планов оплат, либо явно включить ручное обновление в чек-лист запуска.
Улучшить отображение частичного успеха импортаФронтСредняяЕсли в SynchronizeResponse.syncMessages есть warning/error, показывать общий статус Есть предупреждения/ошибки, чтобы success-toast не воспринимался как полный успех.
Согласовать права на платежи и перепривязку оплатФронт/бекСредняяСинхронизировать роли /invoice-payments, GET /Order/InvoicePayment/table, changeInvoicePayment и PATCH /Order/InvoicePayment/{id}. Особенно важно для ручного сценария Other -> Prepayment.

Минимальный ручной чек-лист перед импортом:

  1. Сделать backup базы и сохранить исходные файлы импорта.
  2. Проверить файлы на дубли заказов, дубль счетов и дубли изделий внутри одного заказа.
  3. Проверить, что у всех активных заказов распознан ответственный.
  4. Проверить строки с подписантом покупателя и договорными реквизитами.
  5. Проверить контрольную последнюю строку в каждом Excel-файле.
  6. Проверить, что товары импортируются до активной работы по задачам и до синхронизации заказов на производство.
  7. Проверить Google-таблицу заказов на производство на дубли номеров заказов и дубли номеров заказов покупателя по разным нашим организациям.
  8. Подготовить пользователя/токен ChiefSalesManager для Excel-импортов и внешней синхронизации заказов на производство.
  9. Если загружается банковская выписка, подготовить пользователя Accountant и заранее определить ответственного за разбор проблемных платежей.

Контроль после запуска:

  1. Сверить счетчики readed, added, updated и все syncMessages после каждого импорта.
  2. Проверить, что у каждого нового активного заказа есть один процесс BuyerOrder и одна задача BeginBuyerOrder с исполнителем.
  3. Сверить количество товаров в нескольких контрольных заказах, итоговые суммы и отсутствие дублей изделий.
  4. После синхронизации заказов на производство сверить связи с конкретными товарами, статус и дату согласования чертежа.
  5. После импорта счетов открыть карточки нескольких заказов из файла и сверить вкладки счетов и планов оплат.
  6. Проверить предоплатные счета: они не должны случайно остаться на Other, если по ним ожидается автоматический запуск процесса.
  7. Если загружалась банковская выписка, открыть платежи по выписке и проверить колонку Ошибка.
  8. Проверить, что повторный запуск того же файла не создал дубли и не ухудшил состояние данных.

Что можно отложить, если запуск остается разовым:

  • полноценный preview-режим импорта;
  • историю запусков с хранением исходных файлов в системе;
  • универсальный маппинг колонок;
  • глубокую оптимизацию производительности;
  • полный repair-механизм для старых заказов без процесса.

Формат найденной проблемы

Каждую найденную проблему фиксировать в одном формате:

Участок:
Тип:
Критичность:
Ожидание:
Фактическое поведение:
Где найдено:
Чем опасно:
Рекомендация:
Нужен тест:

Открытые вопросы

  • Должен ли импорт перетирать ручные изменения в заказе покупателя, товаре или счете?
  • Какие поля считаются источником истины из 1С, а какие ведутся только в системе?
  • Должен ли импорт быть полностью транзакционным: весь файл откатывается при ошибке одной строки?
  • Нужно ли хранить исходный файл после запуска? Для разового сценария может быть достаточно сохранить его вручную рядом с задачей/релизом.
  • Нужен ли preview-режим перед применением импорта? Для одного-двух запусков предпочтительнее ручная проверка файла до импорта и backup базы перед запуском.
  • Какие роли, кроме начальника менеджеров по продажам, должны иметь право на импорт?
  • Какой порядок запуска считать обязательным: заказы покупателя -> товары -> заказы на производство -> счета?
  • Должны ли заказы на производство, подтянутые из текущей ветки, заменять ручное создание заказов на производство в задаче запуска или только дополнять его?