При разработке расширений для типовых конфигураций «1С:Предприятие 8.3» (таких как «1С:Розница», «1С:Управление торговлей» или «1С:Комплексная автоматизация») программисты часто сталкиваются с загадочным поведением системы: записи в новом регистре накопления, привязанные к документу ЧекККМ, успешно создаются в течение дня, но бесследно исчезают после закрытия кассовой смены или перезапуска программы. Выясним причину этого поведения и подробно разберем, как правильно спроектировать архитектуру решения, чтобы избежать потери данных.
Для начала проанализируем стандартную логику работы розничных конфигураций 1С. Документ ЧекККМ (Чек ККМ) предназначен для оперативного учета продаж в течение одной кассовой смены. При этом в системе заложен жесткий регламент работы с этими документами:
Техническая суть проблемы: Как только документ ЧекККМ распроводится или архивируется программно, платформа 1С автоматически инициирует очистку всех наборов записей регистров, у которых данный документ указан в качестве регистратора в метаданных. Платформа делает это принудительно, и тот факт, что ваш регистр накопления Расш1_Взаиморасчеты был добавлен через расширение, никак не защищает его движения от автоматического удаления.
Рассмотрим, какими путями можно решить эту проблему, сохранив целостность данных и не нарушив типовую методологию «1С:Предприятия».
Этот вариант является наиболее правильным с точки зрения архитектуры типовых решений. Если система заменяет множество детальных чеков одним сводным отчетом, то и движения по вашему регистру взаиморасчетов должны переноситься в этот отчет.
Разберем по шагам, как это реализовать:
Расш1_Взаиморасчеты в расширении и в список разрешенных регистраторов добавьте, помимо документа ЧекККМ, документ ОтчетОРозничныхПродажах.ЧекККМ. Это позволяет оперативно видеть долги покупателей в режиме реального времени.ОтчетОРозничныхПродажах с помощью механизма расширений (аннотация &После или &Вместо для процедуры ОбработкаПроведения в модуле документа).Посмотрим на пример кода, который собирает информацию по долгам из чеков смены и записывает их в движения «Отчета о розничных продажах»:
&После("ОбработкаПроведения")
Процедура Расш1_ОбработкаПроведения(Отказ, РежимПроведения)
// Запрос для получения данных о долгах из чеков текущей смены
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Чек.Продавец КАК Продавец,
| Чек.Контрагент КАК Контрагент,
| СУММА(Чек.СуммаДолга) КАК СуммаДолга
|ИЗ
| Документ.ЧекККМ КАК Чек
|ГДЕ
| Чек.КассоваяСмена = &КассоваяСмена
| И Чек.Проведен = ИСТИНА
|ГРУППИРОВАТЬ ПО
| Чек.Продавец,
| Чек.Контрагент";
Запрос.УстановитьПараметр("КассоваяСмена", ЭтотОбъект.КассоваяСмена);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
// Получаем набор записей нашего регистра для ОРП
НаборЗаписей = Движения.Расш1_Взаиморасчеты;
Пока Выборка.Следующий() Цикл
Запись = НаборЗаписей.ДобавитьПриход();
Запись.Период = ЭтотОбъект.Дата;
Запись.Продавец = Выборка.Продавец;
Запись.Контрагент = Выборка.Контрагент;
Запись.СуммаДолга = Выборка.СуммаДолга;
КонецЦикла;
// Запись набора произойдет автоматически при завершении проведения транзакции
НаборЗаписей.Записывать = Истина;
КонецЕсли;
КонецПроцедуры
Преимущества: Полное соответствие методологии 1С, отсутствие дублирования данных, корректный расчет остатков на конец смены.
Если вам не требуется стандартный функционал регистра накопления (например, автоматический расчет остатков на уровне СУБД, получение итогов на каждую секунду времени) и вам нужна лишь история долговых обязательств в привязке к чеку, оптимальным решением станет переход на независимый регистр сведений.
Выясним причину, почему это решает проблему удаления:
У независимого регистра сведений в метаданных отсутствует жесткая связь «Регистратор — Движения». Платформа не отслеживает состояние документов, указанных в измерениях такого регистра, и никогда не очищает его данные автоматически при распроведении документов.
Рассмотрим порядок действий для перехода на этот вариант:
Расш1_ИсторияВзаиморасчетовЧеков).ДокументСсылка с типом ДокументСсылка.ЧекККМ.Контрагент, Продавец) и ресурс СуммаДолга.
Процедура Расш1_ЗаписатьВзаиморасчетыВРегистрСведений(ОбъектЧекККМ, СуммаДолга, ОбъектРМК) Экспорт
НаборЗаписей = РегистрыСведений.Расш1_ИсторияВзаиморасчетовЧеков.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ДокументСсылка.Установить(ОбъектЧекККМ.Ссылка);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.ДокументСсылка = ОбъектЧекККМ.Ссылка;
НоваяЗапись.Продавец = ОбъектРМК.Продавец;
НоваяЗапись.Контрагент = ОбъектЧекККМ.Контрагент;
НоваяЗапись.СуммаДолга = СуммаДолга;
Попытка
НаборЗаписей.Записать(Истина);
Исключение
ЗаписьЖурналаРегистрации("Расширение.Взаиморасчеты",
УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
При закрытии смены статус документа ЧекККМ изменится на «Архивный», но запись в регистре сведений останется нетронутой, так как платформа не связывает этот регистр с механизмом проведения документов.
Если вам критически важно использовать именно регистр накопления (например, для построения сложных отчетов по остаткам), но переписывать механизмы заполнения «Отчета о розничных продажах» не представляется возможным, можно применить схему со сторонним регистратором.
Проанализируем эту схему:
Расш1_ОперацияВзаиморасчетов).Расш1_Взаиморасчеты.ЧекККМ программно создавайте и проводите документ Расш1_ОперацияВзаиморасчетов. В реквизитах этого документа-операции сохраняйте ссылку на исходный чек для аналитики.Поскольку при закрытии смены архивируются и распроводятся только чеки ККМ, ваши созданные технические документы Расш1_ОперацияВзаиморасчетов останутся проведенными, и движения по регистру накопления не пострадают.
Обратим внимание на то, как автор вопроса записывает данные в регистр накопления. Делать это напрямую через создание набора записей в обход стандартного механизма проведения (транзакции проведения документа) крайне не рекомендуется:
// Пример некорректной записи в обход транзакции проведения:
НаборЗаписей = РегистрыНакопления.Расш1_Взаиморасчеты.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ОбъектЧекККМ.Ссылка);
// Заполнение записи...
НаборЗаписей.Записать();
Почему так делать нельзя: Запись движений напрямую в обход процедуры проведения приводит к нарушению логики транзакций базы данных. Если проведение документа в дальнейшем по какой-то причине прервется или отменится, ваши записи в регистре накопления останутся "висеть" в базе данных, превращаясь в "мусорные" записи без проведенного документа-основания.
Правильный подход заключается в заполнении коллекции Движения непосредственно внутри обработчиков событий проведения документа, предоставляемых платформой 1С.