Почему при проведении кассового чека ККМ в 1С 7.7 возникает задолженность у покупателя и как это исправить?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При адаптации или переделке механизмов розничной торговли на платформе 1С:Предприятие 7.7 (чаще всего на базе типовой конфигурации «Торговля и Склад») разработчики часто сталкиваются с неприятной проблемой. При проведении розничного документа (например, Кассовый чек или Чек ККМ) деньги корректно поступают в кассу, но на покупателя (например, на предопределенного контрагента «Частный клиент») одновременно вешается дебиторская задолженность. В итоге в отчетах по взаиморасчетам зависают долги, которых в рознице быть не должно.

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

---

Выясняем причину: почему «Частный клиент» становится должником?

Для того чтобы понять суть проблемы, нам необходимо заглянуть в модуль проведения документа. Проанализируем процедуру ОбработкаПроведения(), которую предоставил автор темы. В самом конце процедуры мы видим вызов стандартной глобальной функции:

ДвиженияРегистровНакладных(Контекст);

Эта функция определена в Глобальном модуле конфигурации «Торговля и Склад». Ее основная задача — автоматизировать проведение оптовых документов отгрузки (таких как Реализация товаров или Расходная накладная). Данная процедура выполняет следующие действия:

  1. Списывает себестоимость и количество товаров со складов (по партиям).
  2. Формирует записи в регистр оборотов Продажи.
  3. Формирует движение «Приход» по регистру взаиморасчетов (обычно это регистр Покупатели или Взаиморасчеты), тем самым увеличивая долг контрагента, указанного в реквизите Клиент (или Контрагент).

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

Кроме того, в коде автора наблюдается явное дублирование: списание остатков товаров со склада производится вручную в теле `ОбработкаПроведения()`, а затем повторно инициируется через ДвиженияРегистровНакладных. Это грубая ошибка, приводящая к двойному списанию остатков и искажению себестоимости.

---

Вариант решения №1. Полный отказ от использования взаиморасчетов для ККМ (Рекомендуемый розничный метод)

Самый логичный и чистый подход для розничных продаж — вообще исключить данный документ из контура взаиморасчетов с контрагентами. Розничные чеки не должны делать никаких движений по регистру Покупатели.

Для реализации этого варианта разберем по шагам, как изменить код:

  1. Полностью откажитесь от вызова глобальной процедуры ДвиженияРегистровНакладных(Контекст) в модуле документа КассовыйЧек.
  2. Убедитесь, что в процедуре ОбработкаПроведения() корректно прописано ручное списание товаров со складов и фиксация выручки.

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


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

КонецПроцедуры

---

Вариант решения №2. Автоматическое гашение долга в момент проведения чека

Если специфика вашей конфигурации требует обязательного вызова ДвиженияРегистровНакладных(Контекст) (например, на эту процедуру завязаны сложные механизмы расчета НДС, автоматического подбора партий товаров, распределения скидок или расчета бонусов), то вам придется смириться с тем, что долг покупателя сначала увеличивается.

Однако мы можем сразу же «погасить» этот долг в рамках той же транзакции проведения документа. Для этого сразу после вызова глобальной процедуры необходимо сделать компенсирующее движение по регистру взаиморасчетов.

Разберем по шагам, как добавить автоматическое закрытие долга:

  1. Найдите вызов ДвиженияРегистровНакладных(Контекст); в самом конце процедуры проведения.
  2. Добавьте код списания задолженности по регистру Покупатели (или вашему аналогичному регистру взаиморасчетов):

// Сначала выполняем стандартные оптовые движения (они создадут долг покупателя)
ДвиженияРегистровНакладных(Контекст);

// Теперь принудительно закрываем этот долг, так как оплата получена сразу
Регистр.Покупатели.Покупатель   = Клиент;
Регистр.Покупатели.Договор     = Договор; // Если используется аналитика по договорам
Регистр.Покупатели.КредДокумент = ТекущийДокумент();
Регистр.Покупатели.СуммаРуб     = Итог("Сумма");
Регистр.Покупатели.СуммаВал     = Итог("Сумма"); // Если учет ведется в валюте

// Выполняем движение Расход (уменьшение задолженности контрагента перед нами)
Регистр.Покупатели.ДвижениеРасходВыполнить();

При таком подходе отчет по взаиморасчетам зафиксирует отгрузку товара на 300 рублей и тут же отразит оплату на 300 рублей. Итоговое сальдо по этой сделке закроется в ноль, и «Частный клиент» больше не будет висеть в списке должников.

---

Вариант решения №3. Корректировка алгоритмов Глобального модуля

Если вы хотите решить проблему глобально для всех подобных документов розницы, правильнее всего будет внести изменения непосредственно в процедуру ДвиженияРегистровНакладных в Глобальном модуле вашей конфигурации.

Рассмотрим подробнее этот способ:

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

Если КонтекстВызова.Вид() = "КассовыйЧек" Тогда
    // Для розничного чека движения по взаиморасчетам не делаем
Иначе
    // Здесь оставляем стандартный код формирования движений по регистру Покупатели
    Регистр.Покупатели.Покупатель = КонтекстВызова.Клиент;
    // ... стандартный код ...
    Регистр.Покупатели.ДвижениеПриходВыполнить();
КонецЕсли;

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

---

Важный совет по учету оплат банковскими картами (Эквайринг)

Проанализируем архитектурное решение автора темы по учету безналичных оплат. Автор добавил в стандартный регистр Касса новое измерение Счет и ресурс Банк:


Если ВариантОплаты = Перечисление.ТипыОплатЧекаККМ.ПлатежнаяКарта Тогда
    Регистр.Касса.Счет     = Константа.БанковскийСчетБанкаЭквайера.Получить(ДатаДок);
    Регистр.Касса.Банк     = Итог("Сумма");
Иначе
    Регистр.Касса.Наличность    = Итог("Сумма");
КонецЕсли;

Будьте предельно осторожны с такими доработками! Регистр Касса в типовой «Торговле и Складе 7.7» предназначен исключительно для оперативного учета наличных денежных средств в кассах вашей компании. Добавление безналичных ресурсов в этот регистр неминуемо приведет к следующим проблемам:

Рекомендуемая альтернатива: для фиксации оплат по банковским картам используйте отдельный оборотный регистр (например, создайте новый регистр ОплатыПоКартам) либо задействуйте стандартный для торговых конфигураций механизм эквайринга, где долг закрывается через промежуточный счет «Переводы в пути».

← На главную