Вернемся к нашим контрагентам. С ними мы будем вести разные торговые операции, и, соответственно, будем платить поставщикам за отгруженный товар, а от покупателей получать деньги за проданный. Для ввода данных по хозяйственным операциям в 1С служит такой объект метаданных как "Документ". Документами мы сможем вводить данные по приходу/перемещению/отгрузу товара, приходу/расходу денег, но хранить текущее состояние остатков на складе и состояние взаимозадолженности с контрагентами в документах нельзя. Можно эту информацию хранить в справочнике, если добавить соответствующие поля, но это крайне неэффективно и не удобно. Для такой цели в 1С есть специальный механизм. Этот механизм использует объект метаданных "Регистр" – в оперативном учете (для Бухгалтерии – "ПланСчетов", для Расчета – "Журнал расчетов"). Мы занимаемся изучением компоненты "Оперативный учет" и поэтому будем пользоваться именно "Регистрами".
Как устроен регистр. При его создании фирма 1С использовала некоторые положения технологии OLAP. Вот, к примеру, ссылка с неплохим объяснением, что это такое (http://www.permonline.ru/~enter/june/olap.htm). Там много текста, картинок и все вполне доходчиво. Есть и другие подобные материалы. Описание регистра 1С хорошо посмотреть в КиА том 1.
Регистры бывают двух типов. Регистр остатков и регистр оборотов. Их суть и различия можно проиллюстрировать следующим примером. Представим себе прямую направляющую по которой движется бегунок. На бегунок установлен спидометр с указателем пройденного пути. Мы измеряем расстояние от конца направляющей до бегунка. Бегунок идет вперед – это расстояние растет, идет назад – уменьшается. Так действует регистр остатков. Он показывает текущее состояние координаты бегунка по отношению к какому-то нулевому значению. Аналог – остатки на складе. Они растут, если был приход товара, и уменьшаются, если был расход. У нас есть еще спидометр со счетчиком пройденного пути. В какую бы сторону бегунок не двигался – цифра на счетчике растет. Так действует регистр оборотов. Аналог – величина товарооборота в магазине. Есть ли приход, или расход – товарооборот растет.
Сконструируем
сперва регистр взаиморасчетов. У него будет только два измерения:
"Контрагент" и "Договор" и один ресурс: "Сумма". Регистр у нас будет
типа регистр остатков. Если сумма будет меньше нуля – контрагент
должен нам, если больше – мы должны контрагенту. Реквизит заведем
один "ФлагДвижения" – типа число и будет принимать следующие значения
при изменении состояния регистра:
1 – изменение долга за поставленный нам товар;
2 – изменение долга за проданный нами товар;
3 – изменение долга оплатой за поставленный нам товар;
4 – изменение долга оплатой за проданный нами товар;
Идентификатор:
Взаиморасчеты |
|||
Измерения |
|||
Идентификатор |
Комментарий |
Тип значения |
Дополнительно |
Контрагент |
с кем мы ведем дела |
С.Контрагенты |
Д |
Договор |
по какому договору |
С.Договора |
Д, И |
Ресурсы |
|||
Идентификатор |
Комментарий |
Тип значения |
Дополнительно |
Сумма |
Сумма долга |
Число 15.2 |
|
Реквизиты |
|||
Идентификатор |
Комментарий |
Тип значения |
Дополнительно |
ФлагДвижения |
тип движения |
Число 1.0 |
+ |
Движения по
регистру будут следующие:
Приход – приход к нам товара (общей суммой) либо денег;
Расход – отгруз нами товара (общей суммой) либо выплата денег.
Переходим к конструированию регистра.
У нас есть контрагенты и договора с ними, у нас есть место (регистр), где мы можем хранить информацию по взаиморасчетам с ними. Теперь нам нужен документ, который позволит вводить эти взаиморасчеты. Первым нашим документом будет документ "Приход денег".
В любом документе в 1С есть два поля, присутствующих всегда. Это "ДатаДок" – дата документа и "НомерДок" – номер документа. 1С позволяет завести еще сколько надо полей, которые будут присутствовать во всех документах. Это "Общие реквизиты" документа. Заведем один такой общий реквизит – "Комментарий" текстового типа длиной не более 100 символов. Назначение его ясно из названия.
Перем СтКонтрагент;
// Это мы добавили переменную, область
действия которой
// весь модуль формы документа
//-----------------------------------------------
Процедура ПриОткрытии()
// Это предопределенная процедура, запускается
при возникновении
// события – открытие формы документа
// Она сформировалась автоматически, как мы указали в визарде создания
// документов
  ПриЗаписиПерепроводить(1);
// Это означает, что если мы проведенный
документ изменили, то при
// попытке его сохранения программа попытается его перепровести
  СтКонтрагент=Контрагент;
// Инициализируем переменную СтКонтрагент
значением реквизита Контрагент
КонецПроцедуры
//-----------------------------------------------
Процедура Контрагент()
  Если Контрагент<>СтКонтрагент Тогда
// В поле Контрагент содержимое изменилось
    Договор="";
// Очищаем поле Договор
    СтКонтрагент=Контрагент;
// Инициализируем переменную СтКонтрагент
новым значением
// реквизита Контрагент
  КонецЕсли;
КонецПроцедуры
Процедура ОбработкаПроведения()
// Предопределенная процедура, запускающая
механизмы регистрации движений
  Если Контрагент.Выбран()=0 Тогда
// Выбран() – метод, возвращающий состояние
поля ввода = 1, если поле
// заполнено и 0 если нет
    Предупреждение("Контрагент не
выбран");
// Вызовем на экран информационное окно
с сообщением
    НеПроводитьДокумент();
// Указываем, что документ заполнен
неправильно – он не должен быть проведен
  КонецЕсли;
  Если Договор.Выбран()=0 Тогда
    Предупреждение("Договор не выбран");
    НеПроводитьДокумент();
  КонецЕсли;
  Если Договор.ДатаДоговора>ДатаДок Тогда
// Договор еще не был заключен на дату
документа
    Предупреждение("Неверная дата
договора");
    НеПроводитьДокумент();
  КонецЕсли;
// Теперь будем заполнять поля регистра
"Взаиморасчеты"
  Регистр.Взаиморасчеты.Контрагент =
Контрагент;
  Регистр.Взаиморасчеты.Договор = Договор;
  Регистр.Взаиморасчеты.Сумма = Сумма;
// Движение – поступление денег за продаваемый
нами товар
// ФлагДвижения = 4
  Регистр.Взаиморасчеты.ФлагДвижения
= 4;
// Наш долг возрос, либо долг контрагента
уменьшился – на регистр
// пишем сумму приходом
  Регистр.Взаиморасчеты.ДвижениеПриходВыполнить();
КонецПроцедуры
Документ готов. Проверим его в работе.
Мы теперь, по данным нашей программы, должны фирме "Винни-Пух и все все все" – 1000 ед. денег. Это мы можем определить из нашего единственного документа, но когда таких документов будет много, и контрагентов в документах будет тоже много, мы запутаемся. Пусть лучше машина сама показывает нам кто, кому, по какому договору и сколько должен. Для таких целей существуют отчеты. Простейший отчет – "список номенклатуры" – мы уже создавали. Этот отчет у нас был включен в форму списка справочника. Теперь мы создадим отчет, имеющий свою отдельную форму.
Процедура Сформировать()
  Запрос=СоздатьОбъект("Запрос");
// Запрос – специальный объект в 1С,
служит для получения структурированной
// выборки данных
  ТЗ="
  |Период с ВыбДата по ВыбДата;
  |Контр = Регистр.Взаиморасчеты.Контрагент;
  |Дог = Регистр.Взаиморасчеты.Договор;
  |Сум = Регистр.Взаиморасчеты.Сумма;
  |Функция СумКонОст = КонОст(Сум);
  |Группировка Контр упорядочить по Контр.Код;
  |";
// Это текст запроса. Подробности
в "Описании языка" том 2
  Если Запрос.Выполнить(ТЗ)=0 Тогда
    Сообщить("Запрос не выполнен");
    Возврат;
  КонецЕсли;
// Если запрос будет не выполнен по
какой либо причине, метод Выполнить()
// вернет 0. Мы сообщим пользователю о произошедшей ошибке, и
// командой Возврат – прервем выполнение процедуры
  ИтогоМы=0;
  ИтогоНам=0;
// В этих двух переменных мы будем хранить
итоговую информацию по долгу
  Таб=СоздатьОбъект("Таблица");
  Таб.ИсходнаяТаблица("");
  Таб.ВывестиСекцию("Шапка");
  Пока Запрос.Группировка("Контр")=1 Цикл
// Получаем очередную запись из запроса
    ТЭ=Запрос.Контр;
// Во временную переменную передаем
значение выборки
    Долг=Запрос.СумКонОст;
// Определяем суммарный долг по текущему
значению выборки
// Дальше уже все знакомые нам методы
    Если ТЭ.ЭтоГруппа()=1 Тогда
      НазГр=СокрЛП(ТЭ.Наименование);
      Если  Долг=0 Тогда
      ИначеЕсли Долг>0 Тогда
        Мы=Долг;
        Нам=0;
      ИначеЕсли Долг<0 Тогда
        Мы=0;
        Нам=-Долг;
      КонецЕсли;
      Таб.ВывестиСекцию("Группа");
    Иначе
      Наз="("+СокрЛП(Строка(ТЭ.Код))+") "+СокрЛП(ТЭ.Наименование);
      Если  Долг=0 Тогда
        Продолжить;
      ИначеЕсли Долг>0 Тогда
        Мы=Долг;
        Нам=0;
        ИтогоМы=ИтогоМы+Мы;
      ИначеЕсли Долг<0 Тогда
        Мы=0;
        Нам=-Долг;
        ИтогоНам=ИтогоНам+Нам;
      КонецЕсли;
      Таб.ВывестиСекцию("Строка");
    КонецЕсли;
  КонецЦикла;
  Таб.ВывестиСекцию("Итого");
  Таб.ТолькоПросмотр(1);
  Таб.ПараметрыСтраницы(1,100,1);
  Таб.Показать("");
КонецПроцедуры
Документ "Выплата денег" будет практически аналогичен документу "Приход денег". Поэтому мы его создадим простым копированием. И потом внесем в него ряд небольших изменений.