gifts2017

Автоматическое разнесение платежей по заказам/счетам на примере УТ 10.3 (алгоритм)

Опубликовал Alexander Tsvetkov (ik-mercury) в раздел Программирование - Практика программирования

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

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

  • большое количество счетов/заказов 
  • большое количество входящих платежей (оптимистично, да). Это могут быть Платежки, ПКО и прочие приходные документы.

Необходимо автоматически сопоставить платежи с выставленными счетами и указать их в платежных поручениях входящих (или попытаться это сделать).

Начнем с состава метаданных. Для указания такого соответствия в входящих платежных документах существует отдельная табличная часть - РасшифровкаПлатежа, где в строках проставляется, к каким документам этот платеж относится, и делится сумма платежа на составляющие.

На форме таких документов - есть переключатель Без разбиения/Списком - который, по сути, только переключает внешнее представление этой табличной части. В случае выбора варианта Без разбиения - мы работаем только с первой строкой данной табличной части. В случае выбора второго варианта - имеем дело со всей таблицей.

При поступлении платежа по банку, нам доступны для анализа несколько реквизитов. Это - Контрагент, Договор контрагента, Сумма, Назначение платежа (текстовый комментарий при оформлении платежки). Будем их использовать!

Сразу отмечу - можно сделать автоматическое разнесение минимум двумя способами - обработка, которая будет анализировать все поступающие платежи за период, в дальнейшем можно это поместить в регламентное задание. Второй способ - влезем в модуль документов, процедуру ПриЗаписи - способ менее хорош, потому что задействуем изменение конфигурации.

В данной статье рассмотрим второй способ - он проще и нагляднее, как мне кажется, а привести его к первому варианту не составит большого труда.

Итак. Рассмотрим поступление Платежного поручения входящего (ППВ). Обычно их загружают из клиент-банка, реже вводят вручную. Все необходимые нам реквизиты (повторю - это Контрагент, Договор, Сумма, Назначение) вводятся в ППВ. Теперь нам необходимо проанализировать имеющуюся информацию и попытаться найти один или несколько необходимых счетов.

Анализировать предлагаю в процедуре модуля ПередЗаписью - вызывается перед записью и соответственно перед проведением документа и позволит нам заполнить табличную часть РасшифровкаПлатежа.

Для начала проанализируем, может, мы уже указали соответствующий заказ и ничего делать не требуется. Критериев может быть несколько - заполнены ли все строки в РасшифровкеПлатежа, заполнена ли первая строка в этой ТЧ. Как показала практика, достаточно анализа первой строки:

если не ЗначениеЗаполнено(РасшифровкаПлатежа[0].Сделка) тогда

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

	тзн = новый ТаблицаЗначений;
	тзн.Колонки.Добавить("Счет");
	тзн.Колонки.Добавить("Сумма");
	тзн.Колонки.Добавить("ДатаСчета");

Теперь разбираем Назначение платежа и пытаемся вытащить полезную для нас информацию, которая поможет найти необходимые счета или заказы. Проходим последовательно каждые 10 символов в Назначении и проверяем, не дата ли это. Если дата, то добавляем информацию в нашу новую таблицу значений. Прогоняем два раза - иногда бухгалтеры пишут год в полном формате - "2015", а иногда просто "15". Будем искать фрагменты вида ХХ.ХХ.ХХХХ и ХХ.ХХ.ХХ. В конце проверяем - корректная ли найденная дата. При желании можно самостоятельно оптимизировать код для одного прогона цикла.

		назн = НазначениеПлатежа;
		для к = 1 по стрдлина(назн) - 10 цикл
			ск = СтрЗаменить(сред(назн, к,10),"/",".");
			дт = сред(ск,7,4)+сред(ск,4,2)+лев(ск,2);
			если лев(дт,2) <> "20" тогда
				продолжить;
			конецесли;
			
			ндт = дата(2000,1,2);
			попытка
				ндт = дата(дт);
			исключение
			конецпопытки;
			
			если ндт <> дата(2000,1,2) и ндт <= дата+24*60*60 тогда
				новстр = тзн.Добавить();
				новстр.датасчета = ндт;
			конецесли;
		конеццикла;
		
		
		для к = 1 по стрдлина(назн) - 10 цикл
			ск = СтрЗаменить(сред(назн, к,8),"/",".");
			дт = "20"+сред(ск,7,2)+сред(ск,4,2)+лев(ск,2);
			
			ндт = дата(2000,1,2);
			попытка
				ндт = дата(дт);
			исключение
			конецпопытки;
			
			если ндт <> дата(2000,1,2) и ндт <= дата+24*60*60 тогда
				новстр = тзн.Добавить();
				новстр.датасчета = ндт;
			конецесли;
		конеццикла;

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

		нашли = ложь;
		для каждого стр из тзн цикл
			сч = Документы.СчетНаОплатуПокупателю.Выбрать(НачалоДня(стр.ДатаСчета), КонецДня(стр.ДатаСчета), новый структура("Контрагент", Контрагент));
			если сч.Следующий() тогда
				стр.счет = сч.ссылка;
				стр.сумма = сч.СуммаДокумента;
			конецесли;
			сч = Документы.ЗаказПокупателя.Выбрать(НачалоДня(стр.ДатаСчета), КонецДня(стр.ДатаСчета), новый структура("Контрагент", Контрагент));
			если сч.Следующий() тогда
				стр.счет = сч.ссылка;
				стр.сумма = сч.СуммаДокумента;
			конецесли;
		конеццикла;
		
		если СуммаДокумента = тзн.итог("Сумма") тогда
			расшифровкаплатежа.очистить();
			для каждого стр из тзн цикл
				новстр = РасшифровкаПлатежа.Добавить();
				новстр.ДоговорКонтрагента = ДоговорКонтрагента;
				новстр.КратностьВзаиморасчетов = 1;
				новстр.КурсВзаиморасчетов = 1;
				новстр.СуммаВзаиморасчетов = стр.сумма;
				новстр.СуммаПлатежа = стр.сумма;
				новстр.сделка = стр.счет;
			конеццикла;
		конецесли;

Таким образом, как показывает практика, мы сможем заполнить около 80% входящих платежек и как минимум освободим много времени у нашего бухгалтера. Договор при поиске мы не используем, в случае неправильного указания в клиент-банке подходящего договора, мы не сможем найти необходимые счета. Можно вывести предупреждение о разных договорах в найденных счетах и в самом платежном поручении.

Платежные поручения, разнесенные по Заказам, мы у себя в базе, например, выделяем цветом в общем журнале - чтобы можно было сразу видеть, где надо еще поработать руками:

 Список платежных поручений

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

Всем спасибо за внимание! Будут предложения по алгоритму - с удовольствием выслушаю :) 

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Анянов Михаил (insurgut) 24.12.15 11:47
Плохая затея за назначение платежа цепляться конечно. Не всегда оно заполняется. В разрезе контрагента/договора достаточно по фифо разносить оплаты - конечно же ведение взаиморасчетов по договору в целом должно быть. Для этого достаточно вызывать стандартный алгоритм разнесения платежа с указанной в платежке суммой и признаком не превышать его (алгоритм кнопки Заполнить при редактировании платежа списком).

P.S. Ведение взаиморасчетов по заказам - зло. В подавляющем большинстве случаев менеджеры даже не понимают для чего это надо.
2. Alexander Tsvetkov (ik-mercury) 24.12.15 12:08
(1) insurgut, зло, да. Поэтому мы, лично, ведем все взаиморасчеты по договору в целом. а такое разнесение используем в дальнейшем, чтоб клиенту оперативно напомнить что у него не оплачен такой то счет, на такие то товары/услуги, а не просто сказать сумму задолженности.
3. Александр (popenko) 24.12.15 17:46
а у нас за правильность взаиморасчетов отвечает бухгалтер- и ведет по счетам и автор молодец (без юмора). и потом если платеж клиент "потерял" очень легко находим
4. Вадим Никонов (V.Nikonov) 30.12.15 17:24
При ведении учета ПоЗаказам - легко анализируются ситуации с отсрочкой платежа (в ЗаказеПокупателя есть реквизит СрокОплаты). Для Договоров по Договору... можно использовать Дату документа долга и отсрочку в договоре.
На основе прогнозируемой ДатыОплаты можно строить Лист получения денег... Сортировать Заказы по очередности оплаты... и т.д. в т.ч. распределять не только по Заказам но и по Договорам.
Однако решение - распределять ли сумму по Заказам или НЕ распределять должен принимать человек индивидуально по каждому поступлению денег! Для Банка удобно подправить 1СКлиентБанк (сделать внешней обработкой).