Объекты и контексты

При работе в программе мы сталкиваемся с такими понятиями как организация, документ, товар, основное средство и т.д. Каждое из таких понятий характеризуется определенным набором данных и свойств. Например, у документа есть дата, номер и сумма. Такой набор данных, связанных одним понятием, мы будем называть объектом. В большинстве своем все наши операции и выражения будут обрабатывать либо данные объектов, либо сами объекты.

Приведем пример простейшей операции выдачи денег в подотчет:

Проводка(Д71, Лицо1, Сумма, К50_1);

Под переменной Сумма в данном случае мы подразумеваем сумму документа, для которого выполняется проводка. Иными словами можно сказать, что Сумма - это поле данных или переменная объекта Документ. Очевидно, что у каждого документа есть еще много других полей (переменных). В этот набор входят, по меньшей мере, все те данные, которые мы заполняли, создавая или редактируя документ.

Как обращаться к переменным объекта? Для этого используется следующая форма записи:

Документ.Сумма

Здесь Документ - это имя объекта, Сумма - имя переменной объекта, "." (точка) между ними - символ уточнения - указывает на обращение к переменной объекта. Наш пример с функцией Проводка можно записать в следующем виде:

Проводка(Д71, Документ.Лицо1, Документ.Сумма, К50_1);

И эта, и ранее приведенная запись являются правильными. Заметим, что в первом случае  можно не уточнять, что Сумма относится к документу, и использовать, таким образом, короткую форму записи. Функция Проводка выполняется в операции, закрепленной за документом, и когда мы обращаемся к переменной Сумма, то достаточно очевидно, что мы обращаемся именно к сумме документа (к чему же еще). В данном случае, мы можем говорить о том, что объект Документ является контекстным или умалчиваемым (принимаемый по умолчанию), а обращение к любой переменной подразумевает обращение к переменной этого объекта.

В ходе выполнения операции возможны случаи, когда вместо документа будет установлен другой контекстный объект. Например, при переборе строк накладной текущим контекстом будет объект типа строка документа - мы называем его Наим (от слова наименование). Кроме того, есть специальная функция - Установить - позволяющая Вам самостоятельно установить объект, который будет считаться текущим контекстом.

Вернемся к нашему примеру. Указывая аналитический признак по дебету 71-го счета, мы написали - Лицо1. Что такое Лицо1? С точки зрения оформления документа - это сотрудник, которому выдаются деньги. С точки же зрения правила операции это объект, точнее даже объект аналитического учета. Помня о том, что в документе у нас могут быть два лица - Лицо1 и Лицо2 - можно сказать, что в объекте типа Документ имеются два других объекта Лицо1 и Лицо2, т.е. имеются два подобъекта.

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

При занесении данных в справочник сотрудников будем указывать в поле данных ‘Субсчет’ тот субсчет 71-го счета, к которому относится данный сотрудник. Тем самым мы фактически определим переменную Субсчет в объекте Лицо1, и в дальнейшем сможем использовать ее при составлении правила операции.

Проводка(Лицо1.Субсчет, Лицо1, Сумма, К50);

Запись ‘Лицо1.Субсчет’ означает, что мы обращаемся к полю Субсчет объекта Лицо1. Уточнение в данном случае является обязательным, так как объект Лицо1 в отличие от объекта Документ не является контекстным. Написав просто переменную Субсчет, мы можем получить сообщение об ошибке,  так как контекстный объект Документ в общем случае не содержит такой переменной.

Если записать предыдущий наш пример без использования контекстного объекта, то правило будет выглядеть следующим образом:

Проводка(Документ.Лицо1.Субсчет, Документ.Лицо1, Документ.Сумма, К50);

Остановимся более подробно на записи  Документ.  Лицо1.Субсчет. Что мы делаем в данном случае - берем объект Документ, у него берем подобъект Лицо1, а у этого подобъекта берем поле Субсчет. Если бы у объекта Лицо1 были бы подобъекты, то эту цепочку можно было бы продолжить. Здесь очень важно понять, что везде, где у нас определен объект типа документ, всегда можно обратиться к его переменным и подобъектам. И у этих подобъектов можно обратиться к их переменным и подобъектам и т.д.

Приведем еще один пример обращения к полям объекта. В правиле по закрытию 44 счета можно написать следующую операцию.

ДляВсех(Лиц("44"))
{  C = СКД44 / .ОК46;
   Проводка(Д46_10, C * .ОК46_10, К44, Лицо);
   Проводка(Д46_20, C * .ОК46_20, К44, Лицо);
}

В данном случае мы перебираем всех лиц, имеющих сальдо или обороты по 44-му счету. При переборе в операцию вносится контекстный объект Лицо. Псевдопеременная СКД44 (сальдо конечное дебетовое по 44-му счету) в случае, когда объект типа Лицо является контекстным, трактуется как сальдо по 44-му счету в разрезе данного лица. Аналогичная ситуация и по 46-му счету. Как же в таком случае получить общее сальдо или в данном случае обороты по 46 счету? Для этого используется запись вида ‘.ОК46’. Точка в начале записи говорит о том, что мы обращаемся к базовому значению переменной, вне текущего контекста. Запись с точкой перед именем переменной может использоваться и в других случаях. Не вдаваясь в сложные теоретические обоснования, попробуем пояснить это на примерах:

     Вариант 1                      Вариант 2
ДляВсех(Наименований)          ДляВсех(Наименований)
{  А += СуммаСебест; }         {  .А += СуммаСебест;}
Сообщить(А);                   Сообщить(А);

В варианте 1 при выполнении функции ‘Сообщить’ будет выдано сообщение об ошибке, в связи с отсутствием переменной ‘А’, в вариатне 2 все пройдет нормально. В чем разница? В точке перед именем переменной ‘А’ при суммировании в цикле. В первом случае переменная создается внутри цикла и при его завершении будет уничтожена, и следовательно в момент выполнения функции  ‘Сообщить’ ее уже не будет. Во втором случае переменная ‘А’ создается в базовом контексте, т.е. как бы вне цикла, и соответственно не уничтожается при его завершении.

Набор объектов, с которыми Вам придется оперировать в программе, строго фиксирован и достаточно невелик. Наиболее типичными среди них являются объекты типа Лицо,  Документ и Наим. В дальнейшем мы приведем более подробное описание всех объектов, используемых в системе.

Алгоритм сравнения объектов

Как сравниваются два объекта в СБиС++, например, в выражении оОбъект1 == оОбъект2.

Если оба объекта нулевые (равны "Нет", пустые),
   то они равны.
Иначе Если один из них нулевой, а другой - нет,
   то они не равны
Иначе (оба не нулевые)
   Если оба объекта не имеют записей, то они равны
   Иначе Если один объект имеет запись, а другой - нет, то они не равны
   Иначе (оба объекта имеют записи)
     Если записи имеют ОДНОГО И ТОГО ЖЕ хозяина и ОДИНАКОВЫЙ адрес, то они равны
      Иначе
         они не равны

Поясним на примере действие этого алгоритма. В выражении:

перем оОбъект = Выборка("Организации");
оОбъект.Загрузить(0x12345);
оОбъект.МоёДополнительноеПоле = "1234";

записью будет запись выборки (а МоёДополнительноеПоле в эту запись НЕ войдёт ). Хозяином записи будет выборка "Организации". При сравнении важно, чтобы записи принадлежали не просто к одинаковой выборке, а к ОДНОМУ экземпляру выборки. Например:

перем оТаблица1 = Выборка("Организации");
перем оОбъект1 = оТаблица1.Запись();
оОбъект1.Загрузить( 0x26B );
перем оОбъект2 = оТаблица1.Запись();
оОбъект2.Загрузить( 0x26B );
перем оТаблица2 = Выборка("Организации");
перем оОбъект3 = оТаблица2.Запись();
оОбъект3.Загрузить( 0x26B );
Сообщить("Равны ли оОбъект1 и оОбъект2? " + (оОбъект1 == оОбъект2) );
Сообщить("Равны ли оОбъект1 и оОбъект3? " + (оОбъект1 == оОбъект3) );

В результате получим:

•  Равны ли оОбъект1 и оОбъект2? – Да;

•  Равны ли оОбъект1 и оОбъект3? - Нет.

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