При автоматизации загрузки данных из внешних источников, таких как Excel, разработчики часто сталкиваются с ситуацией, когда сумма в файле не соответствует сумме в конкретном документе 1С. Клиент может оплатить одним платежом несколько счетов или, наоборот, внести частичную оплату. Разберем, как правильно реализовать алгоритм «распила» суммы и какие технические нюансы следует учесть для стабильной работы интеграции.
Рассмотрим стандартную ситуацию: в Excel-файле зафиксирован факт оплаты от контрагента на сумму 300 рублей. В базе 1С у этого контрагента числятся две перевозки: одна на 100 рублей, другая на 200 рублей. Обычный поиск документа по условию СуммаКОплате = ЦенаИзExcel не сработает, так как ни один документ по отдельности не соответствует сумме 300. Проанализируем, как заставить систему автоматически находить неоплаченные документы и последовательно закрывать их.
Самый эффективный способ решить задачу — применить метод FIFO. Это означает, что поступившие деньги должны в первую очередь закрывать самую старую задолженность. Рассмотрим этот процесс по шагам.
Шаг 1. Получение списка долгов. Прежде всего, нам необходимо выбрать из системы все документы «Перевозка», по которым есть остаток задолженности. Для этого лучше всего использовать запрос к регистру накопления или непосредственно к табличной части документов, если учет ведется упрощенно. Обязательно устанавливаем сортировку по дате документа (по возрастанию).
Шаг 2. Распределение суммы. Получив сумму из Excel (например, СуммаИзФайла), мы начинаем обходить наш список неоплаченных документов в цикле. На каждой итерации мы сравниваем остаток суммы из файла с долгом по текущему документу.
Посмотрим на пример программной логики:
// Предположим, СуммаИзФайла получена из Excel и равна 300
// ЗадолженностьПоДокументам - это таблица значений с колонками Документ, ОстатокДолга, СуммаОплаты
ОстатокПлатежа = СуммаИзФайла;
Для Каждого СтрокаДолга Из ЗадолженностьПоДокументам Цикл
Если ОстатокПлатежа <= 0 Тогда
Прервать; // Деньги закончились
КонецЕсли;
НужноПогасить = СтрокаДолга.ОстатокДолга;
Если ОстатокПлатежа >= НужноПогасить Тогда
// Платеж полностью закрывает этот документ
ЗаписатьОплатуВДокумент(СтрокаДолга.Документ, НужноПогасить);
ОстатокПлатежа = ОстатокПлатежа - НужноПогасить;
Иначе
// Платежа хватает только на частичную оплату
ЗаписатьОплатуВДокумент(СтрокаДолга.Документ, ОстатокПлатежа);
ОстатокПлатежа = 0;
КонецЕсли;
КонецЦикла;
Если ОстатокПлатежа > 0 Тогда
// Если после обхода всех документов остались деньги - это аванс
ЗафиксироватьАванс(Контрагент, ОстатокПлатежа);
КонецЕсли;
Проанализируем техническую сторону вопроса. Часто для чтения Excel используют COM-объекты (Excel.Application), но это «медленный и тупой» способ, как справедливо отмечено в обсуждении. Он требует установленного Microsoft Office на сервере и часто зависает.
Рекомендуем использовать метод Прочитать() объекта ТабличныйДокумент. Это встроенный механизм 1С, который работает значительно быстрее и стабильнее:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
Сообщить("Ошибка чтения файла: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Далее обходим строки ТабличногоДокумента
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
ИмяКонтрагента = ТабДок.Область(НомерСтроки, 1).Текст;
СуммаОплаты = ТабДок.Область(НомерСтроки, 2).Значение;
// Вызываем процедуру распределения
РаспределитьОплатуПоКонтрагенту(ИмяКонтрагента, СуммаОплаты);
КонецЦикла;
Как было замечено в обсуждении, математика не всегда может «разрулить» волю клиента. Бывают случаи, когда клиент принципиально не платит по первому счету из-за претензий, но полностью оплачивает второй. Метод FIFO в этом случае сработает некорректно с точки зрения управленческого учета.
Чтобы избежать ошибок, разберем дополнительные меры контроля:
ПоступлениеНаРасчетныйСчет или ПриходныйКассовыйОрдер, который будет делать движения по регистру накопления «Взаиморасчеты». Тогда система сама будет понимать, какой документ является «основанием» для платежа.Выясним, что делать, если клиент заказал на 100, оплатил 50, а потом еще раз заказал на 100 и оплатил 150. При использовании алгоритма FIFO система должна работать так:
Важно: если в вашей конфигурации (например, «Транспорт») задолженность хранится просто в реквизитах документа, не забывайте проверять актуальное состояние СуммаОплаты перед выполнением расчетов, чтобы не «затереть» уже внесенные ранее данные.
Таким образом, комбинируя надежный способ чтения файлов и алгоритм последовательного распределения задолженности, мы превращаем «астрономическую проблему» в стандартную задачу автоматизации, которая исключает ручной ввод и ошибки распределения средств.