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

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

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

Архитектурный выбор: Направление связи

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

Проанализируем ситуацию. Если мы решим добавить реквизит в уже существующий Счет, нам придется столкнуться с несколькими проблемами:

  1. Реструктуризация таблиц: При добавлении нового реквизита в документ, по которому уже создано 50 000 записей, 1С 7.7 потребуется перестроить таблицу 1C_JOURNAL (общий журнал) или специфические таблицы документа. В формате DBF это может занять длительное время и потребовать монопольного доступа к базе.
  2. Пустые значения: Для всех старых 50 000 документов этот реквизит будет пустым, что не несет полезной нагрузки, но увеличивает размер базы.
  3. Масштабируемость: Если в будущем на один Счет потребуется оформить две Доставки, структура с реквизитом в Счете окажется нерабочей.

Поэтому наиболее правильным и принятым в стандартах 1С подходом является создание связи "Снизу вверх". Мы создаем новый документ Доставка и в нем заводим реквизит ДокументОснование (или Счет) с типом Документ.Счет. Это позволяет нам не трогать структуру старых данных и легко расширять функционал.

Реализация механизма Ввод на основании

Для удобства пользователя логично реализовать создание Доставки непосредственно из формы Счета. Рассмотрим, как это сделать правильно. В конфигураторе для документа Доставка необходимо на закладке "Ввод на основании" выбрать документ Счет.

Затем в модуле формы документа Доставка проанализируем процедуру ВводНаОсновании(). Это позволит автоматически заполнять реквизиты (Заказчик, Сумма, Адрес) из данных счета:


Процедура ВводНаОсновании(ДокОсн)
    Если ТипЗначенияСтр(ДокОсн) = "Документ" Тогда
        Если ДокОсн.Вид() = "Счет" Тогда
            // Заполняем реквизиты из Счета
            Счет = ДокОсн;
            ЗаказчикДоставки = ДокОсн.Контрагент;
            СтоимостьДоставки = ДокОсн.Итог("Сумма") * 0.1; // Пример логики
            Комментарий = "Создано на основании счета №" + ДокОсн.НомерДок;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Контроль уникальности: Один счет — одна доставка

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

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


Функция ПроверитьНаличиеДоставки(ТекущийСчет)
    Перем ДокД, КолВо;
    КолВо = 0;
    ДокД = СоздатьОбъект("Документ.Доставка");
    
    // Ищем все документы, где текущий счет является основанием
    ДокД.ВыбратьПодчиненныеДокументы(,, ТекущийСчет);
    Пока ДокД.ПолучитьДокумент() = 1 Цикл
        Если ДокД.ПометкаУдаления() = 0 Тогда
            КолВо = КолВо + 1;
        КонецЕсли;
    КонецЦикла;
    
    Возврат КолВо;
КонецФункции

// В процедуре ПриОткрытии()
Если Выбран() = 0 Тогда // Если документ новый
    Если ПустоеЗначение(Счет) = 0 Тогда
        Если ПроверитьНаличиеДоставки(Счет) > 0 Тогда
            Предупреждение("По этому счету уже оформлена доставка!");
            СтатусВозврата(0);
            Возврат;
        КонецЕсли;
    КонецЕсли;
КонецЕсли;

Оптимизация производительности: Индексы

Выясним причину, почему при росте базы поиск подчиненных документов может замедляться. В 1С 7.7 для быстрой работы метода ВыбратьПодчиненныеДокументы и критериев отбора крайне важно, чтобы реквизит, по которому строится связь (в нашем случае реквизит Счет в документе Доставка), имел установленный флаг "Сортировка" в Конфигураторе.

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

Бухгалтерский учет и проведение

Почему для реализации доставки мы выбираем именно объект Документ, а не Справочник? Как было отмечено в обсуждении, доставка зачастую должна влиять на финансовый результат или взаиморасчеты. В 1С 7.7 только Документ обладает модулем проведения, который может порождать проводки или движения по регистрам.

Если стоимость доставки должна увеличивать задолженность клиента, в модуле проведения документа Доставка мы опишем логику:


Процедура ОбработкаПроведения()
    // Пример для Бухгалтерии 7.7
    Операция.НоваяПроводка();
    Операция.Дебет.Счет = СчетПоКоду("62.1");
    Операция.Дебет.Контрагенты = ЗаказчикДоставки;
    Операция.Кредит.Счет = СчетПоКоду("90.1");
    Операция.Сумма = СтоимостьДоставки;
    Операция.Содержание = "Услуги по доставке согласно счету " + Счет.НомерДок;
    Операция.Записать();
КонецПроцедуры

Визуализация связи для пользователя

Чтобы пользователь, находясь в форме Счета, мог быстро увидеть, есть ли по нему доставка, рекомендуется использовать стандартный механизм "Критерии отбора". Мы можем создать критерий СвязанныеДокументы, включив в него реквизит Счет документа Доставка.

Это позволит пользователю нажать кнопку "Дерево подчиненности" на панели инструментов и увидеть всю цепочку документов. Это гораздо правильнее и стандартнее, чем рисовать отдельные кнопки поиска на форме счета.

Подводя итог, проанализируем преимущества выбранного подхода:

← На главную