При адаптации или переделке механизмов розничной торговли на платформе 1С:Предприятие 7.7 (чаще всего на базе типовой конфигурации «Торговля и Склад») разработчики часто сталкиваются с неприятной проблемой. При проведении розничного документа (например, Кассовый чек или Чек ККМ) деньги корректно поступают в кассу, но на покупателя (например, на предопределенного контрагента «Частный клиент») одновременно вешается дебиторская задолженность. В итоге в отчетах по взаиморасчетам зависают долги, которых в рознице быть не должно.
В этой статье мы подробно разберем, почему возникает такая ситуация, проанализируем исходный код проведения документа и рассмотрим несколько вариантов решения проблемы в зависимости от архитектуры вашей базы данных.
---
Для того чтобы понять суть проблемы, нам необходимо заглянуть в модуль проведения документа. Проанализируем процедуру ОбработкаПроведения(), которую предоставил автор темы. В самом конце процедуры мы видим вызов стандартной глобальной функции:
ДвиженияРегистровНакладных(Контекст);
Эта функция определена в Глобальном модуле конфигурации «Торговля и Склад». Ее основная задача — автоматизировать проведение оптовых документов отгрузки (таких как Реализация товаров или Расходная накладная). Данная процедура выполняет следующие действия:
Продажи.Покупатели или Взаиморасчеты), тем самым увеличивая долг контрагента, указанного в реквизите Клиент (или Контрагент).Поскольку розничный покупатель платит за товар непосредственно в момент покупки (деньги сразу попадают в кассу или на терминал эквайринга), задолженности у него возникать не должно. Но система воспринимает этот документ как стандартную оптовую отгрузку в кредит из-за вызова ДвиженияРегистровНакладных(). При этом ваши кастомные движения по регистру Касса фиксируют только приход денег в сейф ККМ, но никак не связываются с закрытием долга конкретного контрагента по регистру взаиморасчетов.
Кроме того, в коде автора наблюдается явное дублирование: списание остатков товаров со склада производится вручную в теле `ОбработкаПроведения()`, а затем повторно инициируется через ДвиженияРегистровНакладных. Это грубая ошибка, приводящая к двойному списанию остатков и искажению себестоимости.
---
Самый логичный и чистый подход для розничных продаж — вообще исключить данный документ из контура взаиморасчетов с контрагентами. Розничные чеки не должны делать никаких движений по регистру Покупатели.
Для реализации этого варианта разберем по шагам, как изменить код:
ДвиженияРегистровНакладных(Контекст) в модуле документа КассовыйЧек.ОбработкаПроведения() корректно прописано ручное списание товаров со складов и фиксация выручки.Пример правильной структуры проведения розничного чека без привлечения оптовых механизмов взаиморасчетов:
Процедура ОбработкаПроведения()
Если Склад.Выбран() = 0 Тогда
НеПроводить(ТекущийДокумент(), "Не указан склад!");
Возврат;
КонецЕсли;
// Проводим списание товаров по строкам документа
ВыбратьСтроки();
Пока ПолучитьСтроку() > 0 Цикл
Если Товар.Выбран() = 0 Тогда
Продолжить;
КонецЕсли;
// Списание остатков товаров
Регистр.ОстаткиТоваров.Склад = Склад;
Регистр.ОстаткиТоваров.Товар = Товар;
Регистр.ОстаткиТоваров.ОстатокТовара = Количество * Коэффициент;
// Здесь также рассчитывается и списывается себестоимость (БазоваяСтоимость)
// ...
Регистр.ОстаткиТоваров.ДвижениеРасходВыполнить();
// Фиксируем продажи (для отчетов по выручке и прибыли)
Регистр.Продажи.Покупатель = Клиент;
Регистр.Продажи.Товар = Товар;
Регистр.Продажи.Количество = Количество * Коэффициент;
Регистр.Продажи.ПродСтоимость = Сумма;
Регистр.Продажи.ДвижениеВыполнить();
КонецЦикла;
// Оприходование денег в кассу (или банк)
Если ВариантОплаты = Перечисление.ТипыОплатЧекаККМ.ПлатежнаяКарта Тогда
Регистр.Касса.Счет = Константа.БанковскийСчетБанкаЭквайера.Получить(ДатаДок);
Регистр.Касса.Банк = Итог("Сумма");
Иначе
Регистр.Касса.Наличность = Итог("Сумма");
КонецЕсли;
Регистр.Касса.Валюта = Валюта;
Регистр.Касса.ПривязыватьСтроку(1);
Если ВидОперации = Перечисление.ВидыОперацийЧекККМ.Чек Тогда
Регистр.Касса.ДвижениеПриходВыполнить();
Иначе // Чек на возврат
Регистр.Касса.ДвижениеРасходВыполнить();
КонецЕсли;
КонецПроцедуры
---
Если специфика вашей конфигурации требует обязательного вызова ДвиженияРегистровНакладных(Контекст) (например, на эту процедуру завязаны сложные механизмы расчета НДС, автоматического подбора партий товаров, распределения скидок или расчета бонусов), то вам придется смириться с тем, что долг покупателя сначала увеличивается.
Однако мы можем сразу же «погасить» этот долг в рамках той же транзакции проведения документа. Для этого сразу после вызова глобальной процедуры необходимо сделать компенсирующее движение по регистру взаиморасчетов.
Разберем по шагам, как добавить автоматическое закрытие долга:
ДвиженияРегистровНакладных(Контекст); в самом конце процедуры проведения.Покупатели (или вашему аналогичному регистру взаиморасчетов):
// Сначала выполняем стандартные оптовые движения (они создадут долг покупателя)
ДвиженияРегистровНакладных(Контекст);
// Теперь принудительно закрываем этот долг, так как оплата получена сразу
Регистр.Покупатели.Покупатель = Клиент;
Регистр.Покупатели.Договор = Договор; // Если используется аналитика по договорам
Регистр.Покупатели.КредДокумент = ТекущийДокумент();
Регистр.Покупатели.СуммаРуб = Итог("Сумма");
Регистр.Покупатели.СуммаВал = Итог("Сумма"); // Если учет ведется в валюте
// Выполняем движение Расход (уменьшение задолженности контрагента перед нами)
Регистр.Покупатели.ДвижениеРасходВыполнить();
При таком подходе отчет по взаиморасчетам зафиксирует отгрузку товара на 300 рублей и тут же отразит оплату на 300 рублей. Итоговое сальдо по этой сделке закроется в ноль, и «Частный клиент» больше не будет висеть в списке должников.
---
Если вы хотите решить проблему глобально для всех подобных документов розницы, правильнее всего будет внести изменения непосредственно в процедуру ДвиженияРегистровНакладных в Глобальном модуле вашей конфигурации.
Рассмотрим подробнее этот способ:
Процедура ДвиженияРегистровНакладных(КонтекстВызова).Покупатели или Взаиморасчеты).
Если КонтекстВызова.Вид() = "КассовыйЧек" Тогда
// Для розничного чека движения по взаиморасчетам не делаем
Иначе
// Здесь оставляем стандартный код формирования движений по регистру Покупатели
Регистр.Покупатели.Покупатель = КонтекстВызова.Клиент;
// ... стандартный код ...
Регистр.Покупатели.ДвижениеПриходВыполнить();
КонецЕсли;
Этот способ наиболее изящный, так как он не перегружает модуль проведения самого документа лишними компенсирующими транзакциями и сохраняет целостность архитектуры типового решения.
---
Проанализируем архитектурное решение автора темы по учету безналичных оплат. Автор добавил в стандартный регистр Касса новое измерение Счет и ресурс Банк:
Если ВариантОплаты = Перечисление.ТипыОплатЧекаККМ.ПлатежнаяКарта Тогда
Регистр.Касса.Счет = Константа.БанковскийСчетБанкаЭквайера.Получить(ДатаДок);
Регистр.Касса.Банк = Итог("Сумма");
Иначе
Регистр.Касса.Наличность = Итог("Сумма");
КонецЕсли;
Будьте предельно осторожны с такими доработками! Регистр Касса в типовой «Торговле и Складе 7.7» предназначен исключительно для оперативного учета наличных денежных средств в кассах вашей компании. Добавление безналичных ресурсов в этот регистр неминуемо приведет к следующим проблемам:
Рекомендуемая альтернатива: для фиксации оплат по банковским картам используйте отдельный оборотный регистр (например, создайте новый регистр ОплатыПоКартам) либо задействуйте стандартный для торговых конфигураций механизм эквайринга, где долг закрывается через промежуточный счет «Переводы в пути».