1С-Предприятие 8.0. Быстрая разработка прикладных решений
Что я делаю?
А что же я делаю?! Такой вопрос периодически возникает у всех, кто сталкивался или просто интересовался разработками на 1С.Предприятии.
"Пишу программу", - вот наиболее частый ответ. "На чем?" - "на 1С". "На чем вы работаете?" - "на 1С". "На чем это написано?" - "на 1С". "Требуется бухгалтер со знанием 1С", "требуется программист 1С на неполный рабочий день..." и т.д.
Такие фразы можно встретить постоянно, и вам они наверняка хорошо знакомы. Для человека непосвященного в них нет ничего особенного, однако тех, кто имеет представление о разработке на 1С.Предприятии, такие вопросы зачастую могут поставить в тупик, потому что в этих фразах термином "1С" обозначаются совершенно разные предметы, а термин "программа" и вовсе сбивает с толку...
Для успешного освоения этой книги важно понимать основы построения системы 1С:Предприятие, и тогда на вопрос: "а чем вы занимаетесь?", вы уже не ответите уныло: "учусь писать программы на 1С", а с легким чувством превосходства сможете произнести: "я изучаю методы разработки прикладных решений на основе платформы 1С:Предприятия 8.0"!
Чтобы было понятно, что именно мы будем создавать с вами на протяжении этой книги, объясним сначала, что представляет собой система 1С:Предприятие вообще. [14]
Дерево конфигурации
Можно сказать, что дерево конфигурации - основной инструмент, с которым работает разработчик. Дерево конфигурации содержит в себе практически всю информацию о том, из чего состоит конфигурация:

Наверняка у вас уже возник вопрос: почему в дереве что-то есть, если мы пока еще ничего не создавали? Дело в том, что для облегчения работы разработчика "все, из чего состоит конфигурация" собрано в несколько отдельных групп, и сейчас дерево и показывает вам эти группы.
Если вы походите по дереву и понажимаете на


Хотелось бы уже начать что-нибудь делать, но прежде следует определиться с терминами. Вы наверняка уже заметили, что, говоря о содержимом конфигурации, мы сознательно избегали использования каких либо терминов. Но теперь настало время, когда можно определиться с терминологией и рассказать про... [21]
Первое знакомство
Первая глава нашей книги будет посвящена знакомству с системой 1С:Предприятие 8.0 и главным инструментом разработчика - конфигуратором. Вы узнаете, что обозначается терминами платформа, конфигурация и прикладное решение. Познакомитесь с различными режимами запуска системы 1С:Предприятие 8.0, узнаете, что такое объект конфигурации и как можно создать новый объект. [13]
Справочник
В этой главе мы познакомимся с объектом конфигурации Справочник. Вы узнаете, для чего используется этот объект, какова его структура и какими основными свойствами он обладает. На практических примерах вы научитесь создавать справочники, описывать наиболее важные элементы их структуры и заполнять их данными.
Кроме этого вы узнаете еще об одном объекте конфигурации - Форма.
В заключение, в конце главы, будет сделано небольшое отступление, касающееся механизма внесения изменений в конфигурацию и использования одного из инструментов разработчика - палитры свойств. [28]
Документ
В этой главе мы познакомимся с объектом конфигурации Документ. Вы узнаете, для чего используется этот объект, какова его структура и какие основными свойствами обладает документ. Затем мы создадим несколько документов и покажем, каким образом разработчик может задавать собственные алгоритмы выполнения тех или иных действий, связанных с работой документа.
Кроме этого, вы узнаете, как создать форму объекта базы конфигурации, познакомитесь с некоторыми конструкциями встроенного языка и узнаете, что такое типообразующие объекты конфигурации. [60]
Регистр накопления
В этой главе мы познакомимся с объектом конфигурации Регистр накопления. Вы узнаете, для чего используется этот объект, какой структурой он обладает и каковы его отличительные особенности.
В заключение главы мы создадим с вами один из регистров накопления, который будет использоваться в нашей конфигурации. [82]
Отчет
В этой главе мы познакомимся с вами с объектом конфигурации Отчет. Вы узнаете, для чего он используется, и создадите отчет, который будет показывать движения и остатки материалов на нашем предприятии. [96]
Макет
В этой главе вы познакомитесь с очередным новым объектом конфигурации - Макет. Вы узнаете о его назначении и создадите макет документа, на основе которого будет формироваться печатная форма документа. [103]
Как работать с деревом конфигурации и как создать объект
Прежде чем мы приступим к созданию первых объектов конфигурации, следует объяснить некоторые приемы работы с конфигуратором.
Для того чтобы открыть и закрыть конфигурацию следует использовать пункты меню:
Конфигурация

Конфигурация

После того, как конфигурация открыта, ее состав появляется в окне дерева конфигурации. Это окно вы можете закрыть, как любое другое окно Windows, при этом конфигурация останется открытой (т.е. доступной для редактирования). Чтобы снова отобразить на экране окно дерева конфигурации следует воспользоваться командой меню Конфигурация

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


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

Теперь, взглянув на список кратких итогов главы, проверьте, насколько хорошо вы поняли изложенный материал.
После этого мы сможем с вами приступить к созданию первых объектов конфигурации. [26]
Объект конфигурации Документ
Объект конфигурации Документ является прикладным объектом и предназначен для описания информации о совершенных хозяйственных операциях или о событиях, произошедших в жизни организации вообще. На основе объекта конфигурации Документ платформа создает в базе данных информационную структуру, в которой будут храниться, например, такие документы как приходные накладные, или приказы о приеме на работу, или платежные поручения, или счета и т.д.
Характерной особенностью объекта конфигурации Документ является то, что в процессе работы пользователь может самостоятельно создавать новые объекты этой структуры - новые документы.
Поведение документа отличается от поведения всех остальных объектов базы данных. Документ обладает способностью проведения. Факт проведения документа означает, что событие, которое он отражает, повлияло на состояние учета. До тех пор, пока документ не проведен, состояние учета неизменно и документ - не более чем черновик, заготовка. Как только документ будет проведен - изменения, вносимые документом в учет, могут вступить в силу и состояние учета может быть изменено.
Поскольку документ вносит изменения в состояние учета, он всегда "привязан" к конкретному моменту времени. Это позволяет отражать в базе данных фактическую последовательность событий.
Следующим важным фактом, вытекающим из двух предыдущих, является то, что система 1С:Предприятие имеет механизмы, позволяющие отслеживать правильность состояния учета. Предположим, что мы изменили один из проведенных ранее документов и снова провели его "задним числом". В этом случае система 1С:Предприятие способна отследить, повлияют ли внесенные нами изменения на последующие проведенные документы, и если это так, система способна перепровести необходимые документы.

Движения документов no регистрам могут быть теперь с разными датами.
Документ может иметь несколько табличных частей. [61]
У последовательностей могут быть измерения, за счет чего при восстановлении последовательностей будут перепроводиться только те документы, которые изменили состояние регистров no данному значению измерения.

О том, какая существует разница в названии справочников и документов можно прочитать в главе "Справочники и документы" на странице 539.

О том, что такое МоментВремени можно прочитать в главе "Понятие момента времени" на странице 540.
Для "визуализации" документа существует несколько основных форм

О структуре объектов встроенного языка, предназначенных для работы с документами можно прочитать в главе "Документы" на странице 577. [63]
Объект конфигурации Макет
Объект конфигурации Макет предназначен для хранения различных форм представления данных, которые могут потребоваться каким либо объектам конфигурации или всему прикладному решению в целом. Макет может содержать табличный или текстовый документ, двоичные данные, HTML-документ или Active Document. Макеты могут существовать как сами по себе (общие макеты), так и быть подчинены какому либо объекту конфигурации.
Одно из предназначений макета, подчиненного объекту конфигурации и содержащего табличный документ - создание печатной формы этого объекта.
Создание печатной формы заключается в конструировании ее составных частей - именованных областей, из которых затем "собирается" готовая печатная форма. Порядок заполнения областей данными и порядок вывода их в итоговую форму описывается при помощи встроенного языка.
Печатная форма может включать в себя различные графические объекты: картинки, OLE-объекты, диаграммы и т.д.
Помимо создания макета "вручную", конфигуратор предоставляет разработчику возможность воспользоваться специальным инструментом - конструктором печати, который берет на себя большинство рутинной работы по созданию макета. [104]
Объект конфигурации Отчет
Объект конфигурации Отчет является прикладным объектом и предназначен для описания средств и алгоритмов, при помощи которых пользователь сможет получать необходимые ему выходные данные. Алгоритм формирования выходных данных описывается при помощи визуальных средств или с использованием встроенного языка В реальной жизни объектам конфигурации Отчет соответствуют всевозможные таблицы выходных данных, сводных данных диаграммы и пр.

Для тех, кто работал с версией 7.7
Отчеты могут иметь теперь несколько реквизитов, табличных частей, форм и несколько макетов (печатных форм). Теперь доступен программный объект "Построитель отчета", позволяющий формировать отчеты автоматически. Таблица отчета может иметь вертикальные и горизонтальные группировки. [97]
Объект конфигурации Регистр накопления
Объект конфигурации Регистр накопления является прикладным объектом и предназначен для описания структуры накопления данных. На основе объекта конфигурации Регистр накопления платформа создает в базе данных информационную структуру, в которой будут накапливаться данные, "поставляемые" различными объектами базы данных. Эти данные будут храниться в регистре в виде отдельных записей, каждая из которых имеет одинаковую, заданную в конфигураторе, структуру.
Отличительной особенностью регистра накопления является то, что он не предназначен для интерактивного редактирования пользователем. Разработчик может, при необходимости, предоставить пользователю возможность редактировать регистр накопления, но предназначение регистра накопления заключается в том, чтобы его модификация производилась на основе алгоритмов работы других объектов базы данных (не обязательно документов, как в версии 7.7), а не в результате непосредственных действий пользователя.

Движения документа no регистру накопления могут быть теперь с разными датами. Например, документ "План продаж" может внести в регистр накопления записи о предполагаемых продажах компании несколькими разными датами.
Виды числовой информации, накапливаемой регистром накопления, называются ресурсами и также являются подчиненными объектами и описываются в конфигураторе.
Например, регистр накопления может накапливать информацию о количестве и сумме товаров на складах. В этом случае он будет иметь измерения "Товар" и "Склад", и ресурсы "Количество" и "Сумма".
Изменение состояния регистра накопления происходит, как правило, при проведении документа, и заключается в том, что в [85] регистр добавляется некоторое количество записей. Каждая запись содержит значения измерений, значения приращений ресурсов, ссылку на документ, который вызвал эти изменения (регистратор) и "направление" приращения (приход или расход). Такой набор записей называется движениями регистра накопления. Каждому движению регистра накопления всегда должен соответствовать регистратор.
Кроме того, регистр накопления может хранить дополнительную информацию, описывающую каждое движение. Набор такой дополнительной информации задается разработчиком при помощи реквизитов объекта конфигурации Регистр накопления.

О структуре объектов встроенного языка, предназначенных для работы с регистрами накопления можно прочитать в главе "Регистры накопления" на странице 599. [86]
Объект конфигурации Справочник
Объект конфигурации Справочник является прикладным объектом и предназначен для описания списков данных. Объект конфигурации Справочник используется для того, чтобы на его основе платформа создала в базе данных информационную структуру, в которой будет храниться, например, список сотрудников, перечень товаров, список клиентов или поставщиков.
Характерной особенностью объекта конфигурации Справочник является то, что пользователь в процессе работы может самостоятельно добавлять новые элементы в справочник. Например, пользователь может добавить в справочник новых сотрудников, создать новый товар или внести нового клиента.

Элементы справочника могут иметь теперь несколько табличных частей и несколько форм (форма элемента, списка, выбора и т.д.).
Глубина иерархии справочников может быть произвольной. Иерархия может строиться не только no принципу иерархии групп, но и no принципу иерархии элементов (когда элемент справочника подчинен непосредственно другому элементу).
Теперь нет понятия периодических реквизитов справочников. Для хранения каких-либо данных (в том числе значений реквизитов справочников), развернутых во времени, теперь следует использовать новые объекты конфигурации - регистры сведений, поддерживающие периодическое сохранение значений своих ресурсов.
В конфигураторе можно задать набор предопределенных элементов справочника.
Кроме этого, каждый элемент справочника может содержать некоторый набор информации, которая одинакова по своей структуре, но различна по количеству, для разных элементов справочника. Так, например, каждый элемент справочника Сотрудники может содержать информацию о составе семьи сотрудника. Для одного сотрудника это будет только супруга, а у другого семья может состоять из супруги, сына и дочери. Для описания подобной информации могут быть использованы табличные части объекта конфигурации Справочник, являющиеся подчиненными объектами конфигурации.
Для удобства использования элементы справочника могут быть сгруппированы пользователем по какому-либо принципу. Например, в справочнике "Бытовая техника" могут быть созданы группы: "Холодильники", "Телевизоры", "Стиральные машины" и т.д. Возможность создания таких групп в справочнике задается свойством "Иерархический" объекта конфигурации Справочник. В этом случае элемент справочника, представляющий собой группу, будет являться родителем для всех элементов и групп, входящих в эту группу. Такой вид иерархии называется иерархией групп и элементов.
Возможен и другой вид иерархии - иерархия элементов. В этом случае в качестве родителя выступает не группа элементов справочника, а непосредственно один из элементов справочника. Например, такой вид иерархии можно использовать при создании справочника "Подразделения", когда одно подразделение является родителем для нескольких других подразделений, входящих в его состав.
Элементы одного справочника могут быть подчинены элементам или группам другого справочника. Например, справочник "ЕдиницыИзмерения" может быть подчинен справочнику "Товары". Тогда для каждого элемента справочника "Товары" мы сможем указать единицы измерения, в которых этот товар поступает на склад. В системе 1С:Предприятие это достигается путем того, что для каждого объекта конфигурации Справочник можно указать список владельцев справочника. [30]
Порой встречаются ситуации, когда необходимо, чтобы в справочнике некоторые элементы существовали всегда, независимо от действий пользователя. Допустим логика бизнес-процессов на предприятии такова, что все товары сначала поступают на основной склад, а затем по мере надобности перемещаются на другие склады. В этом случае в справочнике "Склады" всегда должен существовать склад "Основной", иначе приходование товаров будет выполнено неправильно. Объект конфигурации Справочник позволяет описать любое количество таких элементов справочника. Они называются предопределенными элементами справочника.
В зависимости от того, какие действия мы хотим выполнять со справочником, нам требуется изображать справочник в "разном виде". Например, для того, чтобы выбрать некоторый элемент справочника, удобнее представить справочник в виде списка, а для того, чтобы изменить какой-то элемент справочника, удобнее представить все реквизиты этого элемента справочника на одной форме. Поэтому объект конфигурации Справочник может иметь произвольное количество форм, часть из которых можно назначить в качестве основных форм справочника.
Следующая таблица поясняет названия этих форм, заданные в конфигураторе:
Любая форма может быть описана в конфигураторе. Для создания такого описания существует подчиненный объект конфигурации Форма. Как правило, он подчинен одному из прикладных объектов, но [31] может существовать и самостоятельно. На основании описания, содержащегося в объекте конфигурации Форма в нужный момент работы пользователя платформа 1С:Предприятие создаст программный объект Форма, с которым и будет работать пользователь.

Объекты конфигурации
Конфигурация представляет собой описание. Она описывает структуру данных, которые пользователь будет использовать в режиме 1С:Предприятие. Кроме этого конфигурация описывает всевозможные алгоритмы обработки этих данных, конфигурация содержит информацию о том, как эти данные должны будут выглядеть на экране и на принтере, и т.д.
В дальнейшем платформа 1С:Предприятия, на основании этого описания, создаст базу данных, которая будет иметь необходимую структуру, и предоставит пользователю возможность работать с этой базой данных.
Для того чтобы систему 1С:Предприятие можно было быстро и легко настраивать на нужные прикладные задачи, все описание, которое содержит конфигурация, состоит из неких логических единиц, называемых объектами конфигурации.
Возможно, вы уже успели заглянуть в книгу "Конфигурирование и администрирование 1С:Предприятия 8.0", в которой дается краткое описание объекта конфигурации.
Мы не будем дублировать это определение в настоящей книге, поскольку наша задача заключается не в том, чтобы изложить концепцию построения системы 1С:Предприятие как структуры метаданных, описанной в терминах классов проблемно-ориентированных бизнес-сущностей, а в том чтобы научить вас методически правильно и грамотно использовать возможности 1С:Предприятия.
Поэтому, что представляют собой объекты конфигурации, мы объясним на "бытовом" уровне, который, однако, даст вам возможность правильно понимать назначение объектов применительно к тем задачам, которые мы будем решать.
С одной стороны, объекты конфигурации представляют собой детали конструктора, из которого собирается конфигурация. Обычно в конструкторе существует некоторый набор деталей. Детали могут быть разного вида: длинные, короткие, квадратные, прямоугольные и т.д. Теперь представьте, что деталей каждого вида мы можем создавать столько, сколько нам нужно (скажем 5 длинных и 3 коротких). Мы можем соединять детали между собой различными способами. [22]
To же и с объектами конфигурации. Мы можем создавать только объекты определенных видов. Но каждого вида объектов мы можем создать столько, сколько нам нужно. Объекты одного вида отличаются от объектов другого вида тем, что имеют разные свойства (точнее говоря разный набор свойств). Объекты могут взаимодействовать друг с другом, и мы можем описать такое взаимодействие.
В чем еще сходство объектов конфигурации с деталями конструктора? В конструкторе обычно есть блоки, которые можно скрепить между собой, и есть другие детали, например колеса, которые скрепить между собой нельзя, зато их можно соединить с осью и тогда колеса будут вращаться. Т.е. разные детали конструктора по-разному ведут себя.
Объекты конфигурации также обладают различным поведением, и это поведение зависит от вида объекта. Одни объекты могут выполнять какие-то действия, другие этих действий выполнять не могут, зато у них есть свой собственный набор действий.
Следующую особенность объектов конфигурации можно продемонстрировать на примере автомобиля. Автомобиль состоит из большого количества деталей. Одна из деталей автомобиля это двигатель. Но двигатель, в свою очередь, тоже состоит из набора деталей, причем в разных двигателях могут использоваться одни и те же детали.
Так же "сложные" объекты конфигурации состоят из более "простых" объектов и одни и те же "простые" объекты могут входить в состав сложных объектов. Такая структура позволяет упростить работу с объектами конфигурации, поскольку если мы знаем, как работать с каким-либо "простым" объектом, то в любом "сложном" объекте, в состав которого он входит, мы будем работать с ним все тем же образом.
И, наконец, самое важное качество объектов конфигурации - это их прикладная направленность. Объекты конфигурации не просто некие абстрактные конструкции, при помощи которых разработчик пытается описать поставленную перед ним задачу - они представляют собой аналоги реальных объектов, которыми оперирует предприятие в ходе своей работы.
Например, на каждом предприятии существуют различные документы, с помощью которых оно фиксирует факты совершения [23] хозяйственных операций. Точно так же в конфигурации существуют объекты вида "Документ".
Кроме этого, на каждом предприятии обязательно ведется список сотрудников, справочник номенклатуры или товаров. В конфигурации тоже есть специальные объекты вида "Справочник", которые позволяют разработчику создавать компьютерные аналоги таких списков.

В версии 8.0 объектная модель платформы была унифщирована и расширена. Теперь, например, элемент справочника может иметь табличную часть. Поскольку объекты унифицированы, табличная часть справочника и табличная часть документа описывается аналогичными объектами конфигурации. Соответственно работа с табличной частью документа аналогична работе с табличной частью справочника.
Мы отойдем от такого "размытого" стиля изложения и в тех местах, где речь будет идти о конфигурации, мы будем использовать явное уточнение - объект конфигурации Справочник "Сотрудники". Там же, где речь пойдет о базе данных, мы будем говорить просто: справочник "Сотрудники". [24]
Оперативное и неоперативное проведение
Факт проведения документа и необходимость поддержания актуальной последовательности документов на оси событий порождают два различных способа проведения документов: оперативное и неоперативное проведение.
С оперативным проведением документов связано понятие оперативной отметки времени.
Оперативная отметка времени представляет собой значение типа Дата, которое формирует система. Оперативная отметка времени создается системой каждый раз при оперативном проведении документа. Ее значение формируется исходя из текущего времени и последней созданной оперативной отметки.
Если последняя оперативная отметка меньше текущего времени, в качестве новой оперативной отметки принимается текущее время.
Если последняя оперативная отметка равна или больше текущего времени, в качестве новой оперативной отметки принимается значение, на одну секунду большее, чем старая оперативная отметка времени.
Таким образом, если у объекта конфигурации Документ установлено свойство оперативного проведения, последовательность действий системы будет следующей: при создании нового документа система будет устанавливать ему текущую дату и "нулевое" время.
При проведении такого документа (с текущей датой), система установит в качестве даты документа оперативную отметку времени. Если отменить проведение документа и затем провести его снова (не изменяя даты), система установит документу новую оперативную отметку времени.
Если же попытаться перепровести документ, то будет выдан запрос о виде проведения (оперативное или нет).
В случае оперативного проведения система установит новую оперативную отметку времени, а при неоперативном проведении время документа будет сохранено прежним.
При попытке проведения (или перепроведения) оперативно проводимого документа с датой, отличающейся от текущей, будет выдано сообщение о том, что оперативное проведение невозможно и [64] предложено провести документ неоперативно (т.е. с сохранением существующей даты и времени документа).

В 1С:Предприятии 8. 0 нет понятия точки актуальности, связанной с расчетом регистров и проведением документов. Теперь регистры актуальны на последнюю дату, которой в них внесены записи.
Средствами встроенного языка возможно определение текущего режима проведения документа (система передает его одним из параметров в обработчик события ОбработкаПроведения()). В зависимости от этого могут существовать различные алгоритмы проведения документа в том или ином режиме. [65]
Основная конфигурация и конфигурация базы данных
До сих пор мы не углублялись в структуру системы 1С:Предприятие 8.0, но теперь пришло время сказать об этом несколько слов.
Вспомните, с точки зрения пользователя, программа 1С состоит из платформы и конфигурации. Мы говорили, что в каждом конкретном случае используется одна из множества возможных конфигураций. Настало время сказать, что это не совсем так.
Почему не так? Потому что в каждой информационной базе существуют, как минимум, две конфигурации.
Почему не совсем так? Потому что пользователь действительно работает всегда только с одной конфигурацией. Вторая конфигурация предназначена для разработчика или человека, который должен вносить изменения в конфигурацию (например, администратора базы данных). Для пользователя она "не видна".
Конфигурация, предназначенная для разработчика, называется Основная конфигурация (или просто Конфигурация - та, которую мы редактировали в Конфигураторе). Конфигурация, с которой работают пользователи, называется Конфигурация базы данных.

Узнай больше!
О том, сколько и каких конфигураций существует в информационной базе можно прочитать в главе "Немного о конфигурациях" на странице 535.
Основную конфигурацию можно редактировать, конфигурацию базы данных редактировать нельзя, можно только произвести обновление конфигурации базы данных на основе основной конфигурации.
Такое внутреннее устройство позволяет вносить изменения в конфигурацию, не прерывая работы пользователей (поскольку изменения вносятся в основную конфигурацию). Затем, когда разработчик будет уверен в том, что все изменения, которые он внес, верны, можно будет быстро произвести обновление конфигурации [52] базы данных, используя основную конфигурацию. Но для этого придется завершить работу всех пользователей.
Разработчик всегда может сравнить основную конфигурацию и конфигурацию базы данных, может вернуться к исходному состоянию основной конфигурации, используя конфигурацию базы данных (если, например, совсем запутался в своих изменениях

Таким образом, взаимодействие двух конфигураций можно представить следующим образом:

Когда разработчик работает с основной конфигурацией, система всегда подсказывает ему, отличается ли его вариант основной конфигурации от того, который сохранен, и отличается ли сохраненный вариант основной конфигурации от конфигурации базы данных.
Если разработчик редактирует основную конфигурацию и редактируемый вариант основной конфигурации отличается от того, который сохранен, в заголовке окна дерева конфигурации появляется признак модифицированности конфигурации (*):

[53]
Если сохраненный вариант основной конфигурации отличается от конфигурации базы данных, в заголовке окна дерева конфигурации появляется знак отличия конфигураций ():

Для сохранения основной конфигурации следует воспользоваться командой
Конфигурация

а для обновления конфигурации базы данных необходимо выполнить команду
Конфигурация

При выполнении команды Отладка

При выполнении команды Отладка

Таким образом, система старается облегчить жизнь разработчика и автоматизировать часто выполняемые операции.
Важным фактом является то, что именно в момент обновления конфигурации базы данных, система создает (модифицирует) в базе данных те структуры хранения данных, которые мы описали в виде объектов конфигурации.
Таким образом, обычные элементы справочника пользователь добавляет в ту структуру базы данных, которую создала система на основе объекта конфигурации Справочник, а предопределенные элементы этого справочника система добавляет в эту структуру сама, на основе все того же описания этой структуры, которым является объект конфигурации Справочник. [54]
Отсюда следует немаловажный факт (о котором говорилось в предыдущем разделе), что если простые элементы справочника "безразличны" для конфигурации, то предопределенные элементы важны для нее, поскольку на них могут быть "завязаны" алгоритмы работы конфигурации. [55]
Палитра свойств
Еще один инструмент разработчика, который мы использовали по ходу изложения, но на описании которого не заостряли внимание, - это палитра свойств.
Если помните, мы использовали палитру свойств, когда создавали табличную часть и реквизиты табличной части объекта конфигурации Справочник "Номенклатура".
Палитра свойств это специальное служебное окно, которое позволяет редактировать все существующие свойства объекта конфигурации. Поскольку разные объекты конфигурации имеют самые разные свойства, содержимое этого окна будет меняться в зависимости от того, какой объект является текущим (на каком объекте конфигурации установлен курсор).
При некоторых действиях разработчика (например, создание табличной части), палитра свойств открывается автоматически. Но разработчик всегда может открыть палитру свойств объекта конфигурации самостоятельно, воспользовавшись пунктом "Свойства" контекстного меню правой кнопки мыши.
В этом случае палитра свойств откроется и будет закреплена на рабочей области конфигуратора. Однако есть удобная возможность "открепить" палитру свойств (используя символ кнопки в заголовке окна палитры свойств):
"Открепим" палитру свойств.

[56]
В этом состоянии, при наведении курсора мыши на любое другое окно, палитра свойств будет сворачиваться на дополнительную панель с правой (по умолчанию) стороны экрана:

А при наведении курсора мыши на символ свернутой палитры свойств, она будет открываться.
Подобным поведением (возможностью быть прикрепленным, прячущимся и т.д.) обладает не только окно палитры свойств, но и другие окна конфигуратора (например, окно дерева конфигурации). [57]
Первое знакомство
Итак, запустим 1С:Предприятие в режиме конфигуратора. Перед вами окно конфигуратора. Именно с помощью этого инструмента мы будем создавать нашу конфигурацию.
Большое количество незнакомых иконок на панели инструментов часто смущает начинающего разработчика. Не следует этого бояться - со временем вы сможете свободно ориентироваться среди них. Сначала пользуйтесь пунктами меню - и постепенно ваша работа сама собой переместится на панель инструментов.
Выполним первую команду, с которой начинается работа с любой конфигурацией - Конфигурация

Редактирование формы документа ОказаниеУслуги
Откроем в конфигураторе форму документа "ОказаниеУслуги" - "ФормаДокумента". Откроем палитру свойств для табличного поля, расположенного в форме, и установим свойство "Подвал", которое определяет наличие подвала у элемента управления табличное поле.
Добавим подвал к табличному полю...

Затем откроем свойства колонки "Цена" и установим текст подвала - "Всего:", горизонтальное положение в подвале - "Прижать вправо" и в шрифте подвала изменим начертание на "Жирный". [114]
После этого откроем свойства колонки "Сумма", установим горизонтальное положение в подвале - "Прижать вправо", установим флаг "Показывать итог в подвале" и в шрифте подвала тоже изменим начертание на "Жирный".
Запустим 1С:Предприятие в режиме отладки и посмотрим, как теперь выглядит форма документа Оказание услуги № 1:

Подобным образом, используя свойства элементов управления и задавая их значения, разработчик имеет возможность создать экранную форму любого дизайна и поведения. [115]
Редактирование макета документа ОказаниеУслуги
Откроем конфигуратор, раскроем дерево документа "ОказаниеУслуги" и дважды щелкнем на макете "Печать". Как видите, макет документа состоит из именованных областей, которые в определенном порядке выводятся на печать.
Добавим новую область для вывода итоговой суммы документа. Выделим мышью две пустые строки и выполним команду Таблица


Выделим мышью две строки и зададим имя области

Назовем область "Всего". В созданной области, в колонке "Цена", напишем "Всего", а в колонке "Сумма" напишем "ВсегоПоДокументу". [110]
Вызвав палитру свойств для последней заполненной нами ячейки, укажем, что в этой ячейке будет находиться не текст, а параметр:
Укажем, что в ячейке будет находиться не текст, а параметр...

Здесь следует сказать о том, что каждая ячейка редактируемого нами табличного документа может содержать либо текст, либо некоторый параметр, либо шаблон.
Текст, содержащийся в ячейке, будет показан на экране.
Параметр будет заменен некоторым значением, которое может быть присвоено ему средствами встроенного языка. Текст, содержащийся в ячейке, является именем этого параметра.
Шаблон представляет собой текстовую строку, в определенные места которой будут вставлены значения параметров.
Поэтому, указав для ячейки в качестве заполнения "Параметр", мы определили параметр области с именем "ВсегоПоДокументу", которому присвоим нужное нам значение при формировании печатной формы. [111]
Теперь откроем модуль формы документа "ОказаниеУслуги" - "ФормаДокумента". Найдем в нем процедуру "Печать" и после цикла добавим в нее следующие строки (новые строки выделены жирным шрифтом):
//{{_КОНСТРУКТОР_ПЕЧАТИ_ЭЛЕМЕНТ(Печать)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
ТабДок = Новый ТабличныйДокумент;
Макет = Документы.ОказаниеУслуги.ПолучитьМакет("Печать");
// Заголовок
Область = Макет.ПолучитьОбласть("Заголовок");
ТабДок.Вывести(Область);
// Шапка
Область = Макет.ПолучитьОбласть("Шапка");
Область.Параметры.Номер = Номер;
Область.Параметры.Дата = Дата;
Область.Параметры.Склад = Склад;
Область.Параметры.Клиент = Клиент;
Область.Параметры.Мастер = Мастер;
ТабДок.Вывести(Область);
// тчНоменклатура
Область = Макет.ПолучитьОбласть("тчНоменклатураШапка");
ТабДок.Вывести(Область);
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
Область = Макет.ПолучитьОбласть("тчНоменклатура");
Область.Параметры.Номенклатура = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Область.Параметры.Количество = ТекСтрокаПереченьНоменклатуры.Количество;
Область.Параметры.Цена = ТекСтрокаПереченьНоменклатуры.Цена;
Область.Параметры.Сумма = ТекСтрокаПереченьНоменклатуры.Сумма;
ТабДок.Вывести(Область);
КонецЦикла;
Область = Макет.ПолучитьОбласть("Всего");
Область.Параметры.ВсегоПоДокументу = ПереченьНоменклатуры.Итог("Сумма");
ТабДок.Вывести(Область);
ТабДок.ОтображатьСетку = Ложь;
ТабДок.Защита = Ложь;
ТабДок.ТолькоПросмотр = Ложь;
ТабДок.ОтображатьЗаголовки = Ложь;
ТабДок.Показать();
//}}_КОНСТРУКТОР_ПЕЧАТИ_ЭЛЕМЕНТ
КонецПроцедуры
Подобным образом, используя свойства ячеек макета и управляя порядком их вывода, разработчик имеет возможность создать печатную форму любого дизайна.
А теперь, для того, чтобы наш документ "ОказаниеУслуги", выглядел вполне законченным, добавим итоговую сумму по документу и на экранную форму, чтобы пользователь мог видеть ее в процессе заполнения табличной части документа. [113]
Система 1С:Предприятие
Система 1С:Предприятие является универсальной системой автоматизации экономической и организационной деятельности предприятия. Поскольку такая деятельность может быть довольно разнообразной, система 1С:Предприятие имеет возможность "приспосабливаться" к особенностям конкретной области деятельности, в которой она используется. Для обозначения такой способности используется термин конфигурируемость, то есть возможность настройки системы на особенности конкретного предприятия и класса решаемых задач.
Это достигается тем, что 1С:Предприятие - это не просто программа, существующая в виде набора неизменяемых файлов, а совокупность различных программных инструментов, с которыми работают разработчики и пользователи. Логически всю систему можно разделить на две большие части, которые тесно взаимодействуют друг с другом: конфигурацию и платформу, которая управляет работой конфигурации.
Для того чтобы легче понять взаимодействие этих частей системы, сравним ее с проигрывателем компакт-дисков. Как вы хорошо знаете, проигрыватель служит для того чтобы слушать музыку. "На вкус и цвет товарищей нет", поэтому существует множество разнообразных компакт-дисков, на которых записаны музыкальные произведения на любой вкус. И для того, чтобы прослушать какую либо композицию, нужно вставить компакт-диск в проигрыватель, и проигрыватель воспроизведет записанное на нем музыкальное произведение. Более того, современный проигрыватель компакт-дисков даже позволит вам записать собственную подборку музыкальных произведений, т.е. создать новый компакт-диск.
Сам по себе проигрыватель совершенно бесполезен без компакт-диска, точно так же, как компакт-диск не может сам по себе принести нам никакой пользы (кроме как стать подставкой под чашку кофе), если у нас нет проигрывателя.
Возвращаясь к системе 1С:Предприятие, можно сказать, что платформа является своеобразным "проигрывателем", а конфигурация - "компакт-диском". Платформа обеспечивает работу конфигурации и позволяет вносить в нее изменения или создавать собственную конфигурацию. [15]
Существует одна платформа (1С:Предприятие 8.0) и множество конфигураций. Для функционирования какого-либо прикладного решения всегда необходима платформа и какая-либо (одна) конфигурация.

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

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

Если речь идет о действиях разработчика, то употребляется термин конфигурация, поскольку это точный термин 1С:Предприятия.
Термин прикладное решение является более общепринятым и понятным для пользователя системы 1С:Предприятие.
Итак, поскольку задачи автоматизации, как было упомянуто выше, могут быть самыми разными, фирма "1С" и ее партнеры выпускают прикладные решения, каждое из которых предназначено для автоматизации одной определенной области человеческой деятельности.
В качестве примеров существующих прикладных решений можно привести решение "Управление торговлей", предназначенное для автоматизации задач оперативного и управленческого учета, "Управление персоналом", предназначенное для реализации кадровой политики компании или "Управление производственным предприятием", охватывающее основные контуры учета и управления на производственном предприятии.
Прикладное решение является, по возможности, универсальным, чтобы удовлетворить потребности самых разных предприятий, работающих в одной области деятельности. И это хорошо. С другой стороны, такая универсальность неизбежно приведет к тому, что на конкретном предприятии будут использоваться далеко не все возможности прикладного решения, а каких-то возможностей в нем будет не доставать (нельзя угодить всем

Вот тут и выходит на передний план конфигурируемость системы, поскольку платформа, помимо управления работы конфигурацией, содержит средства, позволяющие вносить изменения в используемую конфигурацию. Более того, платформа позволяет создать свою собственную конфигурацию "с нуля", если по каким-либо причинам [17] использование типовой конфигурации представляется нецелесообразным.
Обратите внимание, как мы в одном абзаце перешли от "прикладного решения" к "конфигурации". Ничего не поделаешь - для пользователя понятнее так, а для разработчика - по-другому.
Таким образом, если вернуться к сравнению с проигрывателем компакт-дисков, мы можем изменять по своему вкусу мелодии, которые были ранее записаны на компакт-диске, и даже создавать диски со своими собственными музыкальными произведениями, причем нам не потребуются какие-либо музыкальные инструменты, все необходимое для создания мелодий есть в нашем проигрывателе компакт-дисков.
Для того чтобы обеспечить такие возможности, система 1С:Предприятие имеет различные режимы работы: 1С:Предприятие и Конфигуратор.
Режим 1С:Предприятие является основным и служит для работы пользователей системы. В этом режиме пользователи вносят данные, обрабатывают их и получают выходные результаты.
Режим конфигуратора используется разработчиками и администраторами баз данных. Именно этот режим и предоставляет инструменты, необходимые для модификации существующей или создания новой конфигурации.
Поскольку задача нашей книги состоит в том, чтобы научить вас создавать собственные конфигурации и изменять существующие, дальнейшее повествование будет, в основном, посвящено работе с системой в режиме конфигуратора. И лишь иногда, чтобы проверить результаты нашей работы, мы будем запускать систему в режиме 1С:Предприятие. Изучение этой книги предполагает, что у вас уже установлена на компьютере система 1С:Предприятие 8.0. Если это не так, то сейчас самое время это сделать, так как дальнейшее изложение будет непосредственно описывать последовательность работы с программой.
При установке системы 1С:Предприятие у вас не должно возникнуть никаких трудностей. Процесс установки подробно описан в брошюре "Руководство по установке и запуску", входящей в комплект документации системы 1С:Предприятие 8.0. [18]
Также у вас не должно возникнуть трудностей при запуске системы и создании пустой информационной базы.
Будьте внимательны! Для выполнения примера, содержащегося в книге, нам потребуется информационная база с ПУСТОЙ конфигурацией, а не база, созданная из шаблона:
Создадим информационную базу с пустой конфигурацией


При запуске 1С:Предприятия 8.0 вы не увидите привычного выбора 1С:Предприятие



Создание документа ОказаниеУслуги
Теперь мы аналогичным образом создадим второй документ, необходимый нам - "ОказаниеУслуги". Для этого потребуется выполнить следующие действия:
создать новый объект конфигурации Документ "ОказаниеУслуги" с реквизитами:
| · | "Склад", тип СправочникСсылка.Склады, |
| · | "Клиент", тип СправочникСсылка.Клиенты, |
| · | "Мастер", тип СправочникСсылка.Сотрудники, |
создать табличную часть этого документа "ПереченьНоменклатуры" с реквизитами:
| · | "Номенклатура", тип СправочникСсылка.Номенклатура, |
| · | "Количество", тип Число, длина 15, точность 3, неотрицательное, |
| · | "Цена", тип Число, длина 15, точность 2, неотрицательное, |
| · | "Сумма", тип Число, длина 15, точность 2, неотрицательное, |
| · | создать основную форму документа, |
| · | для полей ввода колонок "Количество" и "Цена" создать обработчик события "ПриИзменении", в котором вызывать процедуру "РассчитатьСумму" из общего модуля "РаботаСДокументами". [79] |
В результате документ "ОказаниеУслуги" будет выглядеть следующим образом:

После того, как эти действия будут выполнены, запустим 1С:Предприятие в режиме отладки и убедимся, что при вводе цены и количества в табличную часть документа "ОказаниеУслуги" сумма пересчитывается по нашему алгоритму. [80]
Создание документа ПриходнаяНакладная
После того, как мы познакомились с объектом конфигурации Документ, создадим несколько таких объектов, чтобы иметь возможность фиксировать события, происходящие в нашем OOO "На все руки мастер".
Одними из самых популярных услуг нашего предприятия является ремонт телевизоров и установка стиральных машин. И в том, и в другом случае требуются некоторые материалы, которые расходуются в процессе оказания этих услуг. Поэтому двумя важнейшими событиями в хозяйственной жизни нашей организации будут являться поступление материалов и оказание услуг.
Для отражения этих событий в базе данных мы создадим два документа: "Приходная накладная" и "Оказание услуги". Документ "Приходная накладная" будет фиксировать факт поступления в нашу организацию необходимых материалов, а документ "Оказание услуги" будет фиксировать оказание услуг и расход материалов, которые используются при оказании этих услуг.
Создадим новый объект конфигурации Документ. Зададим имя документа - "ПриходнаяНакладная". Нажмем "Далее".
Создадим реквизит документа с именем "Склад" и типом СправочникСсылка.Склады:
Создадим реквизит документа "Склад".

[67]
После этого добавим табличную часть с именем "Материалы" и создадим у нее четыре реквизита:
| · | "Материал" с типом СправочникСсылка.Номенклатура, |
| · | "Количество" с типом Число, длиной 15, точностью 3, неотрицательное, |
| · | "Цена" с типом Число, длиной 15, точностью 2, неотрицательное, |
| · | "Сумма" с типом Число, длиной 15, точностью 2, неотрицательное. |
Создадим табличную часть и опишем ее реквизиты.

Запустим 1С: Предприятие в режиме отладки и протестируем получившийся результат. В открывшемся окне программы выполним команду Операции

Пока в нашей базе данных нет ни одного документа "Приходная накладная", поэтому создадим новый документ (создать новый документ можно при помощи пункта меню Действия

Добавим новый документ при помощи меню или иконки

Система автоматически присвоит номер новому документу и нам останется только заполнить табличную часть. Заполним ее материалами для ремонта телевизоров так, как показано на рисунке:

Нажмем "ОК". [69]
Аналогичным образом мы создадим второй документ, который будет приходовать следующие материалы для установки стиральных машин:

Наверняка вы обратили внимание на то, что при заполнении документа приходится вводить сумму в каждой строке. Это неудобно, и возникает естественное желание автоматизировать работу документа так, чтобы сумма вычислялась автоматически каждый раз при изменении цены или количества материалов в строке.
Это совсем не сложно и для этого нам потребуется сначала создать собственную форму документа, а затем воспользоваться возможностями встроенного языка.
Создание движений документа ОказаниеУслуги
Теперь мы аналогичным образом создадим движения документа "ОказаниеУслуги". При использовании конструктора будем внимательны и обратим внимание на то, что документ "ОказаниеУслуги" должен расходовать материалы. Поэтому перед тем, как нажать "ОК" убедимся, что выбран правильный тип движения регистров (нам нужен "Расход").
Запустим отладку и создадим документ оказания услуги, который будет расходовать один транзистор Philips за 3 рубля.
Проведем документ оказания услуги и убедимся, что в регистре накопления он создал верные движения.
Сформированные таким образом движения этого документа будут не совсем правильны. Дело в том, что в документе "ОказаниеУслуги", в отличие от документа "ПриходнаяНакладная" могут содержаться не только расходуемые материалы, но и услуги. Поэтому в регистр "ОстаткиМатериалов" будут попадать записи и о расходуемых услугах, что не правильно.
Пока мы ничего не будем делать с движениями, которые сформировал конструктор, но как только познакомимся с перечислениями, мы внесем в обработчик проведения необходимые изменения. [94]
Создание движений документа ПриходнаяНакладная
Движения документа - это записи в регистрах, которые создаются в процессе проведения документа и отражают изменения, производимые документом. Откроем окно редактирования объекта конфигурации Документ "ПриходнаяНакладная".
Перейдем на закладку "Движения" и в списке регистров конфигурации отметим регистр накопления "ОстаткиМатериалов":
Отметим регистр накопления и воспользуемся конструктором движений...

Обратите внимание, что сразу после отметки выбранного регистра становится доступной кнопка "Конструктор движений". Этим конструктором мы и воспользуемся.
Конструктор устроен просто. В списке "Регистры" перечислены регистры, в которых документ может создавать движения. В нашем случае там пока один регистр "ОстаткиМатериалов".
В списке "Реквизиты документа" должны находиться исходные данные для создания движений. А в таблице "Поле - Выражение" [89] должны быть заданы формулы, по которым будут вычисляться значения измерений и реквизитов регистра при записи движений.
(приход или расход)
откуда берем данные

ресурсы регистра
Обратите внимание, что по умолчанию конструктор предлагает нам создавать движения прихода (символ "+" рядом с названием регистра) по регистру "ОстаткиМатериалов". Это нас вполне устраивает, ведь документ "ПриходнаяНакладная" и должен приходовать материалы.
В поле выбора "Табличная часть" выберем табличную часть нашего документа - "Материалы". Список реквизитов документа автоматически заполнится реквизитами нашей табличной части. Теперь нажмем "Заполнить выражения". [90]
В нижнем окне сформируется соответствие полей и выражений.
Выберем табличную часть и нажмем "Заполнить выражения"...

Как видите, конструктор движений установил соответствия подходящим образом: в качестве материала в регистр будет записан материал из табличной части документа, в качестве склада - склад, указанный в шапке документа, а в качестве количества - количество из табличной части документа.
Нажмем "ОК" и посмотрим, какой текст сформировал конструктор в модуле объекта:
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр ОстаткиМатериалов Приход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход; [91]
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаМатериалы.Количество;
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Внутри обработчика расположен цикл, который предназначен для перебора строк табличной части нашего документа. В цикле обращение к табличной части документа происходит по имени ("Материалы"), а строки табличной части документа представляют собой коллекцию значений, для перебора которой можно использовать конструкцию Для каждого ... из ... цикл.
Объект встроенного языка ДокументОбъект имеет свойство "Движения". Оно возвращает коллекцию наборов записей регистров, которые принадлежат этому документу. К набору записей документа, принадлежащему конкретному регистру, можно обратиться, указав через точку имя этого регистра.
Таким образом, в первой строке тела цикла мы добавляем к набору записей, который создает наш документ в регистре, новую запись и сохраняем ее в переменной "Движение".
Затем мы присваиваем нужные значения всем полям этой записи и после перебора всех строк документа (после завершения циклов) "одним махом" записываем в регистр "ОстаткиМатериалов" весь набор записей движений документа.
Посмотрим, как это работает. Запустим 1С:Предприятие в режиме отладки и откроем одновременно два окна: список документов "ПриходнаяНакладная" и список регистра накопления "ОстаткиМатериалов". [92]
Откроем Приходную накладную №1 и нажмем "ОК". Обратите внимание, что при проведении приходной накладной появляются соответствующие записи в регистрах накопления:

Аналогичные действия проделаем и с документом Приходная накладная №2. [93]
Создание формы документа
Прежде всего, следует заметить, что до сих пор мы использовали предопределенные формы объектов, которые система 1С:Предприятие создавала для нас сама "по умолчанию".
Теперь же у нас возникла необходимость слегка изменить логику работы формы документа, а значит, нам придется создать свою собственную форму документа "ПриходнаяНакладная" для того, чтобы в ней мы могли описать тот алгоритм, который нам нужен. [70]

Узнай больше!
О том, для чего предназначены основные формы объектов конфигурации, можно прочитать в главе "Механизм основных форм" на странице 542.
Вернемся в конфигуратор и откроем окно редактирования объекта конфигурации "ПриходнаяНакладная". В этом окне нас интересует закладка "Формы". Как мы видим, ни одна из основных форм документа пока не задана.
Для того чтобы создать форму документа, нажмем на символ лупы в поле ввода:
Создадим форму документа...

[71]
Система вызовет еще один полезный инструмент разработчика - конструктор форм. Этот инструмент также построен по принципу "мастеров" - ввод данных в определенной последовательности и передвижение кнопками "Далее" и "Назад".

Сразу нажмем кнопку "Готово", согласившись тем самым со всем, что нам предложила система. [72]
Обратите внимание, что в дереве объектов конфигурации у объекта конфигурации Документ "ПриходнаяНакладная" появилась форма "ФормаДокумента", а на экране открылось окно редактора форм, содержащее эту форму:
Новая форма документа и окно редактора форм

Как видите, форма документа "ПриходнаяНакладная" содержит большое количество всевозможных полей. Эти поля называются элементами управления. Они имеют разное назначение и разное поведение, которое соответствует их назначению. Однако все они служат для того, чтобы отображать информацию, хранящуюся в базе данных и организовывать интерактивную работу с этой информацией. [73]
Сейчас мы обратим свое внимание только на те элементы управления, которые нас интересуют - это три поля ввода, расположенные в колонках "Количество", "Цена" и "Сумма":
Интересующие нас элементы управления.

Мы хотим, чтобы каждый раз, когда меняется значение в поле "Количество" или в поле "Цена", в поле "Сумма" автоматически устанавливалось значение равное Количество*Цена. Очевидно, что для этого нужно написать на встроенном языке команду похожую на Сумма = Количество*Цена, которая будет выполняться при изменении значения поля "Количество" или "Цена". Но как "поймать" эти моменты изменения?
Создание макета документа ОказаниеУслуги
Откроем в конфигураторе окно редактирования объекта конфигурации Документ "ОказаниеУслуги". Перейдем на закладку "Макеты" и запустим конструктор печати:
Запустим конструктор печати...

На первом шаге укажем, что новая процедура, которая будет создана конструктором для формирования печатной формы документа, будет располагаться в модуле формы.
На втором шаге нажатием двойной стрелки определим, что все реквизиты нашего документа будут отображены в шапке печатной формы.
На третьем шаге точно также определим, что все реквизиты табличной части документа будут отображены в печатной форме.
На четвертом шаге конструктор предложит сформировать нам подвал (нижнюю часть) печатной формы. Мы не станем ничего [105] указывать (подвал в данном случае использовать не будем), и перейдем к пятому шагу.
Здесь укажем, что конструктор должен вставить новую кнопку в форму документа для вызова процедуры формирования печатной формы, и нажмем "ОК".
В конфигураторе откроется форма документа и его макет:

[106]
Проверим макет в работе. Запустим 1С:Предприятие в режиме отладки и откроем документ ОказаниеУслуги №1. Обратите внимание, что в правом нижнем углу документа появилась новая кнопка "Печать".
Появилась новая кнопка "Печать"...

Эта та кнопка, которую добавил конструктор. Нажмем на нее и увидим печатную форму нашего документа.

Как видите, конструктор сформировал вполне подходящую печатную форму для нашего документа. Единственное, чего не хватает в данной форме - это итоговой суммы документа. [107]
В следующей главе мы познакомимся с тем, как можно редактировать макеты и формы объектов конфигурации и добавим итоговую сумму к форме и макету документа "ОказаниеУслуги". [108]
Создание отчета Материалы
Теперь у нас все готово для того, чтобы можно было получать выходные данные. Поэтому приступим к созданию отчета, который будет показывать нам приход, расход и остатки материалов. Данная глава преследует цель лишь проиллюстрировать механизм создания отчетов. Более глубоко работа с конструктором выходной формы будет рассмотрена в главе "Создание отчетов" на странице 162.
Создадим новый объект конфигурации Отчет и назовем его "Материалы". Перейдем на закладку "Макеты" и воспользуемся конструктором выходной формы для того, чтобы полностью создать наш отчет.
Воспользуемся конструктором выходной формы...

После выбора имени формы конструктор предложит нам начать создание отчета. Конструктор обладает большим количеством возможностей для визуального проектирования отчетов, но мы сейчас воспользуемся только самыми простыми его возможностями и просто определим те данные, которые хотим видеть в результате работы нашего отчета.
В списке "База данных" представлен состав объектов базы данных; на основе их данных мы имеем возможность построить отчет. Если раскрыть ветку "РегистрыНакопления" то мы увидим, что кроме [98] таблицы регистра "ОстаткиМатериалов" в этой ветке присутствуют еще несколько виртуальных таблиц, которые формирует система.
Кроме таблицы регистра ОстаткиМатериалов
присутствуют еще несколько виртуальных таблиц...

Поскольку мы хотим видеть как остатки материалов, так и информацию об их поступлении и расходовании, нас будет интересовать виртуальная таблица "ОстаткиМатериалов.ОстаткиИОбороты". Раскроем ее.

Как вы видите, эта таблица содержит материал, склад и кроме этого начальные и конечные остатки, а также значения прихода, расхода и оборотов для всех ресурсов регистра "ОстаткиМатериалов". [99]
Начнем выбирать поля таблицы в нужном нам порядке двойным щелчком мыши. Сначала выберем "Склад" и "Материал". Затем выберем "КоличествоНачальныйОстаток", "КоличествоПриход", "КоличествоРасход" и в заключение "КоличествоКонечныйОстаток".
В результате окно "Поля" должно быть заполнено следующим образом:

После этого на закладке "Итоги" укажем группировочное поле "Склад":

Нажмем "ОК". Система автоматически сформирует формы и откроет их на экране.
Запустим 1С:Предприятие в режиме отладки и посмотрим, как работает отчет. Выполним Операции


Как видите, наш отчет вполне "презентабелен" и полностью отражает движение материалов, произошедшее в нашей организации:

[101]
Создание процедуры обработки события в модуле формы
Щелкните правой кнопкой мыши на поле ввода в колонке "Количество" и откройте для него палитру свойств (пункт контекстного меню Свойства). Прокрутите список до конца, и вы обнаружите перечень событий, которые могут быть связаны с этим полем ввода.
С большинством элементов управления связаны различные события, и именно с их помощью разработчик может влиять на ход работы программы.

Узнай больше!
Подробнее об обработчиках событий можно прочитать в главе "Обработчики событий" на странице 546. [74]
Среди событий, связанных с полем ввода, найдите событие "При изменении". Это событие возникает после изменения значения поля ввода.
Щелкните по кнопке с лупой в конце поля ввода, и система создаст заготовку процедуры обработчика этого события в модуле нашей формы.
Модуль - это "хранилище" для текста программы на встроенном языке. В конфигурации существует большое количество модулей, которые расположены в различных ее точках. Они могут принадлежать некоторым объектам конфигурации (например, формам), а могут существовать сами по себе (принадлежать всей конфигурации в целом). Текст программы, содержащийся в модулях, будет использоваться платформой в заранее известные моменты работы системы 1С:Предприятие.
Выберем событие "При изменении" и система создаст заготовку процедуры в модуле формы.

[75]
В модуль формы добавим следующий текст:
Процедура МатериалыКоличествоПриИзменении(Элемент)
СтрокаТабличнойЧасти = ЭлементыФормы.Материалы.ТекущиеДанные;
СтрокаТабличнойЧасти.Сумма = СтрокаТабличнойЧасти.Количество * СтрокаТабличнойЧасти.Цена;
КонецПроцедуры
Объясним назначение этих строк.
В первой строке мы обращаемся к программному объекту ЭлементыФормы. Этот объект является коллекцией значений, содержащей все элементы управления, расположенные на нашей форме. Каждый элемент управления формы можно получить, указав его имя в качестве свойства объекта ЭлементыФормы. В данном случае мы обращаемся к элементу управления с именем "Материалы" (ЭлементыФормы.Материалы).
Этот элемент управления отображает строки табличной части нашего документа. Получить ту строку, в которой в настоящее время осуществляется редактирование, можно при помощи свойства программного объекта ТабличноеПоле - ТекущиеДанные. Таким образом, в результате выполнения первой строки переменная СтрокаТабличнойЧасти будет содержать объект ДокументТабличнаяЧастьСтрока.ПриходнаяНакладная.Материалы, в котором находятся редактируемые данные.
Во второй строке вычисляется сумма как произведение количества и цены. Объект ДокументТабличнаяЧастьСтрока.<имя> позволяет обратиться к данным конкретной колонки, указав имя колонки в качестве свойства объекта (например, СтрокаТабличнойЧасти.Количество).
Теперь посмотрим, как это работает. В окне программы откроем список документов "ПриходнаяНакладная" и откроем любой из двух созданных нами документов. Если теперь вы поменяете количество в любой строке документа, то сумма в строке будет пересчитана автоматически.
Замечательно. Но теперь хотелось бы и для поля "Цена" сделать то же самое. А если заглянуть вперед, то мы увидим, что подобное автоматическое заполнение поля "Сумма" может нам понадобиться и в других документах. Поэтому лучше будет поместить расчет суммы в [76] некотором "общедоступном" месте, чтобы разные документы, имеющие аналогичные реквизиты табличной части, могли использовать этот алгоритм.
Для описания таких "общедоступных" мест служат объекты конфигурации Общий модуль, расположенные в ветке Общие

Создание процедуры обработки события в общем модуле
Для того, чтобы алгоритм, выполняемый при обработке события, был доступен для разных документов, мы создадим общий модуль и перенесем в него нашу процедуру расчета суммы. А в документе просто оставим вызовы этой процедуры из общего модуля.
Создадим объект конфигурации Общий модуль в ветке Общие

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

Согласно стандартам разработки фирмы "1С", у каждого события должен быть свой обработчик. Если одинаковые действия должны выполняться при изменении разных элементов управления (например, при нажатии нескольких кнопок), то в этом случае следует поступать следующим образом:
| · | создается отдельная процедура (функция), выполняющая необходимые действия; |
| · | для каждого элемента управления создается отдельный обработчик с именем, назначаемым no умолчанию; |
| · | из каждого обработчика вызывается требуемая процедура (функция). |
СтрокаТабличнойЧасти = ЭлементыФормы.Материалы.ТекущиеДанные;
РассчитатьСумму(СтрокаТабличнойЧасти);
КонецПроцедуры
Создание регистра накопления ОстаткиМатериалов
Теперь, когда мы знаем, для чего предназначены регистры накопления, посмотрим, как можно их использовать в нашем примере.
Прежде всего, нас интересует информация о том, сколько и каких материалов есть у нас на складах. Для накопления такой информации мы создадим регистр "ОстаткиМатериалов".
Откроем в конфигураторе нашу учебную конфигурацию и создадим новый объект конфигурации Регистр накопления. Зададим имя регистра - "ОстаткиМатериалов". Нажмем "Далее" и перейдем к созданию структуры регистра.
Создадим измерения регистра:
"Материал", с типом СправочникСсылка.Номенклатура,
"Склад", с типом СправочникСсылка.Склады.
Затем создадим ресурс "Количество" с длиной 15 и точностью 3.
В результате этих действий регистр "ОстаткиМатериалов" должен иметь следующий вид:

Если вы сейчас попытаетесь запустить 1С:Предприятие в режиме отладки, то система выдаст сообщение об ошибке: "РегистрНакопления.ОстаткиМатериалов: Ни один из документов не является регистратором для регистра". Это сообщение еще раз [87] подтверждает тот факт, что назначение регистра накопления в том, чтобы аккумулировать данные, поставляемые различными документами. [88]
Создание справочника Клиенты
Теперь, когда мы немного познакомились с возможностями объекта конфигурации Справочник, создадим несколько таких объектов, чтобы описать справочники, которые будут использоваться в нашей базе данных.
Так как наше OOO "На все руки мастер" оказывает услуги по ремонту бытовой техники, очевидно, что для ведения учета нам потребуется задать некоторую списочную информацию.
Для начала нам понадобится список сотрудников предприятия, которые будут оказывать услуги. Затем нам будет нужен список клиентов, с которыми работает наше ООО. После этого нам понадобится перечень услуг, которые может оказывать наше предприятие, и список материалов, которые могут быть израсходованы. Кроме этого нам потребуется список складов, на которых могут находиться материалы ООО "На все руки мастер".
Начнем с простых вещей - списка сотрудников и списка клиентов. Откроем в конфигураторе нашу учебную конфигурацию и создадим новый объект конфигурации Справочник.
Наша задача будет состоять в том, чтобы создать справочник, в котором будут храниться наименования наших клиентов.
После того, как вы нажмете "Добавить", система откроет окно редактирования объекта конфигурации.
Это средство, которое создано в помощь разработчику. Оно создано специально для сложных объектов конфигурации и позволяет путем выполнения последовательных действий быстро создавать такие объекты. Для того чтобы придерживаться правильной последовательности действий, в нижней части окна имеются кнопки "Далее" и "Назад". Кнопка "Далее" позволяет задавать свойства объекта в нужной последовательности (чтобы ничего не пропустить и не проскочить вперед, где потребуются данные, которые должны были быть введены ранее). Кнопка "Назад" позволяет вернуться на несколько шагов назад, если вы обнаружили, что ранее ввели не все или ошибочные данные. [33]

Про особенности использования окна редактирования объекта конфигурации и палитры свойств можно прочитать в главе "Окно редактирования объекта конфигурации и палитра свойств" на странице 544.

О правилах именования объектов конфигурации можно прочитать в главе "Стандарты именования переменных, процедур и объектов конфигурации" на странице 530.
Поэтому на синоним практически нет никаких ограничений, и его можно задавать в привычном для человека виде.
Зададим имя и синоним справочника

Все подряд свойства объекта конфигурации Справочник мы пока настраивать не будем, нас вполне удовлетворят те значения, которые система предлагает для них по умолчанию. Поэтому три раза нажмем "Далее" и окажемся на закладке "Данные".
Здесь для нас представляют интерес длина кода и длина наименования. Длина кода - важное свойство справочника. Как правило, код справочника используется для идентификации элементов справочника и содержит уникальные для каждого элемента справочника значения. Платформа может сама контролировать уникальность кодов и поддерживать автоматическую нумерацию элементов справочника.
Уникальность кодов платформа может отслеживать сама, поэтому от длины кода будет зависеть количество элементов, которые могут содержаться в справочнике. Длина кода 5 символов - это от 0 до 99999, то есть сто тысяч элементов. Для нашего небольшого OOO "На все руки мастер" этого вполне достаточно. [35]
Перейдем к длине наименования. 25 символов для нас явно мало, увеличим длину наименования до 50.
Согласимся с длиной кода и зададим длину наименования

Все остальные свойства объекта конфигурации Справочник мы оставим такими, как их предлагает система по умолчанию, и нажмем "Закрыть".

Согласно стандартам фирмы "1С", длина кода, если не определяется проектной логикой, должна быть фиксированной: 5 символов. Считается, что этого достаточно для любого справочника любой типовой конфигурации. При наличии префиксации длина кода увеличивается на допустимую длину префикса (на 3 символа).
Что касается длины наименования, то следует избегать завышенной длины, поскольку наименование, в большинстве случаев, является основным представлением, и не должно занимать слишком много места в диалоговых формах. [36]
Для большего порядка предлагается пользоваться вариантами: 25 символов для "небольших" справочников. 50 символов для тех справочников, которым 25 символов мало. 100 символов для тех справочников, которым 50 символов мало.


ответим "Да" и в следующем окне нажмем "Принять":

Перед нами откроется окно системы, в режиме 1С:Предприятие. Поскольку мы не создавали никаких интерфейсов пользователей, для просмотра результатов нашей работы следует воспользоваться меню, которое создает система по умолчанию. [37]
Выполним пункт меню Операции


Система откроет одну из основных форм справочника - основную форму списка. [38]
Пока наш справочник "Клиенты" пуст, поэтому добавим в него несколько элементов (добавить новый элемент в справочник можно при помощи пункта меню Действия

Добавим новые элементы в справочник при помощи меню или иконки

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

Теперь мы можем перейти к созданию второго справочника, который будет использоваться в нашей конфигурации - справочника "Сотрудники". [39]
Создание справочника Номенклатура
Справочник "Номенклатура" будет содержать информацию об услугах, которые оказывает OOO "На все руки мастер", и о тех материалах, которые при этом могут быть использованы.
Этот справочник не будет сложным, единственная особенность, которой он будет обладать - это наличие иерархической структуры. Для того чтобы справочником было удобно пользоваться, мы сгруппируем услуги в одну группу, а материалы - в другую. Кроме этого, поскольку OOO "На все руки мастер" оказывает самые разные услуги, они также будут логически собраны в несколько групп. To же самое можно сказать и про материалы.
Наша задача будет состоять в создании иерархического справочника. Создадим новый объект конфигурации Справочник и назовем его "Номенклатура". Перейдем на закладку "Иерархия" и установим флаг "Иерархический справочник".
Сделаем справочник иерархическим...

На закладке "Данные" зададим длину наименования справочника равной 100 символам. [45]
Теперь запустим 1С:Предприятие в режиме отладки и заполним справочник "Номенклатура". В процессе заполнения справочника мы покажем, как создавать группы справочника и переносить элементы из одной группы в другую.
Создадим две группы в корне справочника: "Материалы" и "Услуги" (меню Действия


В группе "Материалы" создадим пять элементов:
| · | "Строчный трансформатор Samsung", |
| · | "Строчный трансформатор GoldStar", |
| · | "Транзистор Philips 2N2369", |
| · | "Шланг резиновый", |
| · | "Кабель электрический": |

В группе "Услуги" тоже создадим несколько элементов - услуги по ремонту телевизоров:
| · | "Диагностика", |
| · | "Ремонт отечественного телевизора", [46] |
| · | "Ремонт импортного телевизора", и услуги по установке стиральных машин: |
| · | "Подключение воды", |
| · | "Подключение электричества": |

Теперь разнесем услуги по двум смысловым группам: услуги по ремонту телевизоров и услуги по установке стиральных машин. Для этого в группе "Услуги" создадим еще две группы: "Телевизоры" и "Стиральные машины":

[47]
Для того чтобы переместить услуги в соответствующие группы, в окне списка установим курсор на ту услугу, которую мы хотим переместить, и выполним команду Действия

Переместим услугу Диагностика в группу Телевизоры...

Аналогичным образом переместите в группу "Телевизоры" услуги "Ремонт отечественного телевизора" и "Ремонт импортного телевизора". Услуги "Подключение воды" и "Подключение электричества" переместите в группу "Стиральные машины".
Затем в группе материалы создайте две группы: "Радиодетали" и "Прочее". В группу "Прочее" поместите "Кабель электрический" и "Шланг резиновый". Остальные материалы переместите в группу "Радиодетали". [48]
Создание справочника Склады
В заключение мы создадим справочник "Склады", который будет содержать информацию о складах, используемых OOO "На все руки мастер". Этот справочник будет содержать один предопределенный элемент - склад "Основной", на который будут поступать все материалы.
Наша задача будет состоять в том, чтобы создать справочник, содержащий предопределенные элементы. Откроем конфигуратор и создадим новый объект конфигурации Справочник с именем "Склады". Перейдем на закладку "Прочее" и нажмем кнопку "Предопределенные". Система откроет список предопределенных элементов справочника. Сейчас он пуст, поэтому выполним команду Действия


Обратите внимание на то, что помимо наименования мы задали еще и имя предопределенного элемента справочника. В дальнейшем, когда мы будем использовать средства встроенного языка, мы сможем обратиться к этому элементу справочника, используя имя, которое присвоили ему в конфигураторе. [49]
Запустим 1С:Предприятие в режиме отладки и откроем справочник "Склады". Добавим в справочник еще один склад, который назовем "Розничный":

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

Таким образом, теперь мы можем обозначить две характерные особенности предопределенных элементов:
| · | на предопределенные элементы могут опираться алгоритмы работы конфигурации (т.к. возможно обращение к ним из встроенного языка по имени), |
| · | предопределенные элементы являются объектами базы данных, которые нельзя удалить в режиме 1С:Предприятия. |
Из этого видно, в чем заключается принципиальная, с точки зрения конфигурации, разница между обычными и предопределенными элементами справочника.
Обычные элементы "непостоянны" для конфигурации. В процессе работы пользователя они могут появиться, исчезнуть. Поэтому конфигурация хоть и может отличить их друг от друга, но [50] рассчитывать на них в выполнении каких либо алгоритмов она не может, в силу их "непостоянства".
Предопределенные элементы напротив, "постоянны". В процессе работы пользователя они находятся всегда на своих местах, и исчезнуть не могут. Поэтому с ними конфигурация может работать вполне уверенно и опираться на них, при отработке различных алгоритмов. По этой причине каждый из предопределенных элементов имеет уникальное имя для того, чтобы к ним можно было обратиться средствами встроенного языка.
На этом мы завершим подготовительную работу по созданию справочников и сделаем небольшое отступление, касательно тех вопросов, которые постоянно появляются у вас на экране при запуске и продолжении отладки. [51]
Создание справочника Сотрудники
Справочник "Сотрудники" будет устроен несколько сложнее, чем справочник "Клиенты". Дело в том, что в нем мы будем хранить не только фамилию, имя и отчество сотрудника, но и информацию о его прошлой трудовой деятельности. Эта информация однородна по своей структуре (организация, начало, окончание работы, занимаемая должность), но количество предыдущих мест работы у разных сотрудников может быть различным. Поэтому для хранения такой информации мы будем использовать табличную часть справочника.
Вернемся в конфигуратор и создадим новый объект конфигурации Справочник. Назовем его "Сотрудники".
Наша задача будет состоять в том, чтобы создать справочник, имеющий табличную часть.
На закладке "Данные" зададим длину наименования справочника равной 50 символам и добавим в справочник новую табличную часть с именем "ТрудоваяДеятельность":
Добавим в справочник "Сотрудники" новую табличную часть и зададим ее имя...

[40]
Создадим реквизиты табличной части "ТрудоваяДеятельность":
| · | "Организация" - тип Строка, длина 100, |
| · | "НачалоРаботы" - тип Дата, состав даты - "Дата", |
| · | "ОкончаниеРаботы" - тип Дата состав даты - "Дата", |
| · | "Должность" - тип Строка, длина 100: |
Создадим реквизиты табличной части справочника...

Для реквизитов "НачалоРаботы" и "ОкончаниеРаботы" мы выбрали состав даты - "Дата", поскольку в системе 1С:Предприятие 8.0 значения типа Дата содержат как дату, так и время. В данном случае время начала и окончания работы нам безразлично.

Согласно стандартам фирмы "1С" рекомендуется использовать следующие значения для реквизитов объектов конфигурации:
Числовой тип:
Реквизиты "флаг" - тип данных Булево.
Реквизиты "сумма" - длина 15, точность 2.
Реквизиты "количество" - длина 15, точность 3.
Реквизиты "коэффициент" - длина 10, точность 3. [41]
Реквизиты "курс" - длина 10, точность 4.
Реквизиты "процент" - длина 5, точность 2.
Строковый тип:
Допустимая длина должна быть в большинстве случаев переменной.
Неограниченная длина должна назначаться, если реквизит часто может быть не заполнен, или количество символов больше 100 (т. к. строки неограниченной длины хранятся порциями, а пустые строки совсем не занимают места).
Поэтому в справочнике "Сотрудники" мы выберем вариант редактирования справочника обоими способами - как в списке, так и в диалоге. Для этого перейдем на закладку "Формы" и установим соответствующий переключатель:
Зададим вариант редактирования справочника .

[42]
Создание справочника "Сотрудники" завершено - теперь можно запустить 1С:Предприятие в режиме отладки и заполнить справочник.
Выполните пункт меню Отладка


ответьте "Да", на последующие вопросы ответьте так же, как и ранее.
В появившемся окне программы откройте справочник "Сотрудники" и убедитесь, что установлен режим редактирования справочника в диалоге (меню Действия

Создайте сотрудников Гусакова Николая Дмитриевича, Делового Ивана Сергеевича и Симонова Валерия Михайловича, как показано на рисунках. Обратите внимание, что строки табличной части справочника можно сортировать по содержимому любой из колонок, или располагать в произвольном порядке, используя иконки командной панели:

[43]
Можно управлять порядком расположения строк табличной части...


Теперь мы можем приступить к созданию следующего справочника "Номенклатура". [44]
Типообразующие объекты
Прежде чем мы приступим к практическому созданию документов, необходимо сделать отступление о том, какие типы данных могут использоваться в системе 1С: Предприятие.
В предыдущей главе, когда мы создавали реквизиты справочников или табличных частей, мы всегда указывали тип значения, которое может принимать этот реквизит. Это были примитивные типы данных - Число, Строка, Дата и Булево. Примитивные типы данных изначально определены в системе и их набор ограничен.
Наряду с такими изначально определенными в любой конфигурации типами, могут существовать типы данных, определяемые только конкретной конфигурацией. Такие типы образуют сами объекты конфигурации в момент их создания в конфигураторе.
Например, после того, как мы создали объект конфигурации Справочник "Склады", сразу же появилось несколько новых типов данных, связанных с этим справочником. Среди них, например, СправочникСсылка.Склады. И если теперь мы укажем какому-либо реквизиту этот тип данных, то сможем хранить в нем ссылку на конкретный объект справочника "Склады".
Такие объекты конфигурации, которые могут образовывать новые типы данных, называются типообразующими.
Это небольшое отступление было необходимо потому, что уже при создании первого документа мы столкнемся с использованием типа данных, доступного благодаря объекту конфигурации Справочник "Склады". [66]
Зачем нужен регистр накопления?
Итак, мы с вами подошли к одному из главных моментов разработки любой конфигурации - созданию механизма учета накопления данных.
Казалось бы, что все необходимое мы с вами уже создали: у нас есть что расходовать и приходовать (справочники) и у нас есть чем расходовать и приходовать (документы). Осталось только построить несколько отчетов и автоматизация OOO "На все руки мастер" будет закончена.
Однако это не так.
Во-первых, путем анализа документов можно, конечно, получить требуемые нам выходные данные, но представьте, что завтра OOO "На все руки мастер" решит немного изменить свои бизнес-процессы и нам потребуется ввести в конфигурацию еще один документ (или несколько документов!).
Например, сейчас мы полагаем, что товары поступают в OOO и затем расходуются. Руководство захотело усилить материальный контроль и решило приходовать товары на основной склад организации и затем выдавать их материально ответственным лицам. В этом случае нам придется добавить в конфигурацию еще один документ, который будет фиксировать перемещение материалов между основным складом и материально ответственными лицами. И очевидно, нам придется переработать все отчеты, которые были нами созданы к этому моменту, с тем, чтобы они учитывали изменения, вносимые новым документом. А представьте, если в нашей конфигурации не два, а двадцать документов?!
Во-вторых, отчеты, анализирующие документы, будут работать довольно медленно, что будет вызывать раздражение пользователей и недовольство руководителей.
Поэтому в системе 1С:Предприятие есть несколько объектов конфигурации, которые позволяют создавать в базе данных структуры, предназначенные для накопления информации в удобном для последующего анализа виде. [83]
Использование таких "хранилищ" данных позволяет нам с одной стороны накапливать в них данные, поставляемые различными документами (или другими объектами базы данных), а с другой стороны легко создавать нужные нам отчеты или использовать эти данные в алгоритмах работы конфигурации.

В конфигурации существует несколько объектов, называемых регистрами, для описания подобных "хранилищ". Сейчас мы рассмотрим один из них. [84]
1С-Предприятие 8.0. Использование основных объектов конфигурации
Зададим имя пользователя "Администратор", полное имя тоже "Администратор". Перейдем на закладку "Прочие".

[390]
Отметим роль "Администратор", основным интерфейсом укажем "Администратор" и язык конфигурации выберем "Русский".
После этого создадим остальных пользователей системы. Для всех них мы будем использовать аутентификацию Windows и русский язык:

Обратите внимание, что главному бухгалтеру Назаровой поставлены в соответствие две роли: "Расчетчик" и "Бухгалтер", поскольку она должна иметь возможность не только вести бухгалтерский учет, но и рассчитывать зарплату.
Список пользователей, зарегистрированных в системе, можно получить, выполнив команду Действия

Теперь вы можете зайти в нашу информационную базу под различными пользователями и посмотреть, чем отличаются внешний вид интерфейса и возможности различных пользователей. [391]
Администрирование работы пользователей
Для того, чтобы иметь возможность отличать друг от друга пользователей, работающих с информационной базой, в системе 1С:Предприятие существует режим ведения списка пользователей.
В этом режиме администратор базы имеет возможность создавать и удалять пользователей системы, назначать им интерфейсы и роли и т.д.
Прежде чем мы приступим к созданию списка пользователей, необходимо выполнить обновление конфигурации базы данных, поскольку пользователю можно поставить в соответствие только тот интерфейс, и те роли, которые существуют в конфигурации базы данных.
После того, как обновление произведено, выполним команду Администрирование

Пока что он пуст, поэтому добавим нового пользователя (Действия


Имя пользователя - это идентификатор, который будет появляться в окне выбора пользователей при запуске системы в режиме 1С:Предприятие. [389]
Полное имя - строка, которая может быть использована внутри конфигурации при выводе различной справочной информации Хорошим стилем администрирования считается указание в качестве полного имени - фамилии, имени и отчества пользователя (без сокращений).
Следующие две области окна посвящены способам аутентификации пользователя.
Аутентификация средствами 1С:Предприятия подразумевает, что после запуска системы пользователю будет предложено выбрать имя одного из пользователей системы и ввести пароль. Если введенный пароль соответствует тому, который сохранен в системе для этого идентификатора пользователя, система открывается с правами и интерфейсом, которые указаны для этого пользователя.
Аутентификация Windows подразумевает, что при запуске системы 1С:Предприятие от пользователя не требуется никакой дополнительной информации. Система 1С:Предприятие определяет под каким пользователем запущена операционная система Windows (имеет смысл использовать для NT-подобных операционных систем: NT, 2000, XP), и затем обращается к своему списку пользователей. Если она находит в нем пользователя, которому поставлен в соответствие текущий пользователь Windows, система открывается с правами и интерфейсом, которые указаны для этого пользователя.
Анализ данных
Объект анализ данных имеет возможность настройки колонок источника данных и указания параметров анализа. Каждый тип анализа подразумевает свою структуру исходных данных и свой набор параметров анализа.
Автоматическое заполнение цены в документе ОказаниеУслуги
Итак, задача, которая перед нами стоит, заключается в следующем. При создании документа "ОказаниеУслуги" нам необходимо обеспечить автоматическое заполнение поля "Цена" после того, как пользователь выберет услугу. Причем цена услуги должна определяться исходя из даты создаваемого документа.
Найдем в конфигураторе документ "ОказаниеУслуги" и откроем его форму "ФормаДокумента". Откроем свойства поля ввода, расположенного в колонке "Номенклатура" и внизу списка найдем событие "При изменении". Нажмем на кнопку с лупой и в открывшейся заготовке обработчика события напишем следующий текст:
Процедура ПереченьНоменклатурыНоменклатураПриИзменении(Элемент)
//получить текущую строку табличной части
СтрокаТабличнойЧасти = ЭлементыФормы.ПереченьНоменклатуры.ТекущиеДанные;
//установить цену
СтрокаТабличнойЧасти.Цена = РозничнаяЦена(Дата, Элемент.Значение);
//пересчитать сумму строки
РассчитатьСумму(СтрокаТабличнойЧасти);
КонецПроцедуры
Прокомментируем содержимое обработчика.
Первая строка обработчика вам уже знакома - мы получаем текущую строку табличной части документа, так как она нам понадобится в дальнейшем.
Во второй мы устанавливаем полученную цену в документе, вызывая нашу процедуру "РозничнаяЦена". Первым параметром мы передаем дату документа, на которую необходимо получить цену, а вторым параметром мы передаем ссылку, которую отображает элемент управления формой, вызвавший это событие (Элемент.Значение), т.е. ссылку на элемент справочника "Номенклатура". [126]
В заключение мы вызываем нашу процедуру "РассчитатьСумму" из общего модуля "РаботаСДокументами" для того, чтобы она пересчитала итоговую сумму в строке нашего документа.
Проверим, как теперь работает наш документ. Запустим 1С:Предприятие в режиме отладки и откроем регистр сведений "Цены". Для транзистора Philips добавим следующим числом новую цену:

Теперь откроем документ ОказаниеУслуги №1. Как вы помните, этим документом мы как раз "израсходовали" один такой транзистор.
Установим дату документа равной той дате, когда было задано первое значение цены транзистора, и повторим выбор транзистора в колонке "Номенклатура" табличной части документа. Автоматически установится первое значение цены:

[127]
Теперь изменим дату документа на следующий день и снова повторим выбор транзистора. Будет установлено новое значение цены:

Таким образом, в документ подбирается актуальная, на момент создания документа, цена услуги. [128]
Часть II. Использование основных объектов конфигурации
Обратите внимание, что, по большому счету, вы уже можете самостоятельно создавать приложения. Это действительно так, потому что наша учебная конфигурация уже имеет все основные блоки, необходимые для организации учета OOO "На все руки мастер".
В самом деле, мы можем описать предметы учета, можем отразить факты движения этих предметов, можем накопить информацию о движениях и даже можем представить эту информацию в виде некоторой выходной формы.
Поэтому все дальнейшее изложение, грубо говоря, будет посвящено тому, как "приблизить" эту систему учета к реальным потребностям ООО "На все руки мастер". [117]
Дерево решений
Тип анализа АнализДанныхДеревоРешении дерево решений позволяет построить иерархическую структуру классифицирующих правил, представленную в виде дерева.
Для построения дерева решений необходимо выбрать целевой атрибут, по которому будет строиться классификатор и ряд входных атрибутов, которые будут использоваться для создания правил. Целевой атрибут может содержать, например информацию о том, перешел ли клиент к другому поставщику услуг, удачна ли была сделка, качественно ли была выполнена работа и т.д. Входными атрибутами, для примера, могут выступать возраст сотрудника, стаж его работы, материальное состояние клиента, количество сотрудников в компании и т.п.
Результат работы анализа представляется в виде дерева, каждый узел которого содержит некоторое условие. Для принятия решения к [462] какому классу следует отнести некий новый объект, необходимо отвечая на вопросы в узлах пройти цепочку от корня до листа дерева, переходя к дочерним узлам в случае утвердительного ответа и к соседнему узлу в случае отрицательного.
Набор параметров анализа позволяет регулировать точность полученного дерева.
Типы колонок источника данных:
| · | Неиспользуемая - колонка не используется в анализе, |
| · | Входная - колонка будет использоваться как атрибут для создания узлов дерева, содержит характеристику исследуемого объекта. |
| · | Прогнозируемая - колонка, содержащая классификацию. Например - признак того, что контрагент перешел к другому поставщику. |
Параметры:
| · | МинимальноеКоличествоСлучаев - (Число) - минимальное количество случаев в узле. |
| · | МаксимальнаяГлубина - (Число) - максимальная глубина дерева. |
| · | ТипУпрощения - (не упрощать, упрощать) - тип упрощения дерева решений. Упрощать или не упрощать построенное дерево решений. [463] |
Диаграмма Ганта
Диаграмма Ганта представляет собой диаграмму интервалов на шкале времени и отражает использование объектами (точками) ресурсов (серий). Чтобы проще было представить себе составные части диаграммы Ганта, изучим диаграмму, которая должна получиться в результате работы создаваемого нами отчета. [364]
Как мы уже говорили, эта диаграмма будет отображать для каждого сотрудника фактический период действия записи по каждому из видов расчета, имеющих место для этого сотрудника.

Итак, диаграмма Ганта представляет собой совокупность точек, серий и значений для каждой пары точка–серия. В нашем случае точками диаграммы являются сотрудники, а сериями - виды расчетов. Таким образом, для каждого сотрудника существует некоторое значение диаграммы по каждой из серий, то есть по каждому из видов расчета.
Значение диаграммы Ганта представляет собой специальный объект, который формируется системой автоматически на основании того, какие точки и какие серии определены для данной диаграммы. Этот объект является совокупностью (коллекцией) интервалов, т.е. может содержать не один, а несколько интервалов, которые соответствуют паре серия–точка (создаваемый по умолчанию объект ЗначениеДиаграммыГанта не содержит ни одного интервала). Разработчик может получить значение диаграммы, указав [365] интересующую его точку и серию, и затем добавить в коллекцию необходимое количество интервалов.
Все интервалы всех значений диаграммы располагаются с привязкой к единой оси времени, что дает возможность видеть их взаимное расположение.
Теперь объясним коротко последовательность наших дальнейших действий. В качестве исходных данных для построения такой диаграммы мы возьмем данные регистра расчета "Начисления" Каждая запись этого регистра уже содержит все необходимое для построения диаграммы: сотрудника, вид расчета, начало и конец интервала. Нам останется только средствами встроенного языка разместить все это в диаграмме. Итак, приступим.
Диаграмма
Диаграмма является элементом управления, предназначенным для размещения в таблицах и формах системы 1С:Предприятие диаграмм и графиков различного вида.
Логически диаграмма является совокупностью точек, серий и значений серий в точке:
Значениесерии в точке
Серия

Точка
[196]
Как правило, в качестве точек используются моменты или объекты, для которых мы получаем значения характеристик, а в качестве серий - характеристики, значения которых нас интересуют.
Например, диаграмма продаж видов номенклатуры по месяцам будет состоять из точек - месяцев, серий - видов номенклатуры и значений - оборотов продаж.
Диаграмма, как объект встроенного языка, имеет три области, которые позволяют управлять оформлением диаграммы - это область построения, область заголовка и область легенды:
Область построения Область заголовка
Область легенды
Диаграмма может быть вставлена в форму либо в табличный Документ. Заполнение диаграммы данными возможно двумя способами.
Во-первых, можно заполнить диаграмму данными автоматически. Для этого используется свойство диаграммы ИсточникДанных. В качестве источника данных диаграммы может выступать область табличного документа (если диаграмма вставлена в табличный Документ), либо таблица значений. Общее требование к источнику Данных - он должен поставлять диаграмме (кроме самих данных) [197] имена точек и серий. В случае с областью табличного документа имена точек и серий будут браться из верхней строки и левого столбца области; в случае с таблицей значений - из заголовков колонок и первой колонки.
Во-вторых, диаграмма может быть заполнена данными "вручную". Для этого нужно создать в диаграмме несколько серий и точек, а затем, используя метод УстановитьЗначение(), задать нужные значения для каждой пары серия - точка.
Следует отметить, что эти два способа заполнения диаграммы не могут комбинироваться.
В следующем примере мы будем использовать диаграмму, расположенную в форме и заполнять ее данными "вручную", используя метод УстановитьЗначение().
Добавление движений по регистру бухгалтерии Управленческий в документ ОказаниеУслуги
Для того чтобы добавить движения по регистру Управленческий в документ "ОказаниеУслуги", нам уже не удастся воспользоваться конструктором движений. Если вы помните, движения этого документа мы создавали самостоятельно, без использования конструктора.
В отличие от документа "ПриходнаяНакладная", который создавал всего одну бухгалтерскую проводку, документ "ОказаниеУслуги" будет создавать уже две проводки:

Напомним, что бухгалтерия нашего OOO "На все руки мастер" не совсем похожа на "настоящую" бухгалтерию, потому что для облегчения своей работы она учитывает только движения материалов. Услуги, которые оказывает ООО, для нее как бы не существуют. Поэтому документ "ОказаниеУслуги" должен формировать движения по регистру бухгалтерии только в той части, которая касается расходования материалов.
Откроем в конфигураторе модуль объекта конфигурации Документ "ОказаниеУслуги" и найдем в нем процедуру обработки проведения. Она должна иметь следующий вид:
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("СкладВДокументе",Склад);
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Запрос.Текст =
"ВЫБРАТЬ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
| ОказаниеУслугиПереченьНоменклатуры.Количество,
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| ОказаниеУслугиПереченьНоменклатуры.Сумма, [307]
| ОстаткиМатериаловОстатки.КоличествоОстаток,
| СтоимостьМатериаловОстатки.СтоимостьОстаток,
| ОстаткиМатериаловОстаткиНаСкладе. КоличествоОстаток КАК КоличествоОстатокНаСкладе
|ИЗ
| Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК СтоимостьМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = СтоимостьМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(
| &МоментВремени,
| Материал В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура
| ИЗ
| Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка)) КАК ОстаткиМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = ОстаткиМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(
| &МоментВремени,
| Материал В (&СписокНоменклатурыДокумента)
| И Склад = &СкладВДокументе) КАК ОстаткиМатериаловОстаткиНаСкладе
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = ОстаткиМатериаловОстаткиНаСкладе.Материал
|ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
|
|ДЛЯ ИЗМЕНЕНИЯ
| РегистрНакопления.ОстаткиМатериалов.Остатки,
| РегистрНакопления.СтоимостьМатериалов.Остатки";
Иначе
Запрос.Текст =
"ВЫБРАТЬ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
| ОказаниеУслугиПереченьНоменклатуры.Количество,
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| ОказаниеУслугиПереченьНоменклатуры.Сумма,
| ОстаткиМатериаловОстатки.КоличествоОстаток,
| СтоимостьМатериаловОстатки.СтоимостьОстаток
|ИЗ
| Документ.ОказаниеУслуги. ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК [308] СтоимостьМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = СтоимостьМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК ОстаткиМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = ОстаткиМатериаловОстатки.Материал
|ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
|
|ДЛЯ ИЗМЕНЕНИЯ
| РегистрНакопления.СтоимостьМатериалов.Остатки,
| РегистрНакопления.ОстаткиМатериалов.Остатки";
КонецЕсли;
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("СписокНоменклатурыДокумента", ПереченьНоменклатуры.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("Ссылка",Ссылка);
ВыборкаРезультатаЗапроса = Запрос.Выполнить().Выбрать();
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
// Проверить остаток при оперативном проведении
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Остаток = ?(ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе = Null, 0, ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе);
Если Остаток < ВыборкаРезультатаЗапроса.Количество Тогда
Сообщить("Материала " + СокрЛП(ВыборкаРезультатаЗапроса.Номенклатура) + " имеется только " + Остаток);
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецЕсли;
//Сформировать движения
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата; [309]
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
// регистр СтоимостьМатериалов Расход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
//расчитать стоимость материала
СтоимостьМатериала = ?(ВыборкаРезультатаЗапроса.КоличествоОстаток = Null, 0,
ВыборкаРезультатаЗапроса.СтоимостьОстаток / ВыборкаРезультатаЗапроса.КоличествоОстаток);
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
КонецЕсли;
// регистр Продажи
Движение = Движения.Продажи.Добавить();
Движение.Период = Дата;
Движение.Номенклатура = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Клиент = Клиент;
Движение.Мастер = Мастер;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
Движение.Выручка = ВыборкаРезультатаЗапроса.Сумма;
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
Иначе
Движение.Стоимость = 0;
КонецЕсли;
КонецЦикла;
// записать движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Продажи.Записать();
КонецПроцедуры
Добавим движения по регистру бухгалтерии Управленческий:
//Сформировать движения
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
// регистр СтоимостьМатериалов Расход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
// расчитать стоимость материала
СтоимостьМатериала = ?(ВыборкаРезультатаЗапроса.КоличествоОстаток = Null, 0,
ВыборкаРезультатаЗапроса.СтоимостьОстаток / ВыборкаРезультатаЗапроса.КоличествоОстаток);
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
//По регистру Управленческий
//первая проводка:
//Д 62(ДебиторскаяЗадолженность) - К 90 (Капитал)
//розничная сумма
Движение = Движения.Управленческий.Добавить();
Движение.СчетДт = ПланыСчетов.Основной.ДебиторскаяЗадолженность;
Движение.СчетКт = ПланыСчетов.Основной.Капитал;
Движение.Период = Дата;
Движение.Сумма = ВыборкаРезультатаЗапроса.Сумма;
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконто.Клиенты] = Клиент;
//вторая проводка:
//Д90 (Капитал) - К 41 (Товары) - себестоимость
Движение = Движения.Управленческий.Добавить();
Движение.СчетДт = ПланыСчетов.Основной.Капитал;
Движение.СчетКт = ПланыСчетов.Основной.Товары;
Движение.Период = Дата;
Движение.Сумма = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество; [311]
Движение.КоличествоКт = ВыборкаРезультатаЗапроса.Количество;
Движение.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконто.Материалы] = ВыборкаРезультатаЗапроса.Номенклатура;
КонецЕсли;
...
// записать движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Продажи.Записать();
Движения.Управленческий.Записать();
КонецПроцедуры
Во второй проводке мы указываем стоимость материала, количество и субконто кредита, поскольку на счете "Товары" ведется количественный учет в разрезе материалов.
Запустим 1С:Предприятие в режиме отладки, перепроведем документ ОказаниеУслуги №1 и посмотрим, какие движения он сформировал по регистру бухгалтерии "Управленческий":

После этого перепроведем остальные документы Оказание услуги.
Доработка документа ПриходнаяНакладная
Последнее, что нам осталось - доработать документ "ПриходнаяНакладная". Для того чтобы при приходовании товаров пользователь мог указывать набор свойств для каждого приходуемого материала, добавим в табличную [271] часть документа новый реквизит "НаборСвойств" с типом СправочникСсылка.ВариантыНоменклатуры:

После этого расположим этот реквизит в табличном поле формы документа (правая кнопка мыши– Размещение данных):

Для поля ввода, расположенного в колонке "НаборСвойств" снова воспользуемся свойством "Связь по владельцу" ЭлементыФормы.Материалы.ТекущиеДанные.Материал. Теперь при выборе в этом поле ввода будет всегда открываться список [272] элементов справочника "ВариантыНоменклатуры", подчиненных материалу, выбранному в колонке "Материал".
В заключение откроем процедуру обработки проведения в модуле документа и добавим к формируемым движениям присвоение значения измерению "НаборСвойств":
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр ОстаткиМатериалов Приход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.НаборСвойств = ТекСтрокаМатериалы.НаборСвойств;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаМатериалы.Количество;
//КонецЦикла;
//Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр СтоимостьМатериалов Приход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Стоимость = ТекСтрокаМатериалы.Сумма;
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Доработка объектов конфигурации, участвующих в обмене
Первое, что нам следует сделать - внести изменения в модули всех объектов, участвующих в обмене (в нашем случае это будут документы, справочники и планы видов характеристик). Эти изменения будут заключаться в том, что теперь при формировании номера документа и кода справочника или плана видов характеристик будет использоваться значение константы "ПрефиксНумерации" для обеспечения уникальности номеров и кодов в каждой из наших баз.
Функцию формирования префикса номера мы вынесем в общий модуль, поскольку не исключена возможность того, что в будущем алгоритм формирования префикса документов может быть изменен. [401]
Функцию мы разместим в общем модуле "ОбменДанными", выглядеть она будет следующим образом:
Возврат Константы.ПрефиксНумерации.Получить();
КонецФункции
Теперь доработаем справочник "Клиенты". В модуль объекта добавим следующий обработчик события "ПриУстановкеНовогоКода":
Префикс = ПопучитьПрефиксНомера();
КонецПроцедуры
Такие же обработчики нужно будет добавить во все справочники и планы видов характеристик, участвующие в обмене. После этого у всех справочников и планов видов характеристик, участвующих в обмене, нужно будет изменить тип кода на Строка и увеличить длину кода до 7 символов.
Теперь займемся доработкой документов. В модуль документа "ПриходнаяНакладная" добавим обработчик события "ПриУстановкеНовогоНомера":
Префикс = ПопучитьПрефиксНомера();
КонецПроцедуры [402]
На этом подготовительная работа с существующими объектами конфигурации завершена, и мы можем перейти к созданию процедур обмена данными.
Доработка регистра ОстаткиМатериалов
Для того чтобы обеспечить учет материалов по значениям характеристик нам нужно будет изменить структуру регистра накопления "ОстаткиМатериалов" и добавить в него новое измерение "НаборСвойств" с типом СправочникСсылка.ВариантыНоменклатуры:

Доработка справочника Номенклатура
Прежде всего, в справочнике "Номенклатура" нам нужно обеспечить возможность редактирования варианта материала. Для этого укажем, что справочник "Номенклатура" будет редактироваться теперь обоими способами, в списке и в диалоге, и создадим основную форму элемента при помощи конструктора. Немного раздвинем форму по ширине и высоте и добавим в нее панель (Форма



[261]
После того, как мы слегка изменим положение любой из границ панели, появится вопрос:

На этот вопрос мы ответим утвердительно, и все элементы управления переместятся в добавленную панель:

[262]
Теперь мы скорректируем размеры панели и добавим в нее новую страницу (добавление страницы - контекстное меню правой кнопки мыши на поле формы


Зададим имя и заголовок новой страницы - "Свойства", а первую страницу также переименуем в "Основные" и зададим ей такой же заголовок (группа свойств "Текущая страница" в палитре свойств формы):

[263]
После этого выделим все элементы управления, расположенные на панели, и выполним команду Форма



Теперь перейдем на страницу "Свойства" и добавим надпись "НадписьВариантыНоменклатуры" с заголовком "Варианты номенклатуры:". Укажем для нее начертание шрифта "Жирный".

[264]
Под этой надписью расположим табличное поле с командной панелью с именем "Варианты" и типом СправочникСписок.ВариантыНоменклатуры. Из табличного поля удалим колонку "Код". Для этого табличного поля установим свойство "Связь по владельцу" - СправочникОбъект.Ссылка:

Установка этого свойства будет обеспечивать нам то, что для источника данных этого поля - реквизита формы "Варианты", имеющего тип СправочникСписок.ВариантыНоменклатуры, - значение отбора по владельцу всегда будет равно ссылке на редактируемый элемент справочника "Номенклатура". Иными словами, список справочника, содержащийся в реквизите формы "НаборСвойств" всегда будет содержать только элементы, подчиненные редактируемому элементу справочника "Номенклатура". А значит и табличное поле "Варианты", для которого этот реквизит является источником данных, будет отображать только элементы, подчиненные редактируемому элементу справочника "Номенклатура".[265]
Ниже разместим аналогичным образом еще одну надпись "НадписьЗначенияСвойств" с заголовком "Значения свойств:" и начертанием шрифта "Жирный".:

[266]
Под ней расположим табличное поле с командной панелью с именем "Свойства" и типом РегистрСведенийСписок.ЗначенияСвойствНоменклатуры. Для колонки "НаборСвойств" снимем флаг "Видимость", а для поля ввода в колонке "Значение" установим связь по типу - ЭлементыФормы.Свойства.ТекущиеДанные.ВидСвойства:

Связь по типу будет обеспечивать нам то, что тип значений, вводимых в это поле ввода, будет ограничен только типом характеристики, выбранной в поле "Вид свойства". Однако этим мы никак не можем повлиять на само значение, хранимое в этом поле. Если не предпринять никаких дополнительных действий, то получится, что в случае, когда в поле "Значение" было введено какое-либо значение, поменять его на значение другого вида характеристики не удастся. При выборе другого вида характеристики будет возникать несоответствие между типом хранимого значения и типом, которым ограничен ввод в элементе управления. В этом случае, естественно, система будет предлагать вводить тот тип, который имеет хранимое значение.[267]
Чтобы избежать такой ситуации, нам нужно будет при смене значения в поле "Вид свойства" привести значение поля "Значение" к типу характеристики, выбранной в поле "Вид свойства".
Поэтому для поля ввода в колонке "Вид свойства" создадим обработчик события "При изменении":
ДанныеВидСвойства = ЭлементыФормы.Свойства.ТекущиеДанные.ВидСвойства;
ЭлементыФормы.Свойства.ТекущиеДанные.Значение = ДанныеВидСвойства.ТипЗначения.ПривестиЗначение(ЭлементыФормы.Свойства.ТекущиеДанные.Значение);
КонецПроцедуры
Поэтому для табличного поля "Варианты" создадим обработчик события "При активизации строки":
ЭлементыФормы.Свойства.Значение.Отбор.НаборСвойств.Установить(Элемент.ТекущиеДанные.Ссылка, Истина);
КонецПроцедуры
ЭлементыФормы.Свойства.Значение.Отбор.НаборСвойств.Установить(,Истина);
КонецПроцедуры [268]
Прежде всего, создадим обработчик события

О событиях, связанных с формой, можно прочитать в главе "События, связанные с формой" на странице 547.
Cвойства.Отбор.HaбopCвойств.Установить(Cсылка,"Истина");
КонецПроцедуры
Поэтому создадим обработчик события табличного поля "ПередНачаломДобавления":
Если ЭтоНовый() Тогда
Записать();
КонецЕсли;
КонецПроцедуры
Доработка справочника ВариантыНоменклатуры
Теперь нам следует доработать справочник "ВариантыНоменклатуры" таким образом, чтобы пользователь имел возможность создавать новые свойства материалов не только при редактировании самого материала, но и в процессе ввода документов, когда в табличную часть подбирается набор свойств.
Поэтому для справочника "ВариантыНоменклатуры" укажем, что он будет редактироваться обоими способами (как в списке, так и в диалоге) и создадим с помощью конструктора основную форму элемента.
Доработка формы элемента справочника "ВариантыНоменклатуры" будет сводиться, по большому счету, к тем же действиям, которые мы выполнили с формой справочника "Номенклатура". В форме нам нужно будет расположить табличное поле, которое должно отображать существующие в регистре сведений записи о значениях свойств для этого элемента справочника.
Откроем основную форму элемента справочника "ВариантыНоменклатуры" и раздвинем форму вниз. На освободившемся пространстве поместим табличное поле с именем "Свойства", типом РегистрСведенийСписок.ЗначенияСвойствНоменклатуры и командной панелью. Для колонки "НаборСвойств" снимем флаг видимости:

[269]
Затем для поля ввода, расположенного в колонке "Значение" зададим связь по типу ЭлементыФормы.Свойства.ТекущиеДанные.ВидСвойства.
Для поля ввода, расположенного в колонке "ВидСвойства" создадим обработчик события "ПриИзменении":
Процедура СвойстваВидСвойстваПриИзменении(Элемент)
ДанныеВидСвойства = ЭлементыФормы.Свойства.ТекущиеДанные.ВидСвойства;
ЭлементыФормы.Свойства.ТекущиеДанные.Значение = ДанныеВидСвойства.ТипЗначения.ПривестиЗначение(ЭлементыФормы.Свойства.ТекущиеДанные.Значение);
КонецПроцедуры
Теперь необходимо сделать так, чтобы при открытии формы устанавливался нужный нам отбор, а также, в случае, если мы добавляем новый элемент справочника, чтобы отбор устанавливался и после того, как элемент будет записан. Для этого мы воспользуемся возможностью назначения обработчика события изменения данных, который будет отслеживать изменения ссылки на редактируемый элемент справочника.
Периодический регистр сведений
В этой главе мы с вами познакомимся с объектом конфигурации Регистр сведений, а точнее с одним из его видов - периодическим регистром сведений. Вы узнаете, для чего предназначен этот объект конфигурации, и какова его структура.
Мы создадим с вами один периодический регистр сведений, который будет использоваться в нашей конфигурации, и покажем, каким образом можно использовать его данные средствами встроенного языка. [118]
Использование регистра расчета
Теперь у нас все готово для того, чтобы начать разработку системы расчета заработной платы OOO "На все руки мастер". В этой главе мы создадим документ, с помощью которого будут выполняться различные виды начислений, посмотрим, как и когда платформа формирует записи перерасчета, увидим, как работают механизмы вытеснения по периоду действия и зависимости по базовому периоду.
Кроме этого мы создадим отчет, показывающий начисления сотрудникам OOO "На все руки мастер" и сделаем так, чтобы данные расчетов можно было поддерживались в актуальном состоянии.
В заключение мы познакомимся с новым элементом управления - Диаграмма Ганта, и с его помощью наглядно проиллюстрируем работу некоторых механизмов расчета.[340]
Подсистема
В этой главе мы познакомимся с объектом конфигурации Подсистема и узнаем, какие полезные возможности предоставляет разработчику использование этого объекта. [372]
Интерфейс, роль, список пользователей
После того, как созданы все основные объекты конфигурации можно приступить к определению ролей пользователей и созданию интерфейсов.
До сих пор мы с вами использовали пункт меню "Операции", для того, чтобы получить доступ к тому или иному объекту конфигурации. Нам были доступны абсолютно все объекты конфигурации, и мы могли осуществлять с ними все доступные действия.
Однако при реальной работе пользователей одной из главных возможностей, которую должно обеспечивать прикладное решение, является разграничение прав доступа пользователей к той или иной информации, хранящейся в информационной базе.
Например, руководитель должен, очевидно, иметь доступ ко всей информации, которая содержится в базе данных, а вот кладовщик - напротив, должен иметь доступ только к информации, касающейся движения товаров на складах и не иметь возможности просматривать бухгалтерскую или кадровую информацию.
Кроме этого, должна существовать возможность ограничить пользователей в выполнении тех или иных действий с объектами базы данных. Например, кладовщик может создавать и изменять приходные накладные, поскольку он отвечает за учет материалов на предприятии. Мастеру может понадобиться просматривать приходные накладные для того, чтобы знать, какие материалы и когда были получены. Однако мастер не должен иметь возможности вносить какие-либо изменения в приходные накладные.[378]
Обмен данными
В этой главе мы познакомимся с механизмами обмена данными, которые содержит система 1С:Предприятие и добавим в нашу конфигурацию возможность обмена данными с удаленными филиалами и отделениями. [393]
Анализ и прогнозирование данных
В этой главе мы познакомимся с возможностями, которм предоставляет система 1С:Предприятие 8.0 для поиска и анализ закономерностей в имеющихся данных, и построения прогнозов на основе найденных закономерностей.
Следует заметить, что наше изложение будет касаться лищь непосредственно тех механизмов, которые реализованы в платформе 1С:Предприятия 8.0. Для получения базовой теоретической информации по методам анализа данных, соответствующим реализованным моделям, следует обратиться к специальной литературе. Мы полагаем, что разработчик, приступающий к анализу данных, уже владеет необходимыми теоретическими знаниями.
Поскольку анализ данных подразумевает наличие большого объема исходной информации, для всех примеров, рассматриваемых далее, мы будем использовать не информационную базу нашего OOO "На все руки мастер", а некую абстрактную базу данных, которая позволит проиллюстрировать работу анализа и прогнозирования данных.
На диске информационно- технологического сопровождения, в составе демонстрационной конфигурации "Анализ данных", вы можете найти универсальную обработку "Консоль анализа данных", которая позволит вам работать с анализом данных в любом прикладном решении без какого-либо программирования. [444]
Создание документа ввода начальных остатков
В нашей информационной базе, как, впрочем, и в любой другой, обязательно следует предусмотреть возможность ввода начальных остатков в регистры. Это необходимо для того, чтобы пользователи могли начать работу с нашей информационной базой не с "чистого листа", а с некоторого "исходного состояния", которое было в их прежней системе учета (пусть даже они вели учет на бумаге).
Задача ввода начальных остатков отличается от прочих алгоритмов изменения состояния регистров нашей информационной базы тем, что подразумевает изменение данных непосредственно в регистрах, без использования каких-либо промежуточных алгоритмов (заполнения документов данными, проведения документов, контроля правильности данных, указанных в документах и пр.).
Рассмотрим пример ввода начальных остатков регистра накопления "ОстаткиМатериалов". Для выполнения этой задачи мы создадим документ, в котором будем вручную редактировать его движения по регистру "ОстаткиМатериалов" прямо в форме документа.
Откроем конфигуратор и создадим новый объект конфигурации Документ с именем "ВводНачальныхОстатковНоменклатуры". На закладке "Движения" запретим проведение документа (поскольку сами будем формировать записи регистра), и отметим, что движения документа будут находиться в регистре накопления "ОстаткиМатериалов". После этого перейдем на закладку "Формы" и создадим основную форму документа. [477]
Раздвинем форму вниз и разместим в ней табличное поле c командной панелью. Зададим имя табличного поля "ОстаткиМатериалов" и тип значения "РегистрНакопленияНаборЗаписей.ОстаткиМатериалов":

В свойствах табличного поля укажем, что источником данных для него будут являться движения документа по регистру "ОстаткиМатериалов":

[478]
Удалим из табличного поля колонки "Регистратор" и "Активность" (они нам не понадобятся), и изменим размеры формы и расположение элементов управления:

Запустим 1С:Предприятие в режиме отладки и проверим работу нашего документа.
Введем в документ следующие данные:

Обратите внимание на то, что дата документа не совпадает с датами отдельных записей, которые мы создаем в движениях документа. [479]
Нажмем "Записать", и из формы списка документа откроем движения нашего документа в регистре "ОстаткиМатериалов" (кнопка "Перейти").
Вы видите, что записи регистра накопления в точности соответствуют тем, которые мы создали в документе:

Таким образом, мы добились поставленной цели: с одной стороны, задавая дату документа, мы можем фиксировать момент внесения изменений в записи регистра, с другой стороны - для каждой создаваемой нами записи регистра, мы можем указать индивидуальное значение поля "Период".
Теперь займемся "ужесточением" требований, предъявляемых к тому, как наш документ формирует записи регистра, и рассмотрим два типичных варианта.
Первое требование, которое мы реализуем, будет заключаться в том, что записи регистра должны формироваться той же датой, что и дата документа. Иначе говоря, синхронизируем дату движений с датой документа.
Для этого в обработчик события "Перед записью" формы документа добавим следующий текст:
Для Каждого ЗаписьРегистра Из Движения.ОстаткиМатериалов Цикл
ЗаписьРегистра.Период = Дата;
КонецЦикла;
КонецПроцедуры [480]

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


Легким движением брюки превращаются...
Вот мы и создали с вами небольшое прикладное решение, которое позволило автоматизировать работу нашей ремонтной фирмы OOO "На все руки мастер". Теперь настало время для одного чудесного превращения.
Дело в том, что наше прикладное решение настолько понравилось сотрудникам OOO "На все руки мастер", что они рассказали о нем своим соседям - косметическому салону "Королева красоты". Сотрудники салона посмотрели, как работает наше прикладное решение, и обратились к нам с просьбой автоматизировать и их салон тоже.
И мы, конечно же, с радостью согласились, по одной простой причине: мы с вами создали универсальную конфигурацию, подходящую для автоматизации практически любой деятельности, связанной с оказанием услуг.
Все, что нам осталось теперь сделать, чтобы наша конфигурация смогла работать в косметическом салоне, - просто создать новую информационную базу с нашей конфигурацией, и заполнить ее новыми данными, - сотрудниками и новой номенклатурой. Все механизмы учета, которые мы с вами создавали, не были привязаны к какой-либо специфике конкретного предприятия, а потому могут с успехом использоваться на любом другом предприятии, имеющем аналогичную область деятельности.
Таким образом, даже если в косметическом салоне пожелают иметь дополнительную функциональность, нам потребуется всего лишь дописать несколько модулей к нашей конфигурации, что гораздо эффективнее, чем создавать заново индивидуальное решение только для данного предприятия.[485]


Перечисление
До сих пор мы с вами не обращали внимания на то, что у нас нет никакого признака, по которому мы могли бы сказать, чем является конкретный элемент справочника "Номенклатура": материалом или услугой. To, что все элементы справочника разложены у нас по некоторым группам, не может являться надежным критерием оценки: группы можно удалить, переименовать, сгруппировать элементы по другим принципам...
Поэтому нам требуется некоторый признак, позволяющий однозначно определять принадлежность элемента справочника к материалам или услугам, независимо от изменения иерархической структуры справочника.
В этой главе мы создадим у справочника "Номенклатура" специальный реквизит, тип значения которого образуется новым пока еще для нас объектом конфигурации Перечисление. Это поможет нам в дальнейшем легко определять, чем является элемент справочника "Номенклатура": услугой или материалом. Кроме этого, мы скорректируем процедуру проведения документа ОказаниеУслуги и покажем, как работать с перечислением средствами встроенного языка. [130]
Проведение документа по нескольким регистрам
Эта глава будет посвящена тому, как один и тот же документ может "поставлять" информацию в различные регистры конфигурации и для чего может понадобиться такая возможность.
В ходе изучения этой главы мы создадим еще один регистр накопления нашей конфигурации и изменим процедуру проведения документов так, чтобы они записывали необходимые данные как в один, так и в другой регистр и подготовим базу для изучения следующей главы. [138]
Оборотный регистр накопления
В этой главе мы с вами познакомимся с еще одним видом регистра накопления - оборотным регистром накопления.
Вы узнаете о некоторых важных принципах выбора измерений и реквизитов регистров накопления. Мы с вами создадим оборотный регистр накопления и добавим в один из наших документов движения еще и по этому регистру. [152]
Создание отчетов
Настало время, чтобы познакомиться ближе с одним мощным инструментом платформы 1С:Предприятие - конструктором выходной формы.
В этой главе мы рассмотрим построение нескольких отчетов, которые будут использоваться в нашей конфигурации, и на их примере объясним основные возможности конструктора выходной формы.
В основе конструктора выходной формы лежит использование механизма запросов, реализованного в платформе 1С:Предприятие. Поскольку каждый отчет, как правило, подразумевает получение сложной выборки данных, сгруппированных и отсортированных определенным образом, очевидно, что для этих целей лучше всего использовать запрос к информации базы данных. Поэтому при вызове конструктора выходной формы в него "встраивается" конструктор запроса, позволяющий визуальными средствами описать запрос, лежащий в основе отчета. Кроме создания текста запроса конструктор выходной формы помогает также создать форму и макет отчета.
Примечательной возможностью конструктора выходной формы является то, что он может создавать отчет, используя два различных объекта встроенного языка.
Во-первых, отчет может быть построен с использованием объекта встроенного языка Запрос. Такой вариант отчета является довольно простым и не предоставляет больших возможностей для настройки параметров созданного отчета.
Во-вторых, отчет может быть построен с использованием объекта встроенного языка ПостроительОтчета. В этом случае пользователь получает большие возможности по интерактивной настройке самого запроса, на основе которого строится отчет (например, он может определять состав выбранных полей и задавать условия отбора).
Мы начнем рассматривать примеры создания отчетов в более простом варианте - без использования объекта встроенного языка ПостроительОтчета, а после того, как будем обладать достаточными знаниями - рассмотрим несколько примеров, в которых будет использован ПостроительОтчета. [162]
Оптимизация процедуры проведения документа ОказаниеУслуги
После изучения предыдущей главы вы уже достаточно хорошо знакомы с языком запросов, и мы наконец-то можем приступить к одной из самых важных глав нашей книги - к оптимизации документа "ОказаниеУслуги", и в частности, к полному изменению его обработчика события "ОбработкаПроведения".
"Зачем это нужно?" - можете спросить вы. Тому есть две причины. Во-первых, руководство OOO "На все руки мастер" решило, наконец-то, завершить "эксперименты" по вводу стоимости расходуемых материалов руками и перейти на автоматический расчет стоимости расходуемых материалов "по среднему".
Во-вторых, в обработчике события "Обработка проведения" мы используем обращение к реквизиту "ВидНоменклатуры" справочника "Номенклатура" "через точку". Такое обращение может сильно замедлить скорость выполнения процедуры при больших объемах табличной части документа.
Поэтому, изменения, вносимые нами в документ "ОказаниеУслуги", будут преследовать две цели:
| · | определение стоимости расходуемых материалов при проведении документа, |
| · | повышение скорости выполнения процедуры. |
Прежде, чем мы приступим непосредственно к каким-либо действиям, следует сказать несколько слов об особенностях хранения и использования ссылочных данных в системе 1С:Предприятие 8.0.[232]
План видов характеристик
В этой главе мы познакомимся с новым объектом конфигурации - План видов характеристик - и узнаем, каким образом можно использовать этот объект для расширения возможностей нашей конфигурации.[252]
Бухгалтерский учет
В этой главе мы займемся тем, что проиллюстрируем возможность ведения бухгалтерского учета средствами 1С:Предприятия. Для этого мы используем уже знакомый нам план видов характеристик и два новых объекта конфигурации - план счетов и регистр бухгалтерии.
Регистр бухгалтерии будет использоваться нами для накопления данных о совершенных хозяйственных операциях. С помощью плана счетов мы будем описывать счета, в разрезе которых ведется учет, а план видов характеристик будет служить для описания объектов аналитического учета, в разрезе которых должен вестись учет на счетах.
Сразу оговоримся, что план счетов, который мы будем использовать в нашей учебной конфигурации, очень сильно упрощен. Он содержит всего несколько условных счетов, которые, однако, позволят нам познакомиться с основными методами организации бухгалтерского учета средствами 1С:Предприятия. [290]
План видов расчета, регистр расчета
В этой главе мы познакомимся с объектами конфигурации План видов расчета и Регистр расчета и узнаем об основных понятиях, используемых при создании сложных периодических расчетов.
В конце главы мы создадим план видов расчета и регистр расчета, на основе которых в следующих главах продемонстрируем работу механизмов периодических расчетов.[317]
Графическое представление начислений
В конце этой главы мы совместим приятное с полезным и создадим с вами отчет, который в графическом виде будет показывать нам фактический период действия записей расчета Помимо наглядной демонстрации работы механизма вытеснения записей по периоду действия этот отчет позволит нам познакомиться с элементом управления, позволяющим создавать диаграммы Ганта.
Иллюстрация механизмов вытеснения и зависимости от базы
Создадим новый объект конфигурации Отчет. Назовем его "Перерасчет". На закладке "Макеты" откроем конструктор выходной формы, и выберем следующие поля из виртуальной таблицы перерасчета "Начисления.Перерасчет":

На закладке "Отчет" сбросим флаг "Использовать построитель отчета" и нажмем "OK" - наш отчет готов.
Запустим 1С:Предприятие в режиме отладки, сформируем отчет "Перерасчет" и убедимся, что пока он не содержит никаких данных.
Создадим новый документ Начисление сотрудникам №2, в котором начислим премию за март Гусакову и Деловому:

[345]
Этим документом мы зафиксируем тот факт, что сотрудникам Гусакову и Деловому нужно начислить премию по итогам работы за март. Поскольку размер премии нам неизвестен (он будет рассчитываться по некоторому алгоритму), поля "Результат" мы оставляем пустыми. Нажмем "ОК".
Теперь снова откроем документ Начисление Сотрудникам №1 и изменим оклад Гусакова с 10 000 на 7 000. Нажмем "ОК". Сформируем отчет "Перерасчет":

Как видите, отчет теперь содержит какие-то данные. В самом деле, вид расчета "Премия" зависит у нас по базовому периоду от вида расчета "Оклад". Как только мы изменили существовавшие в регистре записи по виду расчета "Оклад" - платформа сразу же сформировала набор записей перерасчета, которые должны быть рассчитаны заново, т.к. изменилась их база.
Вы можете спросить: "почему в перерасчет попали записи как про Делового, так и про Гусакова, хотя оклад мы меняли только Гусакову"? Дело в том, что платформа не отслеживает конкретные изменения, которые пользователь внес в записи документа. Она отслеживает лишь факт изменения набора записей регистра расчета в результате проведения (перепроведения) документа. Поэтому в набор записей перерасчета она включает информацию о ВСЕХ записях регистра, значение ресурсов которых МОЖЕТ измениться в результате перепроведения документа, создавшего базовые записи регистра.
Перепроведем документ Начисления сотрудникам №2 (которым мы начисляли премию) и сформируем отчет "Перерасчет". Он снова не содержит никаких данных - система отметила тот факт, что MЫ "пересчитали" зависимые записи и очистила таблицу перерасчета. [346]
На этом примере мы с вами познакомились с тем, как работает механизм поддержки зависимости по базовому периоду у регистра расчета.
Теперь посмотрим, как работает механизм вытеснения по периоду действия. Для этого нам понадобится создать третий документ НачисленияСотрудникам №3:

Этим документом мы зафиксируем тот факт, что Гусаков не выходил на работу с 1 по 10 марта. Очевидно, что в этом случае потребуется пересчитать его оплату по окладу и, как следствие, начисленную премию.
Нажмем "ОК" и сформируем отчет "Перерасчет":

Как вы видите, в перерасчет попала запись о начислении оклада Гусакову. Это явилось результатом работы механизма вытеснения по [347] периоду действия, ведь вид расчета "Невыход" вытесняет у нас вид расчета "Оклад".
Обратите внимание, что в перерасчет попала и запись о начислении премии Гусакову. Если вы помните, при создании предопределенных видов расчета мы указали, что результат вида расчета премия будет зависеть от изменения результата вида расчета "Невыход". Эта зависимость косвенная, но поскольку явно указали такую зависимость платформа ее отследила.
Перепроведем документы Начисление сотрудникам №1 и №2 и убедимся, что таблица перерасчета очистилась. [348]
Использование построителя отчета в конструкторе выходной формы
В заключение этой главы мы рассмотрим некоторые из созданных нами только что отчетов, но построенные уже с использованием построителя отчета в конструкторе выходной формы.
Использование регистра бухгалтерии
Настало время познакомиться с тем, каким образом используется созданный нами регистр бухгалтерии "Управленческий". В этой главе мы, сначала, доработаем оба наши документа - "ПриходнаяНакладная" и "ОказаниеУслуги" - так, чтобы они "поставляли" данные не только для регистров накопления, но и для регистра бухгалтерии. Затем мы создадим бухгалтерский отчет "Оборотно-сальдовая ведомость", который будет показывать нам состояние товародвижения в нашем OOO "На все руки мастер", основываясь на данных регистра бухгалтерии.
Источники данных запросов
Исходную информацию запрос получает из набора таблиц. Эти таблицы представляют данные реальных таблиц базы данных в удобном для анализа виде. Их можно разделить на две большие группы: реальные и виртуальные.
Реальные таблицы, в свою очередь, могут быть объектными (ссылочными) или не объектными (не ссылочными):

Отличительной особенностью реальных таблиц является то, что они содержат данные какой-либо одной реальной таблицы, хранящейся в базе данных. Например, реальными таблицами являются таблица "Справочник.Клиенты", соответствующая справочнику "Клиенты" или таблица "РегистрНакопления.ОстаткиМатериалов", соответствующая регистру накопления "ОстаткиМатериалов".
Виртуальные таблицы формируются, в основном, из данных нескольких таблиц базы данных. Например, виртуальной таблицей является таблица "РегистрНакопления.ОстаткиМатериалов.ОстаткиИОбороты", формируемая из нескольких таблиц регистра накопления "ОстаткиМатериалов". Иногда виртуальные таблицы могут [163] формироваться и из одной реальной таблицы (например, виртуальная таблица "Цены.СрезПоследних" формируется на основе таблицы регистра сведений "Цены"). Однако общим для всех виртуальных таблиц является то, что им можно задать ряд параметров, которые будут определять, какие данные будут включены в эти виртуальные таблицы. Набор таких параметров может быть различным для разных виртуальных таблиц, и определяется данными, хранящимися в исходных таблицах базы данных.
Реальные таблицы подразделяются на объектные (ссылочные) и не объектные (не ссылочные).
В объектных (ссылочных) таблицах представлена информация ссылочных типов данных (справочники, документы, планы видов характеристик и т.д.). А в не объектных (не ссылочных) - всех остальных типов данных (константы, регистры и т.д.).
Отличительной особенностью объектных (ссылочных) таблиц является то, что они содержат поле "Ссылка", содержащее ссылку на текущую запись. Кроме этого для таких таблиц возможно получение пользовательского представления объекта, эти таблицы могут быть иерархическими и поля таких таблиц могут содержать вложенные таблицы (табличные части).
Изменение процедуры проведения документа ОказаниеУслуги
Если вы помните, в первой части книги, когда создавались движения документа "ОказаниеУслуги" по регистру накопления "ОстаткиМатериалов", мы сказали, что они не совсем правильные, поскольку в регистр будут попадать не только записи об израсходованных материалах, но и записи об оказанных услугах.
Теперь мы займемся тем, что доработаем документ таким образом, чтобы в регистре появлялись только записи, относящиеся к расходу материалов. Эта доработка будет не совсем эффективна с точки зрения производительности, зато позволит нам получить нужные данные в регистре "ОстаткиМатериалов".
Более эффективный вариант обработки проведения этого документа мы рассмотрим после изучения главы, рассказывающей о механизме запросов 1С:Предприятия 8.0.
Скорректируем движения документа, исключив из обработки те строки табличной части, в которых находятся услуги. Для этого в обработчик события "ОбработкаПроведения", расположенный в модуле документа "ОказаниеУслуги", добавим следующий текст (добавленный текст выделен жирным шрифтом):
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
Если ТекСтрокаПереченьНоменклатуры.Номенклатура.ВидНоменклатуры <> Перечисления.ВидыНоменклатуры.Материал Тогда
Продолжить;
КонецЕсли;
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Склад = Склад; [134]
Движение.Количество = ТекСтрокаПереченьНоменклатуры.Количество;
КонецЦикла;
// записываем движения регистров
Откроем в конфигураторе окно редактирования объекта конфигурации Документ "ПриходнаяНакладная" и перейдем на закладку "Движения". В списке регистров отметим, что документ будет создавать теперь движения и по регистру "СтоимостьМатериалов". Запустим конструктор движений, и согласимся с тем, что существующая процедура "ОбработкаПроведения" будет замещена.
Перед нами откроется окно конструктора движений, которое будет содержать созданные нами ранее движения документа по регистру "ОстаткиМатериалов". Добавим в список регистров, по которым формируются движения, еще один регистр - "СтоимостьМатериалов". Выберем для него ту же табличную часть "Материалы" и заполним выражения.
Для ресурса "Стоимость" выберем значения реквизита табличной части "Сумма":
Добавим в список регистров новый регистр...

[141]
Нажмем "ОК" и посмотрим на текст, который сформировал конструктор:
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр ОстаткиМатериалов Приход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаМатериалы.Количество;
КонецЦикла;
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр СтоимостьМатериалов Приход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Стоимость = ТекСтрокаМатериалы.Сумма;
И в заключение этой главы мы внесем изменения в процедуру обработки проведения документа "ОказаниеУслуги". На данном этапе мы будем исходить из пожелания, высказанного руководством OOO "На все руки мастер". Суть его заключается в том, что на первом этапе, при списании материалов, израсходованных в процессе оказания услуги, должна быть возможность указывать различную стоимость для одного и того же материала, которая рассчитана руководством исходя из текущих конъюнктурных соображений.
Поскольку в документе "ОказаниеУслуги" у нас отражена только цена номенклатуры, нам понадобится добавить в табличную часть документа еще одно поле, в котором будет указываться стоимость номенклатуры.
Откроем в конфигураторе окно редактирования объекта конфигурации Документ "ОказаниеУслуги", перейдем на закладку "Данные" и создадим новый реквизит табличной части документа с именем "Стоимость", типом Число, длиной 15 и точностью 2:

[145]
После этого откроем форму "ФормаДокумента" документа "ОказаниеУслуги" и добавим в табличное поле колонку, отображающую новый реквизит "Стоимость", расположив ее после колонки "Номенклатура":

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

Нажмем "ОК" и в тексте, сформированном конструктором, восстановим изменения, внесенные нами ранее, а также объединим два цикла обхода табличной части документа в один (изменения выделены жирным шрифтом):
На этот раз мы не будем использовать конструктор движений документа, а внесем необходимые дополнения прямо в обработчик события "ОбработкаПроведения" документа "ОказаниеУслуги".
Откроем в конфигураторе модуль объекта конфигурации документ "ОказаниеУслуги" и найдем в нем процедуру обработчика события "ОбработкаПроведения".
Создадим еще один цикл обхода табличной части и команду записи движений регистра (добавления выделены жирным шрифтом):
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл [157]
Если ТекСтрокаПереченьНоменклатуры.Номенклатура.ВидНоменклатуры <> Перечисления.ВидыНоменклатуры.Материал Тогда
Продолжить;
КонецЕсли;
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаПереченьНоменклатуры.Количество;
//КонецЦикла;
//Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
// регистр СтоимостьМатериалов Расход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Стоимость = ТекСтрокаПереченьНоменклатуры.Стоимость*ТекСтрокаПереченьНоменклатуры.Количество;
КонецЦикла;
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
Движения.ОстаткиМатериалов.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и проверим работу процедуры проведения документа "ОказаниеУслуги".
Откроем документ Оказание услуги №1 и внесем в него следующие изменения (обратите внимание, что изменен не только состав номенклатуры в табличной части, но и время документа):

Перед тем, как провести документ, откроем список регистра "ОстаткиМатериалов", содержащий движения этого документа. Для этого выполним команду Перейти

Проведем документ и убедимся, что в движения по регистру "ОстаткиМатериалов" включаются только строки, содержащие материалы:

[136]
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
В нашем случае табличная часть всего одна, поэтому можно объединить эти два цикла в один следующим образом (изменения выделены жирным):
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, [142] внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр ОстаткиМатериалов Приход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаМатериалы.Количество;
//КонецЦикла;
//Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр СтоимостьМатериалов Приход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Стоимость = ТекСтрокаМатериалы.Сумма;
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Затем откроем его и убедимся, что документ создает желаемые записи в регистрах накопления:



[144]
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
Если ТекСтрокаПереченьНоменклатуры.Номенклатура.ВидНоменклатуры <> Перечисления.ВидыНоменклатуры.Материал Тогда
Продолжить;
КонецЕсли;
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата; [147]
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаПереченьНоменклатуры.Количество;
//КонецЦикла;
//Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
// регистр СтоимостьМатериалов Расход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Стоимость = ТекСтрокаПереченьНоменклатуры.Стоимость*ТекСтрокаПереченьНоменклатуры.Количество;
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и укажем стоимость выбранных материалов:

[148]
Проведем документ Оказание услуги №1 и посмотрим на движения этого документа по регистру "СтоимостьМатериалов":

Теперь создадим и проведем еще два документа "ОказаниеУслуги". Эти документы понадобятся нам в дальнейшем, поэтому будьте внимательны и обратите внимание на то, что эти документы созданы другими датами:

[149]

Движения документов Оказание услуги №2 и №3 должны выглядеть, соответственно, следующим образом:


[150]
//регистр Продажи
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Продажи.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
Если ТекСтрокаПереченьНоменклатуры.Номенклатура.ВидНоменклатуры <> Перечисления.ВидыНоменклатуры.Материал Тогда
Продолжить;
КонецЕсли;
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаПереченьНоменклатуры.Количество;
//КонецЦикла;
//Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
// регистр СтоимостьМатериалов Расход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаПереченьНоменклатуры.Номенклатура;
Движение.Стоимость = ТекСтрокаПереченьНоменклатуры.Стоимость * ТекСтрокаПереченьНоменклатуры.Количество;
КонецЦикла;
Для Каждого ТекСтрокаПереченьНоменклатуры Из ПереченьНоменклатуры Цикл
//регистр Продажи
Движение = Движения.Продажи.Добавить();
Движение.Период = Дата;
Движение.Номенклатура = ТекСтрокаПереченьНоменклатуры.Номенклатура; [158]
Движение.Клиент = Клиент;
Движение.Мастер = Мастер;
Движение.Количество = ТекСтрокаПереченьНоменклатуры.Количество;
Движение.Выручка = ТекСтрокаПереченьНоменклатуры.Сумма;
Движение.Стоимость = ТекСтрокаПереченьНоменклатуры.Стоимость * ТекСтрокаПереченьНоменклатуры.Количество;
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Продажи.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и перепроведем все документы "Оказание услуги". Движения этих документов по регистру "Продажи" должны иметь следующий вид:
Движения документа Оказание услуги №1

[159]
Движения документа Оказание услуги №2

Движения документа Оказание услуги №3

Теперь у нас есть практически вся необходимая информация для анализа деятельности OOO "На все руки мастер" и в следующей главе мы займемся с вами тем, что создадим несколько отчетов, которые будут представлять нам итоговую информацию о работе предприятия. [160]
Язык запросов
Алгоритм, по которому данные будут выбраны из исходных таблиц запроса, описывается в тексте запроса на специальном языке - языке запросов. Текст запроса состоит из нескольких частей:
| · | описание запроса, |
| · | объединение запросов, |
| · | упорядочивание результатов, |
| · | АВТОУПОРЯДОЧИВАНИЕ, |
| · | описание итогов. |
Обязательной частью запроса является только первая - описание запроса. Все остальные присутствуют по необходимости.
Описание запроса определяет источники данных, поля выборки, группировки и т.д. [164]
Объединение запросов определяет, как будут объединены результаты выполнения нескольких запросов.
Упорядочивание результатов определяет условия упорядочивания строк результата запроса.
АВТОУПОРЯДОЧИВАНИЕ позволяет включить режим автоматического упорядочивания строк результата запроса.
Описание итогов определяет, какие итоги необходимо рассчитывать в запросе и каким образом группировать результат.
Применение различных синтаксических конструкций языка запросов подробно описано в книге "1С:Предприятие 8.0 Описание встроенного языка", поэтому мы перейдем прямо к созданию отчетов, и по пути будем комментировать создаваемый текст запросов. [165]
Кластерный анализ
Тип анализа АнализДанныхКластеризация позволяет разделить исходный набор исследуемых объектов на группы объектов, таким образом, чтобы каждый объект был более схож с объектами из своей группы, чем с объектами других групп. Анализируя в дальнейшем полученные группы, называемые кластерами, можно определить, чем характеризуется та или иная группа, принять решение о методах работы с объектами различных групп.
Например, при помощи кластерного анализа можно разделить клиентов, с которыми работает компания на группы, для того, чтобы применять различные стратегии при работе с ними.
При помощи параметров кластерного анализа аналитик может настроить алгоритм, по которому будет производиться разбиение, а также может динамически изменять состав характеристик, учитываемых при анализе, настраивать для них весовые коэффициенты.
Результат кластеризации может быть выведен в дендрограмму специальный объект, предназначенный для отображения последовательных связей между объектами. [466]
Типы колонок источника данных:
| · | Не используется - колонка не используется при анализе. |
| · | Входная - колонка используется для группирования объектов. |
| · | Прогнозируемая - будет создан прогноз для значения колонки для каждого кластера. |
| · | ВходнаяИПрогнозируемая - колонка используется как входная и как прогнозируемая. |
| · | Ключ - ключевая колонка, предназначенная для идентификации объекта. |
Параметры:
| · | КоличествоКластеров - (Число) - количество искомых кластеров. |
| · | ТипЗаполненияТаблицы - (все поля, используемые поля, ключевые поля, не заполнять) - какие поля выводить в таблицу кластеризации. |
| · | Стандартизация - (не стандартизировать, стандартизировать) - необходимость стандартизации данных. Если необходимо стандартизировать данные, то анализатор предварительно приведет все характеристики объектов к одной весовой категории. |
| · | МераРасстояния - (ЕвклидоваМетрика, ЕвклидоваМетрикаВКвадрате, МетрикаГорода, МетрикаДоминирования) - каким образом вычислять расстояние между объектами. |
| · | МетодКластеризации - (БлижняяСвязь, ДальняяСвязь, КСредних, ЦентрТяжести) - каким методом выполнять кластеризацию. |
Логическая связь объектов
Для реализации этого примера нам понадобятся три новых объекта конфигурации. Прежде всего, это план видов характеристик, который будет хранить виды характеристик, которыми в принципе можно описывать материалы. Затем это справочник, подчиненный справочнику "Номенклатура", элементы которого будут идентифицировать партии материалов с некоторым фиксированным набором значений характеристик. И третий объект - это регистр сведений, в котором собственно и будет храниться соответствие конкретных значений характеристик некоторому варианту материала.
В результате использования подобной логической структуры объектов мы получим возможность описывать каждую поступающую партию материала, любым количеством видов характеристик, поскольку это соответствие будет храниться в регистре сведений. И вместе с тем получим возможность вести учет в разрезе видов характеристик, добавив в регистры накопления еще одно измерение для хранения ссылки на элемент справочника, подчиненного справочнику номенклатура.

Теперь для того, чтобы узнать остатки материалов, обладающих некоторым значением характеристики, достаточно будет выбрать из Регистра сведений все элементы подчиненного справочника,[257] обладающие таким значением характеристики, и затем по ним и их владельцам получить остатки регистра накопления.[258]
Механизм распределенных информационных баз
Механизм распределенных информационных баз является развитием универсального обмена данными. Он реализует привычную, по версии 7.7, модель распределенной информационной базы, которая подразумевает наличие идентичных конфигураций во всех узлах, имеет древовидную структуру и позволяет выполнять обмен как измененными данными так и изменениями, внесенными в конфигурацию.
Механизм распределенных информационных баз реализуется планами обмена. Для этого объект конфигурации План обмена содержит свойство "Распределенная информационная база". Если это свойство установлено, для данного плана обмена включается механизм распределенных информационных баз и разработчик получает возможность создать распределенную базу исключительно интерактивными средствами, без написания кода. Такая возможность не исключает программное управление обменом, которое также доступно при работе с распределенными информационными базами и в ходе создания примера мы рассмотрим оба варианта организации обмена в распределенных информационных базах. [426]
Модель прогноза
Объект модель прогноза представляет собой специальный объект, который создается из результата анализа данных, и позволяет в дальнейшем строить прогнозы для новых данных.
Например, модель прогноза поиска ассоциаций, созданная при анализе покупок клиентов, может быть использована при работе с осуществляющим покупку клиентом, для того, чтобы предложить ему товары, которые он с определенной степенью вероятности приобретет вместе с теми товарами, которые он уже выбрал.
Объект Модель прогноза можно получить из соответствующих объектов результат анализа путем выполнения метода СоздатьМодельПрогноза().
В дальнейшем для модели прогноза можно задать некоторый набор исходных данных и получить результат прогноза в виде таблицы значений.

Источник данных для модели прогноза задается при помощи свойства ИсходныеДанные, а для получения результата прогноза необходимо выполнить метод Выполнить().
Используя соответствующие свойства модели прогноза можно настраивать для нее входные колонки, колонки самой модели и колонки результата.
Кроме этого каждая из моделей прогноза содержит дополнительные свойства, определяемые типом анализа, к которому относится модель прогноза.
Настройка параметров и выполнение анализа
Объект ПостроительОтчетаАнализаДанных может быть использован для выполнения анализа с интерактивной настройкой параметров и последующего отображения результата.
Исходные данные для анализа задаются свойством ИсточникДанных. Свойства НастройкаКолонок и Параметры позволяют интерактивно настраивать колонки анализа (через табличные поля), и задавать параметры для выбранного типа анализа который задается свойством ТипАнализа. Кроме того, построитель отчета анализа данных допускает переопределение стандартного макета отчета путем использования свойства Макет.
В дальнейшем методом Выполнить() можно получить результат анализа данных, который будет доступен через свойство построителя Результат. Таким образом, при необходимости, его можно сохранить в базе данных. Если же сохранения результата не требуется, можно выполнить метод Вывести(), который выведет данные результата анализа, полученного методом Выполнить().
Кроме всего перечисленного, ПостроительОтчетаАнализаДанных позволяет получить объект АнализДанных, соответствующий всем интерактивным настройкам, выполненным в построителе, методом ПолучитьАнализ():

Настройка параметров модели прогноза
Объект ПостроительОтчетаАнализаДанных может быть использован для интерактивной настройки параметров модели прогноза (через табличные поля). Для этого следует использовать его свойство МодельПрогноза, в которое передается настраиваемая модель. После того, как настройка модели выполнена, результат прогноза может быть получен методом модели прогноза Выполнить():

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

Для тех, кто работал с версией 7.7
Перечисления могут теперь иметь формы (в том числе основную форму списка и выбора), а также макеты.

Узнай больше!
О структуре объектов встроенного языка, предназначенных для работы с перечислениями можно прочитать в главе "Перечисления" на странице 584. [131]
Объект конфигурации План счетов
Объект конфигурации План счетов является прикладным объектом и предназначен для описания структуры хранения информации о совокупности синтетических счетов предприятия, которые предназначены для группировки данных о его хозяйственной деятельности. На основе объекта конфигурации План счетов платформа создает в базе данных структуры, в которых может храниться информация о том, какие счета и каким образом будет использовать предприятие. Это может быть система бухгалтерских счетов, установленная государством, план управленческих счетов или произвольный набор счетов, используемых для анализа тех или иных видов деятельности предприятия.
План счетов в системе 1С:Предприятие поддерживает иерархию субсчетов: к каждому счету первого уровня может быть открыто несколько субсчетов, которые в свою очередь могут иметь свои субсчета - и так далее.
По любому счету или субсчету может вестись аналитический учет в разрезе субконто, описанных в плане видов характеристик. Связь между планом счетов и планов видов характеристик задается разработчиком на этапе конфигурирования. Для описания используемых субконто система создает в плане счетов специальную табличную часть ВидыСубконто, которая не видна в конфигураторе (но доступна средствами встроенного языка).
Для каждого счета есть возможность задать несколько видов учета (например, количественный и валютный). Виды учета задаются при помощи подчиненных объектов конфигурации "Признак учета".
Также существует возможность определить несколько видов учета субконто (например, суммовой, валютный или количественный). Виды учета субконто задаются при помощи подчиненных объектов конфигурации "Признак учета субконто".
Помимо всего вышеперечисленного, каждый счет может иметь набор свойств, которые задаются в качестве реквизитов объекта конфигурации План счетов. Они позволяют определять уникальные свойства элементов плана счетов (например, реквизит "ЗапретитьИспользоватьВПроводках").[295]

Узнай больше!
О структуре объектов встроенного языка, предназначенных для работы с планами счетов можно прочитать в главе "Планы счетов" на странице 588.
Объект конфигурации План видов характеристик
Объект конфигурации План видов характеристик был подробно рассмотрен нами в предыдущей главе (см. "Объект конфигурации План видов характеристик" на странице 254), поэтому сейчас мы проиллюстрируем только то, как используется этот объект в контексте бухгалтерского учета.
Бухгалтерский учет, как правило, подразумевает ведение аналитического учета на большинстве из счетов. Для обозначения объектов аналитического учета мы будем использовать термин субконто.
Так вот, частным случаем использования плана видов характеристик является использование его для описания субконто, т.е. все объекты аналитического учета, в разрезе которых должен вестись учет на тех или иных счетах, описываются в соответствующем плане видов характеристик и там же задаются типы значений, которые могут принимать те или иные субконто.
Объект конфигурации План видов характеристик
Объект конфигурации План видов характеристик является прикладным объектом и предназначен для описания структуры хранения информации о характеристиках, создаваемых пользователем. На основе объекта конфигурации План видов характеристик платформа создает в базе данных информационную структуру, в которой может храниться информация о том, какие существуют виды характеристик и какой тип должно иметь значение характеристики каждого вида.
В сущности, план видов характеристик очень напоминает справочник. Однако план видов характеристик имеет более узкую "специализацию": он хранит, по сути, информацию только о том, какими видами характеристик может описываться какой-либо объект базы данных. Эта информация состоит из названия вида характеристики и ее типа. Разработчик и, что самое важное, пользователь могут задать в нем любое необходимое им количество видов характеристик.
Для того чтобы разработчик мог задать некий "набор" возможных типов значений, которые могут принимать виды характеристик, у объекта конфигурации План видов характеристик существует свойство Тип значения характеристик. Это свойство определяет составной тип данных, в который входят все типы, которые могут понадобиться при указании типа значения характеристики.
Кроме этого может случиться так, что пользователю станет недостаточно тех типов данных, которые существуют в конкретной системе (например, он захочет вести учет в разрезе цвета товаров, а справочник Цвет в конфигурации отсутствует). В этом случае он сможет воспользоваться неким вспомогательным справочником, который разработчик создаст заблаговременно и укажет в качестве свойства объекта конфигурации План видов характеристик дополнительные значения характеристик.
Тогда пользователь, создав новый вид характеристики "Цвет", сможет создать необходимые значения этого вида характеристики в справочнике дополнительных значений характеристик.
Примечательно, что этот справочник является подчиненным плану видов характеристик. Таким образом, если затем пользователь [254] пожелает создать новый вид характеристик "Запах" и создать его значения, он будет создавать их в том же самом справочнике дополнительных характеристик, и они не будут "смешиваться" со значениями цвета.

В версии 7. 7 нет прямого соответствия прикладному объекту конфигурации план видов характеристик. Точнее всего будет сказать, что один план видов характеристик включает в себя me функциональные возможности, которыми в версии 7.7 обладали все объекты конфигурации вида "Вид субконто". Таким образом, в терминах 7.7, планы видов характеристик позволяют создавать несколько "наборов" объектов "Вид субконто".
Однако описание механизма ведения аналитического учета на счетах не является теперь основной задачей для плана видов характеристик. Использование подобного механизма было обобщено в виде возможности задания переменного количества свойств, которые могут описывать объект конфигурации. Причем возможность задания свойств существует как в режиме Конфигуратора, так и в режимеработы пользователя "1С:Предприятие".
Работа с планом счетов рассматривается теперь не как основное предназначение плана видов характеристик, а как частный случай, вытекающий из его возможностей. Конечно, как мы увидим далее, взаимодействие плана видов характеристик с планом счетов максимально автоматизировано средствами платформы (no сравнению с взаимодействием с другими объектами конфигурации). Однако основной акцент делается на универсальность механизма, предоставляемого планом видов характеристик. В частности это видно и из названия объекта, где вместо слова субконто (разрез аналитического учета) теперь используется слово характеристика, обозначающее свойство объекта конфигурации, описанное вне его самого (в другом объекте конфигурации).[255]

О структуре объектов встроенного языка, предназначенных для работы с планами видов характеристик, можно прочитать в главе "Планы видов характеристик" на странице 586.
Объект конфигурации План видов расчета
Объект конфигурации План видов расчета является прикладным объектом и предназначен для описания структуры хранения информации о возможных видах расчетов. На основе объекта конфигурации План видов расчета платформа создает в базе данных информационную структуру в которой может храниться информация о том, какие существуют виды расчета, и каковы взаимосвязи между ними.
Отличительной особенностью плана видов расчета является то, что пользователь в процессе работы может добавлять в план видов расчета новые виды расчета. Такая возможность делает механизм периодических расчетов более гибким и позволяет пользователю создавать собственные виды расчета, помимо тех, которые заданы разработчиком как предопределенные.
Объект конфигурации План видов расчета имеет свойство "Использует период действия". С помощью этого свойства определяется, будут ли в этом плане находиться виды расчета, которые могут быть вытеснены по периоду действия. Если это свойство установлено, то разработчик получает возможность указать для каждого вида расчета те виды расчета, которые вытесняют его по периоду действия.
Следующим важным свойством объекта конфигурации План видов расчета является свойство "Зависимость от базы". Оно определяет, будут ли в этом плане находиться зависимые по базовому периоду виды расчета. Если это свойство установлено, появляется возможность указать, в каком плане видов расчета будут находиться базовые виды расчета и, кроме этого указать, как будет определяться эта зависимость.
Существует возможность указать один из двух видов зависимости от базы: "Зависимость по периоду действия" и "Зависимость по периоду регистрации". Оба вида этой зависимости подробно объяснены в разделе "Объект конфигурации Регистр расчета" на странице 327.
Еще одной важной особенностью плана видов расчета является возможность создания предопределенных видов расчета и описания их взаимного влияния. При этом в общем случае, разработчик имеет [322] возможность указать три категории видов расчета, влияющих на предопределенный вид расчета:
| · | Базовые - это те виды расчета, результаты которых должны быть использованы при перерасчете этого вида расчета. |
| · | Вытесняющие - это те виды расчета, которые вытесняют этот вид расчета по периоду действия. |
| · | Ведущие - это те виды расчета, изменение результатов которых должно приводить к необходимости перерасчета этого вида расчета. |
В этом случае для премии следует указать базовым видом расчета оклад, а ведущими - оклад и невыход, поскольку изменение результата расчета невыхода приведет к изменению результата оклада, что в свою очередь должно привести к изменению результата премии.


О структуре объектов встроенного языка, предназначенных ^ работы с планом видов расчета можно прочитать в главе "Планы видов расчета" на странице 590. [324]
Объект конфигурации ПланОбмена
Для того, чтобы существовала возможность обмена какими-либо данными с кем-либо, необходимо некоторым образом идентифицировать тех, с кем мы будем обмениваться и для каждого из них описать перечень того, чем мы будем с ним обмениваться.
Обе эти задачи позволяет решать прикладной объект конфигурации План обмена.
Подобно тому, как элементами данных справочника являются элементы справочника, элементами данных плана обмена являются узлы плана обмена. Каждый узел идентифицирует участника обмена данными по данному плану обмена. Кроме этого, в каждом плане обмена всегда существует один предопределенный узел, идентифицирующий данную информационную базу.
В одной конфигурации может существовать несколько планов обмена. Каждый план обмена определяет набор данных, которым будет производиться обмен в рамках данного плана и сам механизм этого обмена. Наличие нескольких планов обмена может [395] потребоваться в случае, если с разными узлами ведется обмен разным составом данных, или когда схема организации обмена с одними узлами отличается от схемы организации обмена с другими узлами.
В состав данных, которыми может производиться обмен, входят элементы информационных структур базы данных, которые описываются следующими объектами встроенного языка:
| · | КонстантаМенеджерЗначения.<имя>, |
| · | СправочникОбъект.<имя>, |
| · | ДокументОбъект.<имя>, |
| · | ПоследовательностьНаборЗаписей.<имя>, |
| · | ПланВидовХарактеристикОбъект.<имя>, |
| · | ПланСчетовОбъект.<имя>, |
| · | ПланВидовРасчетаОбъект.<имя>, |
| · | РегистрСведенийНаборЗаписей.<имя>, |
| · | РегистрНакопленияНаборЗаписей.<имя>, |
| · | РегистрБухгалтерииНаборЗаписей.<имя>, |
| · | РегистрРасчетаНаборЗаписей.<имя>, |
| · | ПерерасчетНаборЗаписей.<имя>, |
| · | БизнесПроцессОбъект.<имя>, |
| · | ЗадачаОбъект.<имя>, |
| · | УдалениеОбъекта. |
Для упрощения изложения, в дальнейшем будем называть эти элементы информационных структур объектами обмена.
Разработчик имеет возможность определить состав каждого плана обмена, указав, объекты конфигурации, данные которых должны участвовать в обмене по данному плану.
При описании состава данных плана обмена разработчик имеет возможность указать для каждого типа объектов признак "Авторегистрация". Этот признак определяет, каким образом план обмена будет отслеживать изменения этих данных.
Возможность отслеживать изменения данных реализована в плане обмена за счет использования механизма регистрации изменений. Работа этого механизма базируется на том, что каждый из объектов обмена имеет свойство "ОбменДанными", с помощью которого можно указать, для каких узлов необходимо производить регистрацию изменений этого объекта. Любые изменения объекта обмена сводятся, [396] в конечном итоге, к записи или удалению объекта обмена. Механизм регистрации изменений анализирует события записи и удаления объектов обмена и на основании параметров обмена данными, содержащихся в каждом из объектов обмена, формирует записи регистрации изменений. Следует отметить, что свойство "ОбменДанными" не хранится в базе данных, а используется только во время записи объекта обмена.
Так вот, признак "Авторегистрация", устанавливаемый при указании состава данных плана обмена, позволяет указать, что параметры обмена данными будут формироваться каждый раз самим механизмом регистрации изменений на основании информации, содержащейся в плане обмена. После автоматического заполнения параметров обмена, разработчик все же имеет возможность внести изменения в сформированные таким образом параметры. Для этого следует использовать обработчики событий объектов, участвующих в обмене - "ПередЗаписью" и "ПередУдалением", в которых можно модифицировать список узлов-получателей (т.е. тех узлов, для которых регистрируются изменения). Кроме этого, существует возможность отключить авторегистрацию изменений, и тогда параметры обмена данными нужно будет формировать полностью средствами встроенного языка. Гипотетически делать это можно в любом фрагменте кода, но для того, чтобы конфигурация была легко читаема, рекомендуется использовать для этих целей все те же обработчики событий "ПередЗаписью" и "ПередУдалением". В этом случае код формирования параметров обмена данными будет сосредоточен в логически понятных точках, а не разбросан по всей конфигурации.
Итак, как мы теперь знаем, при записи и удалении объектов обмена план обмена формирует записи регистрации изменений. Записи регистрации изменений хранятся в таблицах регистрации изменений, причем для каждого объекта обмена ведется своя отдельная таблица регистрации изменений. При изменении объекта обмена в таблице регистрации изменений создается столько записей, сколько узлов-получателей указано в параметрах обмена данными у объекта обмена. Каждая запись при этом будет хранить ссылку на свой узел-получатель. Таблицы регистрации изменений создаются лишь в том случае, если соответствующий объект метаданных указан в составе хотя бы одного плана обмена. [397]
Кроме ссылки на узел обмена, для которого регистрируются изменения, каждая запись таблицы регистрации изменений хранит также номер сообщения, в котором изменение было передано в первый раз в этот узел. До тех пор, пока сообщение не будет передано в первый раз, это поле хранит Null.
Сообщение, с точки зрения плана обмена, это единица обмена информацией. Поэтому одной из важнейших составляющих плана обмена, помимо службы регистрации изменений, является инфраструктура сообщений. Поскольку сообщения передаются в рамках плана обмена от одного узла к другому, каждое сообщение точно ассоциировано с планом обмена, имеет уникальный номер и имеет одного отправителя и одного получателя. За нумерацию сообщений отвечает инфраструктура сообщений, и благодаря этому записи регистрации изменений и имеют возможность хранить номера сообщений, в которых эти изменения были переданы первый раз.
Инфраструктура сообщений позволяет, также, получать подтверждения от узла-получателя о приеме сообщений. Такое подтверждение содержится в каждом сообщении, приходящем от узла-получателя в виде номера последнего принятого сообщения.
Впоследствии, проанализировав номер последнего принятого сообщения и номера сообщений, содержащиеся в записях регистрации изменений, разработчик может удалить записи регистрации изменений, прием которых подтвержден получателем.
Объект конфигурации Регистр бухгалтерии
Объект конфигурации Регистр бухгалтерии является прикладным объектом и предназначен для описания структуры накопления данных, учет которых ведется исходя из некоторого плана счетов. На основе объекта конфигурации Регистр бухгалтерии платформа создает в базе данных информационную структуру, в которой будут накапливаться данные о хозяйственных операциях, отображаемых в бухгалтерском учете.
По своему виду регистр бухгалтерии напоминает регистр накопления - он также имеет ресурсы, может иметь измерения и реквизиты. Измерения позволяют разделять ведение учета (например, используя измерение "Организация", можно вести учет в разрезе нескольких юридических лиц). Реквизиты служат признаком, по которому одни записи регистра можно отделить от других (например, в качестве реквизита может использоваться номер журнала, что позволит отбирать проводки, имеющие одинаковый смысл).
Значительное отличие от регистра накопления заключается в том, что регистр бухгалтерии имеет жесткую связь с используемым планом счетов. Поэтому каждая запись регистра бухгалтерии содержит дополнительные поля, определяемые настройкой используемого плана счетов. Например, запись регистра может содержать дополнительные поля для указания корреспондирующих счетов, сумм, объектов аналитического учета (субконто), количества, вида валюты и т.д.
Кроме этого, отличительной чертой регистра бухгалтерии является возможность поддержки механизма двойной записи, при которой каждая запись регистра содержит обязательные поля для указания счета дебета и счета кредита.

Узнай больше!
О структуре объектов встроенного языка, предназначенных для работы с регистрами бухгалтерии можно прочитать в главе "Регистры бухгалтерии" на странице 603.[301]
Объект конфигурации Регистр расчета
Объект конфигурации Регистр расчета является прикладным объектом и предназначен для описания структуры накопления данных, являющихся результатами расчетов. На основе объекта конфигурации "Регистр расчета" платформа создает в базе данных информационную структуру, в которой будут накапливаться данные, формируемые различными объектами базы данных.
Отличительной особенностью регистра расчета является то, что он не предназначен для интерактивного редактирования пользователем. Разработчик может, при необходимости, предоставить пользователю возможность редактировать регистр расчета, но предназначение регистра расчета заключается в том, чтобы его модификация производилась на основе алгоритмов работы объектов базы данных, а не в результате непосредственных действий пользователя.
Как и другие регистры, регистр расчета имеет ресурсы, в которых хранит числовые данные, имеет измерения, в разрезе которых можно получать значения ресурсов регистра, имеет реквизиты, которые характеризуют каждую запись регистра расчета.
Отличительными же особенностями регистра расчета является его периодичность, возможность использования механизмов вытеснения по периоду действия и зависимости по базовому периоду, и связь с планом видов расчета. Рассмотрим все эти особенности по порядку.
Периодичность регистра расчета может быть определена одним из следующих значений:
| · | День, |
| · | Месяц, |
| · | Квартал, |
| · | Год. |
Периодичность регистра расчета определяет промежуток времени, к которому будет относиться каждая запись регистра. Если указана периодичность "День", то каждая запись регистра будет относиться к какому либо дню, если периодичность "Месяц" - то к какому либо месяцу и т.д. Для указания факта принадлежности записи к какому либо периоду, регистр имеет служебный реквизит [327] "ПериодРегистрации" типа Дата. При записи данных в регистр платформа всегда приводит значение этого реквизита к началу того периода, в который он попадает.
Например, если в регистр расчета с периодичностью месяц записать данные, где "ПериодРегистрации" задан как 08.04.2004, то регистр сохранит эти данные со значением поля "ПериодРегистрации" 01.04.2004:

Если в этой же ситуации периодичность регистра будет год, сохраненное значение периода регистрации будет 01.01.2004:

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

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

[330]
После добавления в регистр записи вида расчета "Невыход", который вытесняет вид расчета "Оклад" по периоду действия, записи о начислении по окладу примут следующий вид:

Другим механизмом, который поддерживает регистр расчета, является зависимость записей по базовому периоду. Этот механизм позволяет основывать расчет зависимых (вторичных) записей регистра на данных, полученных в результате расчета первичных записей. Регистр расчета может поддерживать два вида зависимости от базы: зависимость по периоду действия и зависимость по периоду регистрации.
Зависимость по периоду действия означает, что при анализе базовых записей, будут выбираться те записи, для которых найдено пересечение их фактического периода действия и указанного базового периода. [331]
Например, в начале апреля производится расчет зарплаты за март. Премия за март должна быть начислена исходя из оплаты по окладу за март. В этом случае, как правило, используется зависимость по периоду действия:

Следует сделать два замечания к приведенному рисунку.
Поля "Начало базового периода" и "Конец базового периода" имеют смысл только для записей тех видов расчета, для которых определена зависимость по базовому периоду (в нашем случае для записи расчета премии).
Значение базы, которая будет получена от конкретной влияюшеи записи, в общем случае не равно результату, который содержит эта запись. База будет рассчитана пропорционально тому, какую часть от фактического интервала влияющей записи составляет [332] перекрывающийся, с указанным базовым периодом, участок. При этом будут использованы данные графика, связанного с записью.
Зависимость по периоду регистрации означает, что при анализе базовых записей, будут выбираться те записи, которые попадают в указанный базовый период значением своего поля "Период регистрации".
В качестве примера можно привести расчет штрафов при начислении зарплаты за март. В качестве базы для расчета суммы штрафов должны браться записи о прогулах, зарегистрированные в марте месяце (это могут быть как записи о мартовских прогулах, так и записи о прогулах в феврале). В этом случае, как правило, используется зависимость по периоду регистрации:
Заключительной важной особенностью регистра расчета является его связь с планом видов расчета. Именно на основе этой связи работают механизмы вытеснения по периоду действия и зависимости по базовому периоду, поскольку в плане видов расчета описано взаимное влияние видов расчета друг на друга.
У регистра расчета могут существовать подчиненные объекты Перерасчет. Они предназначены для регистрации фактов появления в регистре записей, влияющих на результат расчета уже существующих записей регистра. Объект конфигурации Перерасчет может иметь несколько измерений, каждое из которых может устанавливать связь между измерениями данного регистра расчета и влияющих регистров расчета. В частном случае это может быть один и тот же регистр. [333]
В информационной структуре, созданной в базе данных на основе объекта конфигурации Перерасчет, платформа хранит информацию о том, какие записи регистра подлежат перерасчету. Таблицы перерасчета заполняются автоматически как на основании записей регистров расчета, затронутых ведущими видами расчета, так и на основании записей регистра расчета, для которых изменился фактический период действия. Исходя из этой информации разработчик может принимать решение о необходимости перерасчета записей регистра.
Последним замечанием, которое следует сделать, говоря о регистре расчета, является возможность установки связи регистра расчета с графиком времени. Такой график времени должен представлять собой регистр сведений (непериодический, с обязательным измерением типа Дата и ресурсом типа Число), в котором содержится временная схема исходных данных, участвующих в расчетах. Измерениями этого графика могут быть, например, график работы (ссылка на справочник) и дата, а ресурсом - количество рабочих часов в этой дате. В этом случае можно будет связать запись регистра расчета с каким-либо конкретным графиком работы (указав в качестве реквизита записи ссылку на справочник график работы) и в дальнейшем, средствами встроенного языка получать информацию о количестве рабочих часов в периоде действия, фактическом периоде действия или периоде регистрации этой записи.

О структуре объектов встроенного языка, предназначенных для работы с регистром расчета, можно прочитать в главе "Регистры расчета" на странице 606. [334]
Объект конфигурации регистр сведений
Объект конфигурации Регистр сведений является прикладным объектом и предназначен для описания структуры хранения данных в разрезе нескольких измерений. На основе объекта конфигурации Регистр сведений платформа создает в базе данных информационную структуру, в которой может храниться произвольная информация "привязанная" к набору измерений.
Принципиальным отличием регистра сведений от регистра накопления является то, что каждое движение регистра сведений устанавливает новое значение ресурса, в то время как движение регистра накопления изменяет существующее значение ресурса. По этой причине регистр сведений может хранить любые данные (а не только числовые, как регистр накопления).
Следующей важной особенностью регистра сведений является его способность (при необходимости) хранить данные с привязкой ко времени. Благодаря этому регистр сведений может хранить не только актуальные значения данных, но и историю их изменения во времени. Регистр сведений, использующий привязку ко времени называют обычно периодическим регистром сведений.
Периодичность регистра сведений можно определить одним из следующих значений:
| · | в пределах секунды, |
| · | в пределах дня, |
| · | в пределах месяца, |
| · | в пределах квартала, |
| · | в пределах года, |
| · | в пределах регистратора (если установлен режим записи - "Подчинение регистратору"). |
Периодический регистр сведений всегда содержит служебное поле "Период", добавляемое системой автоматически. Оно имеет тип Дата, и служит для указания факта принадлежности записи к какому-либо периоду. При записи данных в регистр, платформа всегда приводит значение этого поля к началу того периода, в который он попадает. Например, если в регистр сведений с периодичностью в пределах месяца записать данные, в которых период указан как 08.04.2004, то регистр сохранит эти данные со значением периода равным 01.04.2004. [120]
Как и для других регистров, система контролирует уникальность записей для регистра сведений. Однако, если для прочих регистров уникальным идентификатором записи является регистратор и номер строки, то для регистра сведений применяется другой принцип формирования ключевого значения.
Ключом записи, однозначно идентифицирующим запись, является в данном случае совокупность значений измерений регистра и периода (в случае, если регистр сведений периодический). Регистр сведений не может содержать несколько записей с одинаковыми ключами.
Если продолжать сравнение с регистром накопления, то можно сказать, что регистр сведений предоставляет больше свободы в редактировании хранимых данных. Наряду с тем, что регистр сведений может использоваться в режиме подчинения регистратору (когда записи регистра сведений "привязаны" к документу-регистратору), регистр сведений может использоваться и в независимом режиме, в котором пользователю предоставляется полная свобода интерактивной работы с данными регистра. Регистр сведений, не использующий подчинение регистратору, называют независимым регистром сведений.

О структуре объектов встроенного языка, предназначенных для работы с регистрами сведений можно прочитать в главе "Регистры сведений" на странице 593. [121]
Объект конфигурации Роль
Для описания подобных разрешений используются объекты конфигурации Роль. С помощью такого объекта разработчик получает возможность описать набор прав на выполнение тех или иных действий над каждым из объектов базы данных и над всей конфигурацией в целом.
Как правило, роли создаются отдельно для каждого вида деятельности, и каждому пользователю системы ставится в соответствие одна или несколько ролей.
В случае, когда пользователю поставлено в соответствие несколько ролей, предоставление доступа будет осуществляться по следующему алгоритму:
| · | если хотя бы в одной роли есть разрешение, то доступ будет открыт, |
| · | если во всех ролях разрешение отсутствует, то доступ будет закрыт. |
Общая статистика
Тип анализа АнилизДанныхОбщаяСтатистика позволяет получать общестатистические показатели выборки, которую представляют исходные данные.
Колонки исходных данных для общестатистического анализа могут быть двух видов: содержащие непрерывные данные, либо содержащие дискретные данные.
Если анализируемые значения являются числовыми, или имеют тип Дата, то для такой колонки следует указывать вид данных "Непрерывные". Во всех остальных случаях (в том числе при анализе значений объектного типа), следует указывать вид данных "Дискретные".
Для указания того или иного вида исходных данных используется свойство объекта АнализДанных - НастройкаКолонок. Это свойство содержит коллекцию значений, элементами которой являются объекты КолонкаАнализаДанных. Каждый такой объект описывает одну колонку исходных данных. Для указания вида данных, содержащихся в колонке, нужно использовать свойство объекта КолонкаАнализаДанных - ВидДанных.
Для непрерывных и дискретных данных рассчитываются различные статистические показатели.
Для непрерывных данных рассчитывается:
| · | количество значений - количество значений, присутствующих в исходной выборке, |
| · | минимальное значение - минимальное значение, присутствующее в исходной выборке, |
| · | максимальное значение - максимальное значение, присутствующее в исходной выборке, [451] |
| · | среднее значение - среднее арифметическое значений выборки, |
| · | размах - разность между максимальным и минимальным значением выборки, |
| · | стандартное отклонение - среднее квадратичное отклонение равное корню квадратному из дисперсии выборки, |
| · | медиана - значение, лежащее в середине выборки упорядоченной по возрастанию или убыванию. Другими словами медиана делит выборку пополам; одна половина выборки имеет значения меньше медианы, другая - больше. В случае четного числа значений выборки, медиана рассчитывается как среднее арифметическое двух значений ближайших к центру выборки. |
Для дискретных данных рассчитывается:
| · | количество значений - общее количество значений, присутствующих в исходной выборке, |
| · | количество уникальных значений - количество уникальных значений, присутствующих в исходной выборке, |
| · | мода - значение, наиболее часто встречающееся в исходной выборке. В выборке могут быть два или более значения, с максимальной частотой (би- или мультимодальная выборка). В этом случае в качестве моды будет взято первое найденное значение с максимальной частотой. |
| · | частота - количество вхождений уникального значения в выборку, |
| · | относительная частота - частота, выраженная в процентах от общего количества значений выборки, |
| · | накопленная частота - сумма частоты значения и частот всех предыдущих значений выборки, |
| · | накопленная относительная частота - сумма относительной частоты и относительных частот всех предыдущих значении выборки. [452] |
Типы колонок источника данных:
| · | Не используется - колонка не участвует в анализе, |
| · | Входная - содержит исходные данные для анализа. |
Общие сведения об анализе и прогнозировании данных
В общем случае анализ и прогнозирование данных связаны следующим образом. Анализ данных позволяет найти неочевидные закономерности в анализируемых данных, и представить их в виде легко воспринимаемого результата.
Прогнозирование позволяет, на основе проведенного анализа данных, предсказать последующие события или значения некоторых характеристик для новых исходных данных.
Таким образом, результаты анализа являются основой, на которой строятся последующие прогнозы.
Например, в нашей базе имеются данные о том, какие товары и когда приобретались нашими клиентами. Было замечено, что если клиент приобретал, скажем, диван "Сказка", то через некоторое время он, зачастую, приобретал и кресло "Сказка", из того же набора мягкой мебели.
Мы хотим проанализировать данные нашей базы в следующем виде: какие существуют наиболее вероятные последовательности покупок товаров одним и тем же клиентом? Иначе говоря - "как обстоят дела сейчас, если взять текущие данные и попробовать определить, какие существуют последовательности покупаемых товаров"? [445]
В терминах 1С:Предприятия 8.0 такой процесс анализа данных можно представить следующей схемой:

Источник данных - представляет исходные данные для анализа. В качестве источника данных может выступать результат запроса, область ячеек табличного документа или таблица значений.
Тип анализа - определяет вид результата, к которому должны быть сведены исходные данные. Система поддерживает пять различных типов анализа:
| · | общая статистика - позволяет получить общую статистическую информацию об источнике данных для его предварительного исследования (количество значений и количество уникальных значений, минимальное, максимальное и среднее значение, размах, стандартное отклонение, медиана, мода, частота появления каждого значения в источнике), [446] |
| · | поиск ассоциаций предназначен для поиска часто встречаемых групп характеристик объектов и создания правил ассоциации "Если ... To ..." (например, такой анализ может быть использован для поиска групп товаров, часто покупаемых вместе), |
| · | поиск последовательностей - применяется для выявления цепочек событий часто наблюдаемых в источнике данных (например, это может быть цепочка товаров или услуг, которые часто последовательно приобретают клиенты), |
| · | дерево решений - предназначен для выявления закономерностей того, что объект относится к тому или иному классу (например, при помощи дерева решения можно проанализировать какие характеристики клиента влияют на то, что он перейдет к другому поставщику), |
| · | кластерный анализ - при помощи кластерного анализа можно объединить объекты в группы (кластеры), в которых будут находиться объекты, наиболее схожие по ряду характеристик. Например, можно сгруппировать клиентов по их характеристикам и деятельности, чтобы в дальнейшем проанализировав полученные кластеры принять решение о стратегии работы с клиентами определенных групп. |
Анализ данных - объект встроенного языка (АнализДанных), непосредственно выполняющий анализ данных. Объекту устанавливается источник данных, задаются параметры, настраиваются колонки анализа данных. Результатом работы данного объекта является результат анализа данных, тип которого зависит от типа анализа. Каждому типу анализа соответствует свой тип результата анализа.
Результат анализа - объект встроенного языка, содержащий информацию о результате анализа. Для каждого типа анализа предусмотрен свой тип результата. Например, результатом анализа данных типа АнализДанныхДеревоРешений будет объект типа РезультатАнализаДанныхДеревоРешений.
В дальнейшем результат может быть выведен в табличный Документ при помощи построителя отчета анализа данных (о нем будет рассказано далее), может быть выведен посредством программного доступа к его содержимому, может быть использован [447] для создания модели прогноза. Любой результат анализа данных может быть сохранен для последующего использования.
Теперь рассмотрим, как выглядит прогнозирование данных Прогнозирование является попыткой предсказать новый результат, на основе некоторой совокупности новых данных и определенной ранее модели. Иными словами, прогнозирование позволяет ответить на вопрос: "как будут обстоять дела, если мы будем иметь такие данные при такой модели их взаимосвязи"?
Возвращаясь к нашему примеру - "какой товар, с большой долей вероятности, клиент приобретет в следующий раз, если до этого он совершал вот такие покупки, и текущие последовательности покупок товаров выглядят следующим образом"?
В терминах 1С:Предприятия 8.0 этот процесс прогнозирования данных можно представить следующей схемой:

Источник данных - таблица значений, результат запроса или область табличного документа, содержащая информацию, по которой необходимо построить прогноз. Например, для модели прогноза МодельПрогнозаПоискАссоциаций, выборка может содержать перечень товаров документа продажи. Результат же работы модели может рекомендовать, какие товары можно еще предложить покупателю.
Модель прогноза - специальный объект, позволяющий выполнять прогноз на основании входных данных. Тип модели зависит от типа анализа данных. Например, модель, созданная для анализа данных АнализДанныхПоискАссоциаций будет иметь тип МодельПрогнозаПоискАссоциаций. Такая модель сможет выдавать прогнозы типа: "т.к. данный покупатель купил заданный набор товаров, то с определенной вероятностью он должен купить и другой набор товаров". На вход модели прогноза передается источник данных для прогноза. Результатом является таблица значений, содержащая прогнозируемые значения.
Таблица значений - таблица значений, состоящая из колонок, согласно настройкам результирующих колонок модели прогноза, содержащая прогнозируемые данные. Конкретное содержание таблицы определяется типом анализа данных. [449]
Если обобщить обе схемы, представленные выше, то анализ и прогнозирование данных в терминах 1С:Предприятия 8.0 можно представить следующим образом:

[450]
Как вы видите, на этой схеме появились новые прямоугольники. Мы рассмотрим их назначение в следующем разделе.
Общие сведения об обмене данными
Средства обмена данными, которые содержит система 1С:Предприятие 8.0 позволяют организовывать обмен информацией, хранимой в базе данных, с другими программными системами. В качестве таких систем могут выступать как другие информационные базы 1С:Предприятия 8.0 (имеющие аналогичную или отличающуюся конфигурацию), так и программные системы, не основанные на 1С:Предприятии 8.0.
Такая гибкость обмена данными достигается тем, что средства обмена данными 1С:Предприятия 8.0 могут использоваться в различных комбинациях, и кроме этого, формат обмена данными основан на языке XML, являющимся на сегодняшний день общепринятым средством представления данных.
К механизмам обмена данными могут быть отнесены:
| · | Планы обмена, |
| · | XML-сериализация, |
| · | Средства чтения и записи документов XML. |
В общем случае схема взаимодействия этих трех составляющих может быть представлена следующим образом:

При помощи планов обмена мы получаем информацию о том, какие элементы данных были изменены, и в какой узел обмена их необходимо передать. Это возможно благодаря тому, что планы обмена содержат механизм регистрации изменений. Информация об [394] измененных данных переносится с помощью сообщений, инфраструктура которых также поддерживается планами обмена.
XML-сериализация позволяет преобразовать объект 1С:Предприятия в последовательность данных, представленных в формате XML. Кроме этого, XML-сериализация выполняет и обратное преобразование - преобразует последовательность данных формата XML в объект 1С:Предприятия, при условии, что имеется соответствующий тип 1С:Предприятия.
Запись и чтение документов XML обеспечивают запись/чтение документов формата XML из встроенного языка.
При реализации алгоритма обмена данными перечисленные механизмы могут быть использованы как все вместе, так и в различной комбинации. В каждом конкретном случае разработчик решает эту задачу самостоятельно.
В примере, приведенном в этой книге, мы используем все три механизма обмена данными, поэтому прежде чем перейти непосредственно к написанию кода, познакомимся с каждым из них более подробно.
Оптимизация документа ОказаниеУслуги
Первое, что мы сделаем для оптимизации документа "ОказаниеУслуги" - удалим реквизит табличной части "Стоимость", который нам не понадобится в будущем.
Также следует удалить соответствующую колонку из табличного поля, расположенного в форме.
После этого можно полностью удалить содержимое обработчика события "ОбработкаПроведения" в модуле документа и создать в нем заготовку процедуры проведения. Текст запроса, выполняемого в режиме оперативного проведения, будет отличаться от запроса, выполняемого при неоперативном проведении, поэтому формирование текста запроса мы включим в условие Если...Иначе...КонецЕсли:
Запрос = Новый Запрос;
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Запрос.Текст =
;
Иначе
Запрос.Текст =
;
КонецЕсли;
КонецПроцедуры
| · | "Номенклатура", |
| · | "Количество", |
| · | "ВидНоменклатуры", |
| · | "Сумма".[238] |
Эти поля будут нужны нам для задания значений измерений регистров и их ресурсов. Кроме того, поле "ВидНоменклатуры" понадобится нам для анализа того, чем является номенклатура, указанная в документе: материалом или услугой:

Теперь задумаемся о том, что для указания значений ресурса "Стоимость" регистров "СтоимостьМатериалов" и "Продажи" нам понадобится рассчитать текущую стоимость номенклатуры как частное стоимости остатка этого материала и его оставшегося количества.
Поэтому добавим к списку выбранных таблиц еще две таблицы:
| · | "РегистрНакопления.СтоимостьМатериалов.Остатки", |
| · | "РегистрНакопления.ОстаткиМатериалов.Остатки": |

Для этих виртуальных таблиц нам нужно будет задать параметры. Эти параметры будут одинаковы для обеих таблиц. Они будут включать в себя момент времени, на который должны быть получены остатки этих регистров, и условие получения данных.[239]
Условие получения данных указывает, что остатки должны быть получены только по тем позициям номенклатуры, которые содержатся в проводимом документе (перед выполнением запроса мы передадим в параметр "СписокНоменклатурыДокумента" список всех позиций номенклатуры, содержащихся в проводимом документе):


Следует внимательно подходить к использованию виртуальных таблиц запросов. В частности, необходимо уделять особое внимание максимально возможному использованию параметров этих таблиц. Например, в нашем случае можно было бы и не использовать параметр "Условие", а ограничить выбранные поля уже в самом запросе, указав в условии ПО равенство номенклатуры из документа и материала из таблицы остатков. В результате мы получили бы тот же самый результат, однако no производительности этот способ сильно отличался бы от того, который мы используем.
В самом деле, в нашем варианте виртуальная таблица предоставит нам ровно столько записей, сколько различных элементов номенклатуры содержится в проводимом документе. Если же не указывать условие, виртуальная таблица предоставит нам записи no абсолютно всем элементам номенклатуры, информация о которых есть в регистре накопления. И уже в самом нашем запросе мы будем отбирать из этой огромной массы записей лишь несколько, которые нам действительно нужны.
Очевидно, что второй вариант будет работать дольше, и время выполнения такого запроса будет зависеть в основном не от количества данных, содержащихся в документе (т.е. реального количества обрабатываемой информации), а от размера регистра накопления.[240]
Кроме того, что подобный вариант снижает производительность конфигурации, могут возникать ситуации, когда результаты, полученные одним и другим способом, будут различны. Такое, например, вполне возможно при использовании виртуальной таблицы регистра сведений "СрезПоследних". Более подробно можно прочитать об этом на диске ИТС (информационно технологического сопровождения) в статье "Использование отборов в запросах с виртуальными таблицами".

Теперь вспомним о том, что документы "ОказаниеУслуги" могут быть проведены как в оперативном, так и в неоперативном режиме.

О концепции оперативного и неоперативного проведения документов можно прочитать в главе "Концепция оперативного и неоперативного проведения документов" на странице 541.

[241]
Для этой виртуальной таблицы мы также укажем "МоментВремени", а в условии напишем, что материал должен находиться в списке номенклатуры и склад должен быть равен складу указанному в документе:

Теперь из этой виртуальной таблицы мы выберем поле "КоличествоОстаток":

На этом формирование списка выбранных полей закончено, и мы можем перейти к заданию условий связи между выбранными таблицами. Каждая из виртуальных таблиц должна быть связана с таблицей документа таким образом, что для всех записей таблицы документа должны подбираться имеющиеся записи виртуальной таблицы, причем номенклатура в таблице документа должна быть равна материалу из виртуальной таблицы:


[242]
Теперь перейдем на закладку "Дополнительно" и установим флаг "Для изменения". Предложение ДЛЯ ИЗМЕНЕНИЯ позволяет заблаговременно заблокировать чтение указанных данных (которые могут читаться транзакцией другого соединения) уже при считывании, чтобы исключить взаимные блокировки при записи. Это предложение дает возможность указать в запросе таблицы, считываемые данные которых предполагается изменять.

Более подробно об использовании предложения ДЛЯ ИЗМЕНЕНИЯ можно прочесть на диске ИТС (информационно-технологического сопровождения) в статье "Использование предложения ДЛЯ ИЗМЕНЕНИЯ в языке запросов".

Перейдем на закладку "Условия" и зададим условие отбора из таблицы документа только строк проводимого документа (ссылка на него будет передана в параметр запроса "Ссылка"):

[243]
Перейдем на закладку "Псевдонимы" и зададим следующие псевдонимы полей:
| · | "НоменклатураВидНоменклатуры" - "ВидНоменклатуры", |
| · | "КличествоОстаток1> - "КоличествоОстатокНаСкладе". |
Запрос = Новый Запрос;
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Запрос.Текст =
"ВЫБРАТЬ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
| ОказаниеУслугиПереченьНоменклатуры.Количество,
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| ОказаниеУслугиПереченьНоменклатуры.Сумма,
| ОстаткиМатериаловОстатки.КоличествоОстаток,
| СтоимостьМатериаловОстатки.СтоимостьОстаток,
| ОстаткиМатериаловОстаткиНаСкладе.КоличествоОстаток КАК КоличествоОстатокНаСкладе
|ИЗ
| Документ.ОказаниеУслуги. ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК СтоимостьМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = СтоимостьМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК ОстаткиМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = ОстаткиМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(
| &МоментВремени,
| Материал В (&СписокНоменклатурыДокумента)
| И Склад = &СкладВДокументе) КАК ОстаткиМатериаловОстаткиНаСкладе
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = ОстаткиМатериаловОстаткиНаСкладе.Материал
|ГДЕ [244]
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
|
|ДЛЯ ИЗМЕНЕНИЯ
| РегистрНакопления.СтоимостьМатериалов.Остатки,
| РегистрНакопления.ОстаткиМатериалов.Остатки";
Иначе
Запрос.Текст =
;
КонецЕсли;
КонецПроцедуры
Текст запроса для случая неоперативного проведения документа будет практически таким же, за исключением того, что в нем будет отсутствовать третье левое соединение и, соответственно, поле "КоличествоОстатокНаСкладе", т.к. проверку остатков в этом случае мы выполнять не будем:
Иначе
Запрос.Текст =
"ВЫБРАТЬ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
| ОказаниеУслугиПереченьНоменклатуры.Количество,
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| ОказаниеУслугиПереченьНоменклатуры.Сумма,
| ОстаткиМатериаловОстатки.КоличествоОстаток,
| СтоимостьМатериаловОстатки.СтоимостьОстаток
|ИЗ
| Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК СтоимостьМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = СтоимостьМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК ОстаткиМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = [245] ОстаткиМатериаловОстатки.Материал
|ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
|
|ДЛЯ ИЗМЕНЕНИЯ
| РегистрНакопления.СтоимостьМатериалов.Остатки,
| РегистрНакопления.ОстаткиМатериалов.Остатки";
КонецЕсли;
КонецПроцедуры
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("СкладВДокументе",Склад);
...
| РегистрНакопления.ОстаткиМатериалов.Остатки";
КонецЕсли;
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("СписокНоменклатурыДокумента", ПереченьНоменклатуры.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("Ссылка",Ссылка);
...
КонецПроцедуры
После этого добавим получение результата запроса и цикл его обхода:
КонецЕсли;
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("СписокНоменклатурыДокумента", ПереченьНоменклатуры.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("Ссылка",Ссылка);
ВыборкаРезультатаЗапроса = Запрос.Выполнить().Выбрать();
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
КонецЦикла;
КонецПроцедуры
КонецЕсли;
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("СписокНоменклатурыДокумента", ПереченьНоменклатуры.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("Ссылка",Ссылка);
ВыборкаРезультатаЗапроса = Запрос.Выполнить().Выбрать();
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
//Проверить остаток при оперативном проведении
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Остаток = ?(ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе = Null, 0, ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе);
Если Остаток < ВыборкаРезультатаЗапроса.Количество Тогда
Сообщить("Материала " + СокрЛП(ВыборкаРезультатаЗапроса.Номенклатура) + " имеется только " + Остаток);
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли; [247]
КонецЕсли;
КонецЦикла;
КонецПроцедуры
КонецЕсли;
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("СписокНоменклатурыДокумента", ПереченьНоменклатуры.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("Ссылка",Ссылка);
ВыборкаРезультатаЗапроса = Запрос.Выполнить().Выбрать();
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
//Проверить остаток при оперативном проведении
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Остаток = ?(ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе = Null, 0, ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе);
Если Остаток < ВыборкаРезультатаЗапроса.Количество Тогда
Сообщить("Материала " + СокрЛП(ВыборкаРезультатаЗапроса.Номенклатура) + " имеется только " + Остаток);
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецЕсли;
//Сформировать движения
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
// регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
// регистр СтоимостьМатериалов Расход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход; [248]
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
//расчитать стоимость материала
СтоимостьМатериала = ?(ВыборкаРезультатаЗапроса.КоличествоОстаток = Null, 0,
ВыборкаРезультатаЗапроса.СтоимостьОстаток / ВыборкаРезультатаЗапроса.КоличествоОстаток);
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
КонецЕсли;
// регистр Продажи
Движение = Движения.Продажи.Добавить();
Движение.Период = Дата;
Движение.Номенклатура = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Клиент = Клиент;
Движение.Мастер = Мастер;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
Движение.Выручка = ВыборкаРезультатаЗапроса.Сумма;
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
Иначе
Движение.Стоимость = 0;
КонецЕсли;
КонецЦикла;
// записать движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Продажи.Записать();
КонецПроцедуры
В заключение следует сделать небольшое отступление, которое касается задания параметров виртуальных таблиц, использовавшихся в наших запросах.[249]
Как в первом, так и во втором запросах мы использовали условие что материал должен находиться в списке значений, задаваемом одним из параметров запроса:
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК СтоимостьМатериаловОстатки
...
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(
| &МоментВремени,
| Материал В
| (ВЫБРАТЬ РАЗЛИЧНЫЕ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура
| ИЗ
| Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка))
...
Теперь мы можем на некоторое время отвлечься от запросов, с которыми мы достаточно "плотно" работали в этой главе, и обратить свое внимание на не менее интересные возможности, которые предоставляет разработчику платформа 1С:Предприятие 8.0.[250]
Основные сведения о распределенных информационных базах
Как мы уже говорили выше, распределенная информационная база должна иметь четко определенную древовидную структуру. Количество уровней в такой структуре не ограничено, главное - между двумя связанными узлами всегда должно быть определено отношение "главный - подчиненный":

Таким образом, любой узел этой структуры может иметь произвольное количество подчиненных узлов (в том числе и ни одного). Кроме этого все узлы, кроме одного, должны иметь по одному главному узлу, и один узел не будет иметь главного узла - это корневой узел.
Такое жесткое задание структуры узлов необходимо для определения порядка миграции изменений данных и изменений конфигурации.
Конфигурация может быть изменена только в узле, не имеющем главного узла (то есть в корневом узле). Изменения данных могут выполняться в любом узле.
Изменения конфигурации будут передаваться от главного к подчиненным узлам. Изменения данных могут передаваться между любыми связанными узлами. [427]
Разрешение коллизий также будет производиться исходя Из отношения "главный–подчиненный". Если изменения выполнены одновременно и в главном, и в подчиненном узле, при обмене данными будут приняты только изменения главного узла, а изменения подчиненного отвергнуты.
Для любого подчиненного узла возможно создание начального образа - информационной базы, созданной на основании конфигурации и данных главного узла, в соответствии с правилами определяемыми планом обмена. Процедура создания начального образа узла может выполняться неоднократно, при этом удаляются все записи изменений в базе главного узла для подчиненного узла. Сразу после создания начальный образ готов к обмену с главным узлом.
Создание начального образа является рекомендуемым способом создания подчиненного узла в распределенной информационной базе.
в поле, хранящем реквизит табличной
Например, если взять наш документ "ОказаниеУслуги", то в поле, хранящем реквизит табличной части "Номенклатура" на самом деле находится внутренний идентификатор, указывающий на элемент справочника "Номенклатура":

Когда в обработчике события "ОбработкаПроведения" документа "ОказаниеУслуги" мы присваиваем значение реквизита "Номенклатура" табличной части какой-либо переменной, мы имеем дело с объектом ДокументОбъект.ОказаниеУслуги. Этот объект содержит в себе значения всех реквизитов документа и реквизитов его табличных частей. Поэтому обращение:

Однако когда мы обращаемся к виду номенклатуры как к реквизиту того элемента справочника, ссылка на который указана в табличной части документа:

Поскольку в объекте ДокументОбъект.ОказаниеУслуги есть только ссылка на элемент справочника "Номенклатура" и больше никаких данных об этом элементе нет, система возьмет эту ссылку и обратится по ней в кэш объектов, в надежде найти там данные того объекта, ссылка на который у нее есть. Если кэш объектов не будет иметь нужных данных, он обратится к базе данных с тем, чтобы прочитать все данные объекта, ссылкой на который он обладает. После того, как все данные, хранящиеся в реквизитах нужного элемента справочника и в реквизитах его табличных частей, будут считаны в кэш объектов, кэш объектов вернет запрашиваемую ссылку, хранящуюся в реквизите "ВидНоменклатуры" справочника "Номенклатура".[236]
Как несложно догадаться, подобное обращение к базе данных требует гораздо большего количества времени, нежели просто чтение из оперативной памяти. При интерактивном заполнении документа, подобные задержки ничтожно малы, по сравнению со скоростью работы пользователя. Однако при выполнении большого количества расчетов (например, при проведении больших документов, содержащих несколько тысяч строк), разница во времени может быть довольно заметной.

Более подробно об устройстве кэша объектов можно прочитать в главе "Кэш объектов" на странице 554.
To же самое справедливо в отношении выполнения любых участков программы, критичных по производительности. Механизм запросов лучше "читает" информационную базу и может за один раз выбрать все необходимые данные, поэтому, например, в типовых решениях вы практически не увидите использования объекта СправочникВыборка<имя>.[237]
Особенности использования ссылочных данных
Термином "ссылочные данные" мы будем обозначать данные, хранящиеся в базе данных, доступ к которым возможен при помощи объектов встроенного языка вида Ссылка: СправочникСсылка<имя>, ДокументСсылка.<имя> и т.д. Для того чтобы дальнейшее изложение было более понятным, мы построим объяснение на примере получения ссылки на вид номенклатуры при проведении документа "ОказаниеУслуги".
Не все данные, хранящиеся в базе данных, являются ссылочными. Это связано с тем, что в модели данных 1С:Предприятия 8.0 существует деление на данные, представляющие объектные сущности (справочники, планы счетов, документы и т.д.), и данные, представляющие необъектные сущности (регистры сведений, регистры накопления и т.д.).
С точки зрения системы, некоторая совокупность объектных данных определяется не только значениями своих полей, но и самим фактом своего существования. Другими словами, удалив из базы некоторую совокупность объектных данных, мы не сможем вернуть систему в то же состояние, которое было до удаления. Даже если мы заново создадим ту же самую совокупность объектных данных с теми же самыми значениями полей, с точки зрения системы это будет ДРУГАЯ совокупность объектных данных. Каждую такую совокупность объектных данных, уникальную с точки зрения системы, называют объектом базы данных. Для того чтобы система могла отличить один объект базы данных от другого, каждый объект базы данных (совокупность объектных данных) имеет внутренний идентификатор. Различные объекты базы данных всегда будут иметь различные внутренние идентификаторы. Этот идентификатор хранится вместе с остальными данными объекта в специальном поле "Ссылка".
Необъектные данные хранятся в виде записей, и с точки зрения системы определяются исключительно значениями своих полей. Таким образом, удалив некоторую запись и записав после этого новую, с точно такими же значениями всех полей, мы получим то же самое состояние базы данных, которое было до удаления.
Таким образом, поскольку мы можем однозначно указать на каждый объект базы данных, у нас появляется возможность хранить [233] такой указатель в полях других таблиц базы данных, выбирать его в поле ввода, указывать в параметрах запроса при поиске по ссылке и т.д. Во всех этих случаях как раз и будет использоваться объект встроенного языка вида Ссылка. Фактически этот объект хранит только внутренний идентификатор, находящийся в поле "Ссылка".
Отчет ОстаткиМатериаловПоСвойствам
Для полного завершения картины мы создадим отчет, который будет показывать нам наличие материалов с теми или иными свойствами.
Создадим новый объект конфигурации Отчет и назовем его "ОстаткиМатериаловПоСвойствам". Запустим конструктор выходной формы, и займемся конструированием запроса.
Исходными данными для нашего запроса будут являться материал, свойство и значение свойства. Причем нужно предусмотреть возможность того, что материал выбираться не будет, а будут указываться только свойство и его значение.
Таким образом, алгоритм получения результирующих данных будет распадаться на две части: сначала, по указанным свойству и его значению, нам нужно будет выбрать все наборы свойств из регистра сведений "ЗначенияСвойствНоменклатуры", которым сопоставлены указанное свойство с указанным значением. Затем, для выбранных наборов свойств и их владельцев нам нужно будет получить остатки и обороты из регистра накопления "ОстаткиМатериалов".
Для того чтобы обеспечить такую "двухуровневую" выборку данных, мы воспользуемся возможностью создания вложенных запросов.
Сначала мы создадим вторую часть нашего алгоритма - запрос к регистру накопления "ОстаткиМатериалов".[277]
Выберем виртуальную таблицу регистра накопления "ОстаткиМатериалов.ОстаткиИОбороты". В параметрах виртуальной таблицы зададим условие отбора таким, что значение измерения регистра "НаборСвойств" должно находиться в списке, передаваемом в качестве параметра "СписокСвойств":

Для формирования такого списка наборов свойств нам и понадобится вложенный запрос к регистру сведений. Но этим мы займемся позже, а сейчас продолжим работать с регистром накопления.[278]
Из виртуальной таблицы регистра накопления "ОстаткиМатериалов.ОстаткиИОбороты" выберем следующие поля:
| · | "ОстаткиМатериаловОстаткиИОбороты.Материал", |
| · | "ОстаткиМатериаловОстаткиИОбороты.НаборСвойств, |
| · | "ОстаткиМатериаловОстаткиИОбороты.КоличествоНачальныйОстаток", |
| · | "ОстаткиМатериаловОстаткиИОбороты.КоличествоПриход", |
| · | "ОстаткиМатериаловОстаткиИОбороты.КоличествоРасход", |
| · | "ОстаткиМатериаловОстаткиИОбороты.КоличествоКонечныйОстаток": |

После этого на закладке "Объединения/Псевдонимы" зададим псевдонимы числовых полей без слова "Количество":

На закладке "Отчет" сбросим флаг "Использовать построитель отчета", а на закладке "Выходная форма" укажем, что не нужно редактировать в форме параметр "СписокСвойств".
На этом создание первого запроса завершено. Нажмем "ОК".
Откроем модуль формы и удалим элементы текста, которые нам не понадобятся. В процедуре "ДействияФормыОстаткиМатериаловПоСвойствамСформировать" [279] удалим второй параметр при вызове процедуры "ОстаткиМатериаловПоСвойствам":
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ_ПРОЦЕДУРА_ВЫЗОВА(ОстаткиМатериаловПоСвойствам)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
ТабДок = ЭлементыФормы.ПолеТабличногоДокумента;
ОстаткиМатериаловПоСвойствам(ТабДок);
//}}КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ_ПРОЦЕДУРА_ВЫЗОВА
КонецПроцедуры
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ(ОстаткиМатериаловПоСвойствам)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Макет = ОтчетОбъект.ПолучитьМакет("ОстаткиМатериаловПоСвойствам");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиМатериаловОстаткиИОбороты.Материал,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.Материал),
| ОстаткиМатериаловОстаткиИОбороты.НаборСвойств,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.НаборСвойств),
| ОстаткиМатериаловОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоПриход КАК Приход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоРасход КАК Расход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
|ИЗ
| РегистрНакопления.ОстаткиМатериалов.ОстаткиИОбороты(, , , , НаборСвойств В (&СписокСвойств)) КАК ОстаткиМатериаловОстаткиИОбороты";[280]
//Запрос.УстановитьПараметр("СписокСвойств",СписокСвойств);
Результат = Запрос.Выполнить();
...
Обладая достаточными навыками написания запросов, мы могли бы вручную, вместо "&СписокСвойств" написать текст вложенного запроса. Но, поскольку мы только осваиваем язык запросов, воспользуемся более комфортным способом: создадим текст вложенного запроса при помощи конструктора, а затем просто скопируем его в нужное нам место модуля. Для этого выполним команду Текст

В качестве исходных данных вложенного запроса выберем таблицу регистра сведений "ЗначенияСвойствНоменклатуры". Из нее выберем единственное поле - "ЗначенияСвойствМатериалов.НаборСвойств".
Зададим условия выборки. Прежде всего, владелец набора свойств должен быть равен переданному в параметре "Материал" материалу:
ЗначенияСвойствНоменклатуры.НаборСвойств.Владелед = &Материал
Затем укажем, что вид свойства должен быть равен переданному в параметре "ВидСвойства" значению:
ЗначенияСвойствНоменклатуры.ВидСвойства = &ВидСвойства [281]
И в заключение отметим, что значение свойства также будет задаваться параметром "Значение":
ЗначенияСвойствНоменклатуры.Значение = &Значение

Вложенный запрос готов. Теперь нажмем кнопку "Запрос", расположенную в нижней части окна конструктора запроса, выделим и скопируем текст запроса в буфер обмена Windows. Закроем окно с текстом запроса и нажмем "Отмена" в конструкторе запроса. Теперь вставим текст из буфера обмена вместо параметра в созданный нами ранее запрос:
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ(ОстаткиМатериаловПоСвойствам)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Макет = ОтчетОбъект.ПолучитьМакет("ОстаткиМатериаловПоСвойствам");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиМатериаловОстаткиИОбороты.Материал,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.Материал),
| ОстаткиМатериаловОстаткиИОбороты.НаборСвойств,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.НаборСвойств),
| ОстаткиМатериаловОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоПриход КАК Приход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоРасход КАК Расход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
|ИЗ
| РегистрНакопления.ОстаткиМатериалов.ОстаткиИОбороты(,,,,
| НаборСвойств В
| (ВЫБРАТЬ
| ЗначенияСвойствНоменклатуры.НаборСвойств [282]
| ИЗ
| РегистрСведений.ЗначенияСвойствНоменклатуры КАК ЗначенияСвойствНоменклатуры
| ГДЕ
| ЗначенияСвойствНоменклатуры.НаборСвойств.Владелец = &Материал
| И ЗначенияСвойствНоменклатуры.ВидСвойства = &ВидСвойства
| И ЗначенияСвойствНоменклатуры.Значение = &Значение)) КАК ОстаткиМатериаловОстаткиИОбороты";
Результат = Запрос.Выполнить();
...
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ(ОстаткиМатериаловПоСвойствам)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Макет = ОтчетОбъект.ПолучитьМакет("ОстаткиМатериаловПоСвойствам");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиМатериаловОстаткиИОбороты.Материал,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.Материал),
| ОстаткиМатериаловОстаткиИОбороты.НаборСвойств,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.НаборСвойств),
| ОстаткиМатериаловОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоПриход КАК Приход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоРасход КАК Расход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
|ИЗ
| РегистрНакопления.ОстаткиМатериалов.ОстаткиИОбороты(,,,,
| НаборСвойств В
| (ВЫБРАТЬ
| ЗначенияСвойствНоменклатуры.НаборСвойств
| ИЗ
| РегистрСведений. ЗначенияСвойствНоменклатуры КАК ЗначенияСвойствНоменклатуры [283]
| ГДЕ
|";
Если Не Материал.Пустая() тогда
Запрос.Текст = Запрос.Текст +
"ЗначенияСвойствНоменклатуры.НаборСвойств.Владелец = &Материал И
|";
КонецЕсли;
Запрос.Текст = Запрос.Текст +
" ЗначенияСвойствНоменклатуры.ВидСвойства = &ВидСвойства
| И ЗначенияСвойствНоменклатуры.Значение = &Значение)) КАК ОстаткиМатериаловОстаткиИОбороты";
Результат = Запрос.Выполнить();
...
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ(ОстаткиМатериаловПоСвойствам)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Макет = ОтчетОбъект.ПолучитьМакет("ОстаткиМатериаловПоСвойствам");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиМатериаловОстаткиИОбороты.Материал,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.Материал),
| ОстаткиМатериаловОстаткиИОбороты.НаборСвойств,
| ПРЕДСТАВЛЕНИЕ(ОстаткиМатериаловОстаткиИОбороты.НаборСвойств),
| ОстаткиМатериаловОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоПриход КАК Приход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоРасход КАК Расход,
| ОстаткиМатериаловОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
|ИЗ
| РегистрНакопления.ОстаткиМатериалов.ОстаткиИОбороты(,,,,
| НаборСвойств В
| (ВЫБРАТЬ
| ЗначенияСвойствНоменклатуры.НаборСвойств
| ИЗ
| РегистрСведений.ЗначенияСвойствНоменклатуры КАК ЗначенияСвойствНоменклатуры
| ГДЕ
|"; [284]
Если Не Материал.Пустая() тогда
Запрос.Текст = Запрос.Текст +
"ЗначенияСвойствНоменклатуры.НаборСвойств.Владелец = &Материал И
|";
КонецЕсли;
Запрос.Текст = Запрос.Текст +
" ЗначенияСвойствНоменклатуры.ВидСвойства = &ВидСвойства
| И ЗначенияСвойствНоменклатуры.Значение = &Значение)) КАК ОстаткиМатериаловОстаткиИОбороты";
Если Не Материал.Пустая() тогда
Запрос.УстановитьПараметр("Материал", Материал);
КонецЕсли;
Запрос.УстановитьПараметр("ВидСвойства", ВидСвойства);
Запрос.УстановитьПараметр("Значение", Значение);
Результат = Запрос.Выполнить();
...
Откроем форму отчета и разместим на ней три поля ввода:
"Материал" с типом СправочникСсылка.Номенклатура,
"ВидСвойства" с типом ПланВидовХарактеристикСсылка.СвойстваНоменклатуры,
"Значение" с типом Характеристика.СвойстваНоменклатуры:

Для поля ввода "Материал" установим свойство "Выбор групп и элементов" как "Элементы".
Для поля ввода "Значение" установим связь по типу с реквизитом "ВидСвойства". А для поля ввода "ВидСвойства" создадим обработчик события "ПриИзменении":
Значение = ВидСвойства.ТипЗначения.ПривестиЗначение(Значение);
КонецПроцедуры [286]
Сначала посмотрим, какие у нас есть материалы с сечением 2,5 мм2:

Затем посмотрим, какие у нас есть материалы черного цвета:

[287]
И в заключение, чтобы убедиться в правильности работы отчета посмотрим, сколько у нас электрических кабелей черного цвета:

Таким образом, вы убедились в том, что при использовании данной логической схемы мы имеем теперь возможность вести учет материалов в произвольном количестве разрезов свойств и их значений.
Следует заметить, что пример, рассмотренный нами в этой главе, не является законченным решением для данной конфигурации. Мы лишь продемонстрировали возможность ведения такого учета. Для того чтобы наша конфигурация могла полноценно использовать свойства материалов, необходимо внести соответствующие изменения в остальные регистры, документы и некоторые отчеты. [288]
Отчет ПереченьУслуг
Отчет "Перечень услуг" будет содержать информацию о том, какие услуги и по какой цене оказывает OOO "На все руки мастер". На его примере мы познакомимся с возможностью получения последних значений из периодического регистра сведений и вывода иерархических справочников.
Создадим новый объект конфигурации Отчет "ПереченьУслуг". Перейдем на закладку "Макеты" и вызовем конструктов выходной формы.
Выберем объектную (ссылочную) таблицу справочника "Номенклатура" и виртуальную таблицу регистра сведений "Цены.СрезПоследних". Для того чтобы исключить неоднозначность имен в запросе, переименуем таблицу "Номенклатура" в "СпрНоменклатура".
Вызовем диалог ввода параметров виртуальной таблицы "ЦеныСрезПоследних" и укажем, что период будет передан в параметре "ДатаОтчета". Затем выберем из таблиц следующие поля:
| · | "СпрНоменклатура.Родитель", |
| · | "СпрНоменклатура.Ссылка", |
| · | "ЦеныСрезПоследних.Цена": |

Перейдем на закладку "Связи" и сбросим флаг "Все" у таблицы регистра и установим его у таблицы справочника. [191]
На закладке "Условия" зададим условие выбора элементов справочника "Номенклатура" - выбираемые элементы должны соответствовать виду номенклатуры переданному в параметре запроса "ВидНоменклатуры":

На закладке "Объединения/Лсевдонимы" укажем, что поле "Родитель" будет иметь псевдоним "ГруппаУслуг", а поле "Ссылка" - "Услуга":

Перейдем на закладку "Итоги" и укажем, что группировка будет производиться по полю "ГруппаУслуг" с типом итогов "Элементы и иерархия", а значения суммируемых полей задавать не станем:

На закладке "Отчет" сбросим флаг "Использовать построитель отчета".
На закладке "Выходная форма" отметим, что тип параметра "ДатаОтчета" будет Дата, а параметр "ВидНоменклатуры" в форме редактироваться не будет. Нажмем "ОК". [192]
Откроем модуль формы и в процедуре "ПереченьУслуг" определим значение параметра запроса:
Запрос.УстановитьПараметр("ДатаОтчета", ДатаОтчета);
"ВЫБРАТЬ
| СпрНоменклатура.Родитель КАК ГруппаУслуг,
| ПРЕДСТАВЛЕНИЕ(СпрНоменклатура.Родитель),
| СпрНоменклатура.Ссылка КАК Услуга,
| СпрНоменклатура.Представление,
| ЦеныСрезПоследних.Цена
|ИЗ
| Справочник.Номенклатура КАК СпрНоменклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Цены.СрезПоследних(&ДатаОтчета, ) КАК ЦеныСрезПоследних
| ПО ЦеныСрезПоследних.Номенклатура = СпрНоменклатура.Ссылка
|ГДЕ
| СпрНоменклатура.ВидНоменклатуры = &ВидНоменклатуры
|ИТОГИ ПО
| ГруппаУслуг ИЕРАРХИЯ";
Теперь запустим 1С:Предприятие в режиме отладки и, прежде всего, откроем периодический регистр "Цены". [193]
Добавим в него еще одно значение для услуги "Диагностика" новая цена услуги на 01.04.2004 (это позволит нам протестировать отчет):

Теперь выполним отчет "Перечень услуг" по состоянию на 31.03.2004:

Наш отчет правильно отражает цену услуги "Диагностика" на 31.04 - 200pyб. [194]
Еще раз выполним отчет, но теперь уже на другую дату 01.04.2004:

Как видите, показана новая цена услуги "Диагностика" - 350 руб.
Таким образом, на примере этого отчета мы показали, как при помощи запроса можно получить последние значения из периодического регистра сведений и как вывести группировки по иерархии справочника. [195]
Отчет РеестрДокументовОказаниеУслуги
Первым отчетом, на основе которого мы начнем знакомиться с языком запросов, будет отчет "РеестрДокументовОказаниеУслуги". Этот отчет просто будет выводить список существующих в базе данных документов "ОказаниеУслуги" в порядке их дат и номеров.
Создадим в конфигураторе новый объект конфигурации Отчет "РеестрДокументовОказаниеУслуги". Перейдем на закладку "Макет" и запустим конструктор выходной формы.
В качестве источника данных для запроса выберем объектную (ссылочную) таблицу документов "ОказаниеУслуги". Из этой таблицы выберем следующие поля:
| · | "Дата", |
| · | "Номер", |
| · | "Склад", |
| · | "Мастер", |
| · | "Клиент": |

Обратите внимание, что при выборе полей "Склад", "Мастер" и "Клиент" в список выбранных полей подбираются также поля "Склад.Представление", "Мастер.Представление" и "Клиент.Представление". Дело в том, что в общем случае подразумевается, что эти поля будут выводиться в ячейки табличного документа. Поскольку соответствующие поля "Склад", "Мастер" и "Клиент" являются ссылочными, то в случае, если в качестве значения параметра для вывода будет передано значение-ссылка, система будет выполнять дополнительный запрос для получения представления этого поля (которое и будет выведено в документ), в результате чего вывод [166] отчета замедлится. Поэтому система, при выборе ссылочных полей, предлагает сразу же включить в список выбранных полей и представления ссылочных полей, в расчете на то, что именно они и будут использованы для вывода в документ.
После этого перейдем на закладку "Порядок" и укажем, что результат запроса должен быть сначала упорядочен по значению поля "Дата", а затем - по значению поля "ОказаниеУслуги.Ссылка":

Перейдем на закладку "Отчет" и сбросим флаг "Использовать построитель отчета":
Сбросим флаг "Использовать построитель отчета"...

Нажмем "ОК". Конструктор сформирует форму отчета и макет. Откроем модуль формы и найдем в нем процедуру "РеестрДокументовОказаниеУслуги". В этой процедуре как раз [167] формируется текст запроса, который будет использован для получения интересующих нас данных:
"ВЫБРАТЬ
| ОказаниеУслуги.Дата КАК Дата,
| ОказаниеУслуги.Номер КАК Номер,
| ОказаниеУслуги.Склад,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Склад),
| ОказаниеУслуги.Мастер,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Мастер),
| ОказаниеУслуги.Клиент,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Клиент)
|ИЗ
| Документ.ОказаниеУслуги КАК ОказаниеУслуги
|
|УПОРЯДОЧИТЬ ПО
| Дата,
| Номер";
"ВЫБРАТЬ
| ОказаниеУслуги.Дата КАК Дата,
| ОказаниеУслуги.Номер КАК Номер,
| ОказаниеУслуги.Склад,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Склад),
| ОказаниеУслуги.Мастер,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Мастер),
| ОказаниеУслуги.Клиент,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Клиент)
|ИЗ
| Документ.ОказаниеУслуги КАК ОказаниеУслуги
После ключевого слова ИЗ указываются источники данных - исходные таблицы запроса, содержимое которых обрабатывается в запросе. В данном случае это объектная (ссылочная) таблица "Документ.ОказаниеУслуги". После ключевого слова КАК указывается псевдоним источника данных. В нашем случае это "ОказаниеУслуги". В дальнейшем к этому источнику данных можно будет обращаться в тексте запроса, используя псевдоним.
Такое обращение мы видим в описании полей выборки:
| ОказаниеУслуги.Дата КАК Дата,
| ОказаниеУслуги.Номер КАК Номер,
| ОказаниеУслуги.Склад,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Склад),
| ОказаниеУслуги.Мастер,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Мастер),
| ОказаниеУслуги.Клиент,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Клиент)
После части описания запроса в нашем примере следует часть упорядочивания результатов:
| Дата,
| Номер";
Теперь обратим внимание на то, как выводится результат запроса в табличный документ.
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ(РеестрДокументовОказаниеУслуги)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Макет = ОтчетОбъект.ПолучитьМакет("РеестрДокументовОказаниеУслуги");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОказаниеУслуги.Дата КАК Дата,
| ОказаниеУслуги.Номер КАК Номер,
| ОказаниеУслуги.Склад,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Склад),
| ОказаниеУслуги.Мастер,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Мастер),
| ОказаниеУслуги.Клиент,
| ПРЕДСТАВЛЕНИЕ(ОказаниеУслуги.Клиент)
|ИЗ
| Документ.ОказаниеУслуги КАК ОказаниеУслуги
|
|УПОРЯДОЧИТЬ ПО
| Дата,
| Номер";
Результат = Запрос.Выполнить();
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ОбластьПодвалТаблицы = Макет.ПолучитьОбласть("ПодвалТаблицы");
ОбластьДетальныхЗаписей = Макет.ПолучитьОбласть("Детали");
ТабДок.Очистить();
ТабДок.Вывести(ОбластьЗаголовок);
ТабДок.Вывести(ОбластьШапкаТаблицы);
ТабДок.НачатьАвтогруппировкуСтрок();
ВыборкаДетали = Результат.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетали.Уровень());
КонецЦикла;
ТабДок.ЗакончитьАвтогруппировкуСтрок();
ТабДок.Вывести(ОбластьПодвалТаблицы);
ТабДок.Вывести(ОбластьПодвал);
//}}КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ
КонецПроцедуры
В начале процедуры мы получаем макет отчета, из которого затем получаем существующие в нем области в соответствующие переменные:
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ОбластьПодвалТаблицы = Макет.ПолучитьОбласть("ПодвалТаблицы");
ОбластьДетальныхЗаписей = Макет.ПолучитьОбласть("Детали");
...
ТабДок.Очистить();
ТабДок.Вывести(ОбластьЗаголовок);
ТабДок.Вывести(ОбластьШапкаТаблицы);
ТабДок.НачатьАвтогруппировкуСтрок();
...
После этого мы получаем выборку из результата запроса, которую перебираем в цикле:
...
ВыборкаДетали = Результат.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетали.Уровень());
КонецЦикла; [171]
В заключение процедуры, мы выводим в табличный документ завершающие области макета:
ТабДок.ЗакончитьАвтогруппировкуСтрок();
ТабДок.Вывести(ОбластьПодвалТаблицы);
ТабДок.Вывести(ОбластьПодвал);
...

Таким образом на примере этого отчета мы продемонстрировали, как использовать конструктор выходной формы и познакомились с некоторыми основными конструкциями языка запросов. [172]
Отчет Рейтинг услуг
Отчет "Рейтинг услуг" будет содержать информацию о том, выполнение каких услуг принесло OOO "На все руки мастер" наибольшую прибыль в указанном периоде. На примере отчета "Рейтинг услуг" мы проиллюстрируем, как отбирать данные в некотором периоде, как задавать параметры запроса и как использовать в запросе данные из нескольких таблиц и включать в результат запроса все данные одного из источников.
Создадим новый объект конфигурации Отчет "РейтингУслуг". Перейдем на закладку "Макеты" и вызовем конструктор выходной формы.
Выберем объектную (ссылочную) таблицу справочника "Номенклатура" и виртуальную таблицу регистра накопления "Продажи.Обороты". Для того чтобы исключить неоднозначность имен в запросе, переименуем таблицу "Номенклатура" в "СпрНоменклатура" (контекстное меню правой кнопки мыши).
Затем установим курсор на таблицу "ПродажиОбороты" и вызовем диалог ввода параметров виртуальной таблицы:
Откроем диалог ввода параметров виртуальной таблицы

[173]
Укажем, что начало и конец периода будут переданы в соответствующих параметрах "ДатаНачала" и "ДатаОкончания" (символ "&" перед именем указывает, что это параметр запроса):

Затем выберем из таблиц поля "СпрНоменклатура.Ссылка" и "ПродажиОбороты.ВыручкаОборот":

Перейдем на закладку "Связи" и увидим, что конструктор уже создал связь между двумя выбранными таблицами - значение изменения регистра "Номенклатура" должно быть равно ссылке на элемент справочника "Номенклатура". [174]
Единственное, что нам останется сделать, это сбросить флаг "Все" у таблицы регистра и установить его у таблицы справочника.
Будем выбирать все элементы из справочника "Номенклатура"

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

[175]
В дальнейшем, перед выполнением запроса, мы передадим в параметр "ВидНоменклатуры" - соответствующее значение перечисления.
Перейдем на закладку "Объединения/Псевдонимы" и укажем, что представление элемента справочника будет иметь псевдоним "Услуга", а поле регистра будет иметь псевдоним "Выручка":

Перейдем на закладку "Порядок" и укажем, что результат запроса должен быть отсортирован по убыванию значения поля "Выручка".
На закладке "Итоги" определим, что нужно выводить общие итоги, и они должны представлять собой сумму значений поля "Выручка":

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

Нажмем "ОК". Платформа сформирует макет и форму отчета Откроем модуль формы и найдем в нем процедуру "РейтингУслуг". [176]
В этой процедуре, в той части, где выполняется установка параметров запроса, определим значение параметра "ВидНоменклатуры" (исправления выделены жирным шрифтом):
| СпрНоменклатура.Ссылка КАК Услуга,
| СпрНоменклатура.Представление,
| ПродажиОбороты.ВыручкаОборот КАК Выручка
|ИЗ
| Справочник.Номенклатура КАК СпрНоменклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, , ) КАК ПродажиОбороты
| ПО ПродажиОбороты.Номенклатура = СпрНоменклатура.Ссылка
|ГДЕ
| СпрНоменклатура.ЭтоГруппа = ЛОЖЬ
| И СпрНоменклатура.ВидНоменклатуры = &ВидНоменклатуры
|
|УПОРЯДОЧИТЬ ПО
| Выручка УБЫВ
|ИТОГИ
| СУММА(Выручка)
|ПО
| ОБЩИЕ";
Запрос.УстановитьПараметр("ВидНоменклатуры", Перечисления.ВидыНоменклатуры.Услуга);
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
"ВЫБРАТЬ
| СпрНоменклатура.Ссылка КАК Услуга,
| СпрНоменклатура.Представление,
| ПродажиОбороты.ВыручкаОборот КАК Выручка
|ИЗ
| Справочник.Номенклатура КАК СпрНоменклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&ДатаНачала, [177] &ДатаОкончания, , ) КАК ПродажиОбороты
| ПО ПродажиОбороты.Номенклатура = СпрНоменклатура.Ссылка
|ГДЕ
| СпрНоменклатура.ЭтоГруппа = ЛОЖЬ
| И СпрНоменклатура.ВидНоменклатуры = &ВидНоменклатуры
|
|УПОРЯДОЧИТЬ ПО
| Выручка УБЫВ
|ИТОГИ
| СУММА(Выручка)
|ПО
| ОБЩИЕ";
При описании источников запроса (после ключевого слова ИЗ), использована возможность определения нескольких источников запроса:
| Справочник.Номенклатура КАК СпрНоменклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, , ) КАК ПродажиОбороты
| ПО ПродажиОбороты.Номенклатура = СпрНоменклатура.Ссылка
ЛЕВОЕ СОЕДИНЕНИЕ означает, что в результат запроса надо включить комбинации записей из обоих источников, которые соответствуют указанному после ключевого слова ПО условию. Кроме этого, в результат запроса надо включить еще и записи из первого (указанного слева от слова СОЕДИНЕНИЕ) источника, для которых не найдено соответствующих условию записей из второго источника. [178]
В описании первого источника и условия соединения нет для нас ничего нового, а вот при описании второго источника, используется возможность задания параметров виртуальной таблицы запроса:
Если заранее известно, что пользователя не будут интересовать результаты работы отчета в периодах, указанных с точностью до секунд, то следует учесть следующую особенность: по умолчанию время в дате установлено в 00:00:00. Поэтому, если не предпринять специальных мер, получится, что когда пользователь задаст период отчета с 01.03.2004 по 31.03.2004, итоги регистра будут рассчитаны с начала дня 01.03.2004 00:00:00 по начало дня 31.03.2004 00:00:00. Таким образом, данные за 31 число, отличные от начала дня, в расчет не войдут, что сильно удивит пользователя.
Для того чтобы исключить эту ситуацию, следует сделать две вещи.
Во-первых, в форме отчета ограничить пользователя в возможностях ввода даты начала и даты окончания, установив для соответствующих полей ввода состав даты как "Дата":
Определим состав даты...

[179]
Во-вторых, при передаче параметров использовать встроенную функцию КонецДня(). Для этого вернемся в модуль формы отчета и внесем необходимые изменения (добавления выделены жирным шрифтом):
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ_ПРОЦЕДУРА_ВЫЗОВА(РейтингУслуг)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
ТабДок = ЭлементыФормы.ПолеТабличногоДокумента;
РейтингУслуг(ТабДок, Неопределено, ДатаНачала, КонецДня(ДатаОкончания));
//}}КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ_ПРОЦЕДУРА_ВЫЗОВА
КонецПроцедуры
| СпрНоменклатура.Ссылка КАК Услуга,
| СпрНоменклатура.Представление,
| ПродажиОбороты.ВыручкаОборот КАК Выручка
|ИЗ
| Справочник.Номенклатура КАК СпрНоменклатура
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, , ) КАК ПродажиОбороты
| ПО ПродажиОбороты.Номенклатура = СпрНоменклатура.Ссылка
|ГДЕ
| СпрНоменклатура.ЭтоГруппа = ЛОЖЬ
| И СпрНоменклатура.ВидНоменклатуры = &ВидНоменклатуры
Далее в запросе следует часть упорядочивания результатов, а за ней - новая для нас часть, которая не встречалась ранее - описание итогов:
| СУММА(Выручка)
|ПО
| ОБЩИЕ";
Теперь, когда мы закончили знакомиться с текстом запроса, запустим 1С:Предприятие в режиме отладки и посмотрим, как работает наш отчет.
Зададим период отчета с 01.03.2004 по 30.04.2004. Результат будет выглядеть следующим образом:

[181]
Теперь изменим дату окончания на 31.03.2004 и убедимся, что данные за 31 марта попадают в отчет:

Таким образом, на примере этого отчета мы продемонстрировали, как отбирать данные в некотором периоде, как задавать параметры запроса и как использовать в запросе данные из нескольких таблиц и включать в результат запроса все данные одного из источников. [182]
Отчет РейтингКлиентов
Отчет "Рейтинг клиентов" будет показывать, каков доход от оказания услуг каждому из клиентов за все время работы OOO "На все руки мастер". На его примере мы продемонстрируем возможность использования диаграммы для отображения результата запроса.
Здесь стоит сделать оговорку о том что, используя построитель отчета, можно вывести данные в диаграмму исключительно с помощью конструктора выходной формы, что мы и покажем в конце главы. Однако для того, чтобы понимать, как устроена диаграмма, и каким образом можно заполнить ее данными, мы рассмотрим сначала более подробный вариант.
На примере создания второго универсального
На примере создания второго универсального отчета мы рассмотрим способы непосредственного управления настройками построителя отчета и возможность формирования макетов на основе вариантов стандартного оформления.
Для более легкого понимания мы будем использовать практически тот же самый запрос по регистру накопления "Продажи". Таким образом, можно сказать, что в этом отчете мы просто покажем другой вариант управления настройками построителя отчета.
Создадим новый объект конфигурации Отчет с именем "Универсальный2".
На закладке "Данные" создадим реквизит отчета с именем "ПостроительОтчета" и типом ПостроительОтчета. На закладке "Формы" с помощью конструктора создадим основную форму отчета и приступим к ее редактированию.
Расположим в форме две надписи с именами "Поля" и "Порядок" и заголовками "Поля:" и "Порядок:" соответственно:

Под каждым текстовым полем расположим командную панель и табличное поле с именами "КоманднаяПанельПоля" и [216] "ТабличноеПолеПоля" (соответственно "КоманднаяПанельПорядок" и "ТабличноеПолеПорядок"):

Теперь для табличного поля "ТабличноеПолеПоля" зададим источник данных как ОтчетОбъект.ПостроительОтчета.ВыбранныеПоля:

[217]
После этого для командной панели "КоманднаяПанельПоля" установим флаг "Автозаполнение" и в качестве источника действий укажем ТабличноеПолеПоля:

Затем аналогичные действия произведем для другой командной панели и табличного поля.[218]
Табличному полю "ТабличноеПолеПорядок" укажем источник данных ОтчетОбъект.ПостроительОтчета.Порядок, и у командной панели "КоманднаяПанельПорядок" поднимем флаг "Автозаполнение" и укажем в качестве источника действий ТабличноеПолеПорядок:

Путем этих несложных действий мы с вами связали элементы управления, расположенные в форме, со свойствами построителя отчета "ВыбранныеПоля" и "Порядок". Свойство "ВыбранныеПоля" позволяет управлять списком полей, которые войдут в результат запроса, а свойство "Порядок" позволяет настраивать порядок вывода строк результата запроса.
Кроме этого, для того, чтобы пользователь мог настраивать значения этих полей, мы расположили в форме две командные панели, связанные с этими табличными полями. Используя свойства командных панелей "Автозаполнение" и "ИсточникДействий" мы добились автоматического формирования команд в командных панелях, исходя из типа данных, содержащихся в каждом из табличных полей.

О связи элементов управления и данных, можно прочитать в разделе "Данные и элементы управления" на странице 502. [219]

Теперь откроем модуль формы и добавим в него текст запроса для построителя отчета:
КонецПроцедуры
ПостроительОтчета.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.Клиент КАК Клиент,
| Продажи.Мастер КАК Мастер,
| Продажи.Количество КАК Количество,
| Продажи.Выручка КАК Выручка,
| Продажи.Стоимость КАК Стоимость
|
|{ВЫБРАТЬ
| Номенклатура.*,
| Клиент.*,
| Мастер.*,
| Количество.*,
| Выручка.*,
| Стоимость.*}
|ИЗ [220]
| РегистрНакопления.Продажи КАК Продажи
|
|{УПОРЯДОЧИТЬ ПО Номенклатура.*, Клиент.*, Мастер.*}
|
|ИТОГИ СУММА(Количество), Сумма(Выручка), Сумма(Стоимость)
| ПО ОБЩИЕ";
Конструкция ВЫБРАТЬ позволяет предоставить пользователю возможность выбирать в качестве полей запроса как сами исходные поля запроса, так и все поля "через точку" от данных полей.
Конструкция УПОРЯДОЧИТЬ ПО предоставляет пользователю возможность упорядочивать строки результата запроса.
Теперь, для того, чтобы привести состав полей в "исходное" состояние, добавим команду очистки выбранных полей построителя отчета, и затем в обработчик "КнопкаСформироватьНажатие" вставим команды выполнения построителя отчета:
ПостроительОтчета.МакетОформления = ПолучитьМакетОформления(ПолеВыбораОформление);
ПостроительОтчета.ОформитьМакет();
ПостроительОтчета.Выполнить();
ПостроительОтчета.Вывести();
КонецПроцедуры
ПостроительОтчета.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.Клиент КАК Клиент,
| Продажи.Мастер КАК Мастер,
| Продажи.Количество КАК Количество,
| Продажи.Выручка КАК Выручка,
| Продажи.Стоимость КАК Стоимость
|
|{ВЫБРАТЬ
| Номенклатура.*,
| Клиент.*,
| Мастер.*,
| Количество.*,
| Выручка.*, [221]
| Стоимость.*}
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|
|{УПОРЯДОЧИТЬ ПО Номенклатура.*, Клиент.*, Мастер.*}
|
|ИТОГИ СУММА(Количество), Сумма(Выручка), Сумма(Стоимость)
| ПО ОБЩИЕ";
ПостроительОтчета.ВыбранныеПоля.Очистить();
Здесь следует сказать о том, что построитель отчета предоставляет возможность полностью формировать макет будущего отчета, как задавая его целиком (свойство "Макет"), так и путем описания отдельных областей макета (свойства "МакетДетальныхЗаписей", "МакетЗаголовка" и т.д.).
Теперь, для завершения нашего универсального отчета следует заполнить список выбора поля выбора "ПолеВыбораОформление" и установить начальное значение поля:
ПостроительОтчета.МакетОформления = ПолучитьМакетОформления(ПолеВыбораОформление);
ПостроительОтчета.ОформитьМакет();
ПостроительОтчета.Выполнить();
ПостроительОтчета.Вывести();
КонецПроцедуры
ПостроительОтчета.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.Клиент КАК Клиент, [222]
| Продажи.Мастер КАК Мастер,
| Продажи.Количество КАК Количество,
| Продажи.Выручка КАК Выручка,
| Продажи.Стоимость КАК Стоимость
|
|{ВЫБРАТЬ
| Номенклатура.*,
| Клиент.*,
| Мастер.*,
| Количество.*,
| Выручка.*,
| Стоимость.*}
|ИЗ
| РегистрНакопления.Продажи КАК Продажи
|
|{УПОРЯДОЧИТЬ ПО Номенклатура.*, Клиент.*, Мастер.*}
|
|ИТОГИ СУММА(Количество), Сумма(Выручка), Сумма(Стоимость)
| ПО ОБЩИЕ";
ПостроительОтчета.ВыбранныеПоля.Очистить();
СписокВыбора = ЭлементыФормы.ПолеВыбораОформление.СписокВыбора;
СписокВыбора.Добавить(СтандартноеОформление.БезОформления, "БезОформления");
СписокВыбора.Добавить(СтандартноеОформление.Апельсин, "Апельсин");
СписокВыбора.Добавить(СтандартноеОформление.Асфальт, "Асфальт");
СписокВыбора.Добавить(СтандартноеОформление.Бирюза, "Бирюза");
СписокВыбора.Добавить(СтандартноеОформление.Текстиль, "Текстиль");
ПолеВыбораОформление = СтандартноеОформление.БезОформления;
Выберем поля: "Мастер", "Номенклатура.ВидНоменклатуры", "Номенклатура" и "Выручка". Зададим следующий порядок сортировки:
| · | "Мастер" по возрастанию, |
| · | "Номенклатура.ВидНоменклатуры" по убыванию, |
| · | "Номенклатура" по возрастанию.[223] |

Теперь изменим условия формирования отчета. Выберем поля "Клиент", "Номенклатура" и "Выручка", порядок сортировки будет по возрастанию значения поля "Клиент", а вариант оформления - "Асфальт":

Таким образом, на примере этого отчета вы познакомились с возможностью задания условий для построителя отчета и одним из способов формирования макета отчета на основе интерактивного выбора пользователя.[224]
Отчет УниверсальныйЗ
Посмотрим, как будет выглядеть отчет "Универсальный2", если, при создании его в конструкторе выходной формы, указать использование построителя отчета.
Создадим новый объект конфигурации Отчет с именем "УниверсальныйЗ". Запустим конструктор выходной формы, и выберем все поля из виртуальной таблицы регистра накопления "Продажи.Обороты".
На закладке "Итоги" отметим получение общих итогов и перейдем на закладку "Отчет":

Используя построитель отчета можно вывести результат запроса в табличный документ, сводную таблицу, диаграмму или сводную Диаграмму. Для каждого выбранного представления данных можно настроить параметры оформления (например, выбрать вариант стандартного оформления) и некоторые способы формирования [225] представления (например, для табличного документа - размещение группировок, реквизитов, итогов, наличие группировок и т.д.).
В нашем случае согласимся с параметрами, которые конструктор предложил по умолчанию, единственное, что мы изменим - вариант стандартного оформления установим "Асфальт".
Перейдем на закладку "Выходная форма" и откроем закладку: "Форма настройки построителя отчета":

Дело в том, что кроме самой формы отчета, на которой будет расположено представление данных, конструктор формирует сразу же форму настройки отчета, позволяющую пользователю интерактивно настраивать параметры отчета. В конструкторе мы имеем возможность выбрать, какие из параметров настройки будут доступны пользователю и, кроме того, определить, на какой из форм будет расположена настройка отбора: либо в форме настроек отчета, либо прямо на самой форме отчета.
В нашем случае мы снова согласимся с тем, что конструктор предлагает по умолчанию, и нажмем "ОК".
Конструктор сформирует форму отчета и форму настроек отчета.[226]
Запустим 1С:Предприятие в режиме отладки, откроем отчет "УниверсальныйЗ", нажмем кнопку "Настройка..." и установим параметры выбранных полей и порядка такими же, как в последнем примере с отчетом "Универсальный2":
| · | выбранные поля: "Клиент", "Номенклатура", "ВыручкаОборот", |
| · | порядок: "Клиент" по возрастанию: |

Как вы видите, мы получили тот же самый результат, однако достигнуть его оказалось гораздо легче; кроме этого, в отчете появилась дополнительная функциональность - возможность установки отбора и изменения состава выбранных полей и порядка вывода результатов.
Отчет ВыручкаМастеров
Отчет "Выручка мастеров" будет содержать информацию о том, какая выручка была получена OOO "На все руки мастер" благодаря работе каждого из мастеров, с детализацией по всем дням в выбранном периоде и разворотом по клиентам, обслуженным в каждый из дней. На примере этого отчета мы проиллюстрируем, как строить многоуровневые группировки в запросе, как обходить все даты в выбранном периоде и как управлять состоянием группировок в табличном документе.
Создадим новый объект конфигурации Отчет "ВыручкаМастеров". Перейдем на закладку "Макет" и запустим конструктор выходной формы.
Выберем виртуальную таблицу регистра накопления "Продажи.Обороты". Зададим для нее значения параметров "НачалоПериода", "КонецПериода" и "Периодичность":

После этого выберем из таблицы следующие поля:
| · | "ПродажиОбороты.Мастер", |
| · | "ПродажиОбороты.Период", |
| · | "ПродажиОбороты.Клиент", |
| · | "ПродажиОбороты.ВыручкаОборот": |

Теперь перейдем на закладку "Объединения/Псевдонимы" и зададим псевдоним "Выручка" для поля "ПродажиОбороты.ВыручкаОборот":

На закладке "Порядок" определим, что результат запроса будет отсортирован по возрастанию значения поля "Период" и на закладке "Итоги" зададим получение общих итогов и промежуточных итогов по полям "Мастер" и "Период":

[184]
На закладке "Отчет" сбросим флаг "Использовать построитель отчета".
На закладке "Выходная форма" отметим, что тип параметров "ДатаНачала" и "ДатаОкончания" будет Дата. Нажмем "OK".
Сразу, как и в предыдущем отчете, определим состав даты для полей ввода, расположенных в форме, и затем в вызове процедуры "ВыручкаМастеров" уточним передачу последнего параметра при помощи функции КонецДня():
//{{КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ_ПРОЦЕДУРА_ВЫЗОВА(ВыручкаМастеров)
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
ТабДок = ЭлементыФормы.ПолеТабличногоДокумента;
ВыручкаМастеров(ТабДок, ДатаНачала, КонецДня(ДатаОкончания));
//}}КОНСТРУКТОР_ВЫХОДНЫХ_ФОРМ_ПРОЦЕДУРА_ВЫЗОВА
КонецПроцедуры
"ВЫБРАТЬ
| ПродажиОбороты.Мастер КАК Мастер,
| ПРЕДСТАВЛЕНИЕ(ПродажиОбороты.Мастер),
| ПродажиОбороты.Период КАК Период,
| ПродажиОбороты.Клиент,
| ПРЕДСТАВЛЕНИЕ(ПродажиОбороты.Клиент),
| ПродажиОбороты.ВыручкаОборот КАК Выручка
|ИЗ
| РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, День, ) КАК ПродажиОбороты
|
|УПОРЯДОЧИТЬ ПО
| Период
|ИТОГИ
| СУММА(Выручка)
|ПО
| ОБЩИЕ,
| Мастер,
| Период"; [185]
| РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, День, ) КАК ПродажиОбороты
Далее в тексте запроса следует известная нам часть упорядочивания результатов, и в следующей части - описание итогов - мы видим новые для нас строки:
| СУММА(Выручка)
|ПО
| ОБЩИЕ,
| Мастер,
| Период";
Теперь, чтобы наглядно продемонстрировать смысл наших дальнейших действий, запустите 1С:Предприятие в режиме отладки и посмотрите на результат работы отчета "Выручка мастеров" за период c 01.03.2004 по 30.04.2004:

Если вы помните, в начале раздела мы говорили, что этот отчет должен показывать данные с детализацией по всем дням в выбранном периоде. У нас же отображаются только те дни, для которых существуют ненулевые записи в таблице регистра накопления. Поэтому сейчас мы займемся тем, что изменим текст программы таким образом, чтобы в отчет попадала каждая дата из указанного периода.
Вернемся к модулю отчета "ВыручкаМастеров" и в части описания итогов запроса уточним, каким образом должны рассчитываться итоги по полю "Период":
"ВЫБРАТЬ
| ПродажиОбороты.Мастер КАК Мастер,
| ПРЕДСТАВЛЕНИЕ(ПродажиОбороты.Мастер),
| ПродажиОбороты.Период КАК Период,
| ПродажиОбороты.Клиент,
| ПРЕДСТАВЛЕНИЕ(ПродажиОбороты.Клиент),
| ПродажиОбороты.ВыручкаОборот КАК Выручка [187]
|ИЗ
| РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, День, ) КАК ПродажиОбороты
|
|УПОРЯДОЧИТЬ ПО
| Период
|ИТОГИ
| СУММА(Выручка)
|ПО
| ОБЩИЕ,
| Мастер,
| Период ПЕРИОДАМИ(День, &ДатаНачала, &ДатаОкончания)";
И для того, чтобы все эти итоги попали в итоговый табличный документ, нам нужно будет уточнить порядок вывода итогов в выборке результата запроса:
Пока ВыборкаМастер.Следующий() Цикл
ОбластьМастер.Параметры.Заполнить(ВыборкаМастер);
ТабДок.Вывести(ОбластьМастер, ВыборкаМастер.Уровень());
ВыборкаПериод = ВыборкаМастер.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период","Все");
Пока ВыборкаПериод.Следующий() Цикл
ОбластьПериод.Параметры.Заполнить(ВыборкаПериод);
ТабДок.Вывести(ОбластьПериод, ВыборкаПериод.Уровень());
ВыборкаДетали = ВыборкаПериод.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетали.Уровень());
КонецЦикла;
КонецЦикла;
КонецЦикла; [188]
Запустим 1С:Предприятие в режиме отладки и выполним отчет "ВыручкаМастеров" за период с 20.03.2004 по 20.04.2004.
В целях экономии неинформативного пространства книги, мы не будем приводить результат работы отчета, но на словах объясним, что результат отчета будет содержать по 32 строки дат для каждого сотрудника.
Очевидно, что такой внешний вид отчета абсолютно "нечитабелен", поэтому мы снова вернемся к модулю отчета и внесем небольшие уточнения в алгоритм вывода областей табличного документа:
ОбластьМастер.Параметры.Заполнить(ВыборкаМастер);
ТабДок.Вывести(ОбластьМастер, ВыборкаМастер.Уровень());
ВыборкаПериод = ВыборкаМастер.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период","Все");
Пока ВыборкаПериод.Следующий() Цикл
ОбластьПериод.Параметры.Заполнить(ВыборкаПериод);
ТабДок.Вывести(ОбластьПериод, ВыборкаПериод.Уровень(),,Ложь);
ВыборкаДетали = ВыборкаПериод.Выбрать();
Пока ВыборкаДетали.Следующий() Цикл
ОбластьДетальныхЗаписей.Параметры.Заполнить(ВыборкаДетали);
ТабДок.Вывести(ОбластьДетальныхЗаписей, ВыборкаДетали.Уровень());
КонецЦикла;
КонецЦикла;
КонецЦикла;
Запустим 1С:Предприятие в режиме отладки и снова выполним отчет "ВыручкаМастеров" за период с 20.03.2004 по 20.04.2004. [189]
На этот раз результат выглядит гораздо лучше:

Итак, на примере этого отчета мы продемонстрировали, как строить многоуровневые группировки в запросе, как обходить все даты в выбранном периоде и как управлять состоянием группировок в табличном документе. [190]
мы создадим отчет, аналогичный отчету
Tеперь, мы создадим отчет, аналогичный отчету "ВыручкаМастеров", который будет выводить результат в сводную диаграмму.
Откроем конфигуратор и создадим новый объект [227] конфигурации Отчет с именем "ВыручкаМастеров2". Запустим конструктор выходной формы, и выберем поля "Мастер", "Клиент", "ВыручкаОборот" и "СтоимостьОборот" из виртуальной таблицы регистра накопления "Продажи". На закладке "Итоги" укажем группировочные поля "Мастер" и "Клиент" и суммируемые поля "ВыручкаОборот" и "СтоимостьОборот". В заключение на закладке "Отчет" отметим, что результат должен быть выведен только в сводную диаграмму. Нажмем "ОК".
Запустим 1С:Предприятие в режиме отладки и откроем отчет "ВыручкаМастеров2". На закладке "Настройка" укажем, что порядок вывода должен быть по убыванию значения поля "ВыручкаОборот". После этого двойным щелчком мыши по полю сводной диаграммы откроем окно выбора параметров диаграммы и в точки диаграммы поместим поле "Мастер", в серии - поле "Клиент", а поля "ВыручкаОборот" и "СтоимостьОборот" поместим в данные:

Теперь зададим условие отбора таким, что значение поля "Номенклатура.ВидНоменклатуры" должно быть равно "Материал" (для ввода условия отбора можно использовать клавишу "Insert"). И в заключение, после того как диаграмма будет заново сформирована, раскроем группу серий "ВыручкаОборот":

Таким образом, на примере этого отчета мы продемонстрировали возможность использования сводной диаграммы и построителя отчета при создании отчета конструктором выходной формы.
Как вы видите, использование этих инструментов позволяет предоставить пользователю достаточно широкие возможности по интерактивной работе с данными и в то же время упрощает задачу разработчика, сводя ее, в большинстве случаев, к визуальному описанию параметров будущего отчета.[229]
Отображение существующего результата анализа
Объект ПостроительОтчетаАнализаДанных может быть использован для отображения результата анализа данных, который был получен ранее. Для этого можно с помощью стандартного конструктора создать новый объект ПостроительОтчетаАнализаДанных и в методе Вывести() передать ему существующий результат анализа:

Построитель = Новый ПостроительОтчетаАнализаДанных;
Построитель.Вывести(РезультатАнализа, ТабличныйДокумент); [473]
Поиск ассоциаций
Тип анализа АнализДанныхПоискАссоциаций предназначен для поиска часто встречаемых вместе групп объектов или значений характеристик, а также выполняет поиск правил ассоциаций. Этот тип анализа может использоваться для определения часто приобретаемых вместе товаров или услуг.
Типы колонок источника данных:
| · | Не используется - колонка не используется в анализе. |
| · | Объект - колонка содержит объект, например документ "Оказание услуги". |
| · | Элемент - колонка содержит элемент, например номенклатуру из документа "Оказание услуги". |
Параметры:
| · | МинимальныйПроцентСлучаев - (Число) - минимальный процент случаев, в которых наблюдается группа элементов. Найденные группы, у которых процент случаев меньше, в отчет включены не будут. |
| · | МинимальнаяДостоверность - (Число) - минимальная достоверность правила. Найденные правила, у которых достоверность меньше, в отчет включены не будут. |
| · | МинимальнаяЗначимость - (Число) - минимальная значимость правила. Найденные правила, значимость которых меньше, в отчет включены не будут. Значимость правила - величина, характеризующая насколько правило важно. Чем выше значимость, тем интересней правило. |
| · | ПоискПоИерархии - (Булево) - необходимость поиска по иерархии. При помощи этого параметра можно указать анализу, что необходимо искать ассоциации не только среди элементов, но и среди групп. |
| · | ТипОтсеченияПравил - (избыточные, покрытые) - тип отсечения найденных правил. Избыточные - отсекать избыточные правила, покрытые - отсекать правила, покрытые другими правилами. |
| · | ТипИсточникаДанных - (объектный, событийный) - тип источника данных. Анализ работает с двумя типами источника. Объектный - каждая строка источника содержит [455] объект с его характеристиками. Событийный - источник данных содержит список событий. Например, состав документа "Оказание услуги". |
| · | ИспользованиеЧисловыхЗначений - (как булево, как число) как интерпретировать числовые значения. Можно интерпретировать числовые значения как числа или как логические значения, т.е. рассматривать ноль как Ложь, а все остальные ненулевые значения как Истина. |
| · | ИгнорироватьНезаполненныеЗначения - (Булево) - Как использовать незаполненные значения. Т.е. игнорировать их или нет. |
| · | Порядок - (по достоверности, по значимости, по количеству случаев) - определяет порядок отображения данных в результате анализа. [456] |
Поиск последовательностей
Тип анализа АнализДанныхПоискПоследовательностей предназначен для выявления в источнике данных последовательных цепочек событий. Например, это может быть цепочка услуг, которые часто последовательно заказывают клиенты.
Поддерживается поиск по иерархии, что позволяет отслеживать не только последовательности конкретных событий, но и последовательности родительских групп.
Набор параметров анализа позволяет ограничивать временные расстояния между элементами искомых последовательностей, а также регулировать точность получаемых результатов.
Типы колонок источника данных:
| · | Не используется - колонка не используется в анализе. |
| · | Элемент - колонка содержит исследуемый элемент. Например, в случае исследования продаж, это может быть колонка, содержащая товар. |
| · | Последовательность - колонка содержащая последовательности. Например, это может быть контрагент. |
| · | Время - время события. |
Параметры:
| · | МинимальныйПроцентСлучаев - (Число) - минимальное число последовательностей, в которых должен наблюдаться шаблон последовательности. |
| · | ПоискПоИерархии - (Булево) - необходимо ли осуществлять поиск по иерархии. |
| · | МинимальныйИнтервал - (Булево) - признак того, что установлен минимальный интервал между наблюдаемыми событиями. Установка минимального интервала означает, что для того, чтобы элементы попали в искомую последовательность необходимо, чтобы временной интервал между элементами был не менее установленного. |
| · | ЕдиницаМинимальногоИнтервала - единица минимального интервала [459] |
| · | КратностьМинимальногоИнтервала - (Число) - кратность минимального интервала |
| · | МаксимальныйИнтервал - (Булево) - признак того, что установлен максимальный интервал между наблюдаемыми событиями. Установка максимального интервала означает, что для того, чтобы элементы попали в искомую последовательность необходимо, чтобы временной интервал между элементами был не более установленного. |
| · | ЕдиницаМаксимальногоИнтервала - единица максимального интервала |
| · | КратностьМаксимальногоИнтервала - (Число) - кратность максимального интервала |
| · | ИнтервалЭквивалентностиВремени - (Булево) - признак того, что установлен интервал эквивалентности времени между наблюдаемыми событиями. Если установлен интервал эквивалентности времени, то события, временной интервал между которыми меньше интервала эквивалентности времени считаются произошедшими в одно время. |
| · | ЕдиницаИнтервалаЭквивалентностиВремени - единица интервала эквивалентности времени |
| · | КратностьИнтервалаЭквивалентностиВремени - (Число) - кратность интервала эквивалентности времени |
| · | МинимальнаяДлина - (Число) - минимальная длина последовательности. |
| · | Порядок - (по длине, по количеству случаев) - определяет порядок отображения данных в результате анализа. [460] |
Постановка задачи
Итак, наше OOO "На все руки мастер" открыло свой филиал в городе Урюпинск и установило в нем такую же конфигурацию для учета работы филиала. В результате возникла необходимость наладить обмен данными между этими двумя базами таким образом, чтобы каждая из баз отражала полную информацию о материалах и услугах, в то время как бухгалтерский учет и расчет зарплаты велся бы в каждой базе отдельно.
Для этого мы создадим план обмена, опишем состав данных, которые будут включены в обмен и создадим несколько процедур, которые будут позволять нам формировать на жестком диске файлы обмена и соответственно загружать полученные файлы обмена с жесткого диска. Для упрощения примера мы не будем программировать какой-либо автоматический обмен файлами между двумя базами, и запуск процедуры обмена будем осуществлять вручную.
Прежде чем мы начнем непосредственно программировать алгоритм обмена, следует сказать о некоторых доработках, которые нам придется предварительно внести в нашу базу.
Эти доработки будут связаны с тем, что до сих пор мы работали только в одной базе и использовали уникальность номеров кодов справочников и номеров документов. Теперь, когда создание новых элементов справочников и новых документов будет происходить в двух базах одновременно и независимо друг от друга, нам снова необходимо обеспечить уникальность номеров кодов элементов справочников и номеров документов теперь уже "в пространстве" двух баз. Если мы этого не сделаем, то не исключена ситуация, когда в каждой из баз будут созданы, например, новые документы с одинаковыми номерами и при обмене данными возникнет конфликт, поскольку система будет пытаться записать в базу документ с номером, который уже используется другим документом.
Для исключения подобных ситуаций в каждой базе к номерам документов и кодам справочников мы будем добавлять уникальный префикс, однозначно идентифицирующий базу данных. Тогда, даже [400] если номера новых документов в двух базах совпадут, они все равно будут отличаться префиксом и конфликта не возникнет.
Для хранения префикса номеров мы используем объект конфигурации, с которым до сих пор еще не работали - это объект Константа.
Постановка задачи
В качестве примера, на котором мы проиллюстрируем использование механизма распределенных информационных баз, будет создание нескольких отделений нашего OOO "На все руки мастер". В отличие от филиалов, которые расположены в других городах, являются отдельными юридическими лицами и довольно самостоятельны в плане организации учета своей деятельности, отделения нашего OOO расположены в этом же городе, никакой юридической самостоятельностью не обладают и ведут учет в точности так, как это организовано в главном офисе. Поэтому все они используют ту же конфигурацию, что и главный офис, причем, если главный офис вносит какие-либо изменения в свою конфигурацию, все эти изменения должны быть своевременно внесены и в конфигурации отделений.
Для реализации такой схемы работы распределенная информационная база подойдет как нельзя лучше, и сначала мы организуем обмен с отделениями, используя исключительно интерактивные средства.[428]
Постановка задачи
Задача, которую мы перед собой поставим, будет заключаться в следующем: мы создадим механизм, который позволит пользователю произвольным образом описывать материалы, и, что самое главное, вести учет в разрезе всех тех описаний, которые могут быть заданы пользователем.
Описывать материалы пользователь сможет следующим образом: для каждого материала будет возможность создать некоторые (произвольные) характеристики этого материала (например, цвет, производитель и пр.). Затем, при поступлении материалов можно будет задать конкретные значения интересующих характеристик (например, при поступлении электрических кабелей можно будет указать, что они белого цвета и их сечение равно 2,5 мм2, а при поступлении резиновых шлангов указать, что они черного цвета и произведены на фирме "Fagumit, Sp. z o.o.").
В дальнейшем всегда можно будет получить информацию о том, сколько и каких материалов есть у нас, скажем, белого цвета, или сколько было израсходовано черных резиновых шлангов.
Поскольку заранее не известно, какими именно характеристиками пользователь захочет описать тот или иной материал, мы должны предоставить ему некоторый механизм, позволяющий создавать любые характеристики и, что самое важное, указывать, какой тип значения должен быть у этих характеристик. Тогда при задании значений определенной характеристики пользователь сможет выбирать значения строго в соответствии с указанным типом.
Такую возможность описания характеристик как раз и обеспечивает объект конфигурации План видов характеристик, с которым мы сейчас познакомимся.[253]
Построитель отчета анализа данных
Объект ПостроительОтчетаАнализаДанных позволяет представить данные анализа в виде табличного документа. Структура такого табличного документа определяется типом анализа, для каждого из типов анализа документ будет содержать определенный набор областей.
Объект ПостроительОтчетаАнализаДанных может использоваться для выполнения трех различных задач.
Во-первых, для визуального отображения существующего результата анализа данных.
Во-вторых, для интерактивной настройки параметров анализа данных, выполнения анализа и отображения полученного результата.
В-третьих, для настройки параметров модели прогноза.
Построитель отчета
Построитель отчета является объектом встроенного языка, позволяющим выполнять различные настройки запроса в ходе выполнения программы. Такие настройки могут выполняться как средствами встроенного языка (в результате работы некоторого алгоритма работы программы), так и интерактивно, непосредственно пользователем. [208]
Исходными данными для построителя отчета является текст запроса. На его основании построитель отчета определяет, какие параметры будут доступны для настройки и каким образом возможна настройка состава и порядка итоговых данных. Затем происходит программное или интерактивное формирование этих настроек и вывод результатов в табличный документ, диаграмму, сводную таблицу или сводную диаграмму.

Формировать параметры настройки на основании текста запроса построитель отчета может двумя способами: автоматически и на основании указаний, расположенных в тексте запроса. [209]
Автоматически параметры настройки формируются вызовом метода ЗаполнитьНастройки() следующим образом:
| · | полями, доступными для выбора в качестве полей отбора, порядка или вывода в отчет (свойство "ДоступныеПоля"), становятся все поля из списка выборки и все их подчиненные поля, |
| · | в список полей, выбранных для вывода в отчет (свойство "ВыбранныеПоля"), добавляются все поля из списка выборки, |
| · | полями, доступными для выбора в качестве измерений, становятся все поля из предложения ИТОГИ ПО и все их подчиненные поля, |
| · | в список измерений по строкам (свойство "ИзмеренияСтроки") добавляются все поля из предложения ИТОГИ ПО, |
| · | в доступные отборы (свойство "Отбор") добавляются параметры виртуальных таблиц. |
Вторым способом формирования параметров настроек построителя отчета является выделение их в тексте запроса. Для этого используются фигурные скобки "{ }". Фигурными скобками могут быть выделены параметры построителя отчета, а также некоторые синтаксические конструкции:
| · | ВЫБРАТЬ ... - описывает поля, которые пользователь сможет выбирать для вывода, |
| · | ГДЕ ... - описывает поля, на которые пользователь может накладывать ограничения, |
| · | УПОРЯДОЧИТЬ ПО ... - описывает поля для обозначения порядка, |
| · | ИТОГИ ПО ... - описывает поля, по которым будут выводиться итоговые значения. |
После того, как значения параметров указаны, вывод результатов запроса возможен как принудительно (используя методы Выполнить() и Вывести()), либо автоматически, если результаты выводятся в сводную таблицу. [210]
В качестве примера возьмем данные
В качестве примера возьмем данные регистра "Продажи": поле "Регистратор" и измерение "Номенклатура":

[457]
Результат анализа будет выглядеть следующим образом:

[458]
В качестве примера снова возьмем
В качестве примера снова возьмем данные регистра "Продажи": измерения "Номенклатура", "Контрагент" и поле "Период":

[461]
Результат анализа будет выглядеть следующим образом:

На этот раз мы проанализируем
На этот раз мы проанализируем данные справочника "Контрагенты". В качестве входных колонок мы используем поля реквизитов справочника "КоличествоРозничныхТочек", "КоличествоАвтомобилей", "ВремяРаботыОрганизации" и "ВремяЗаключенияДоговора". Прогнозируемой колонкой будет поле реквизита справочника "Контрагенты" - "ПрекращениеОтношений".

[464]
Результат анализа будет иметь следующий вид:

[465]
Для анализа мы возьмем те
Для анализа мы возьмем те же поля справочника "Контрагенты", что и в предыдущем примере: "КоличествоРозничныхТочек", "КоличествоАвтомобилей", [467] "ВремяРаботыОрганизации", "ВремяЗаключенияДоговора" и "ПрекращениеОтношений". В качестве ключа мы используем значение поля "Ссылка":

Результат анализа будет выглядеть следующим образом:

[468][469]
В качестве примера мы рассмотрим
В качестве примера мы рассмотрим использование модели прогноза данных при оформлении покупки, выполняемой контрагентом.
Предположим, что периодически проводится анализ данных базы типа поиск ассоциаций, и сохраняется актуальная модель прогноза.
Тогда, при формировании расходной накладной контрагента, мы можем использовать эту модель прогноза для того, чтобы исходя из состава расходной накладной, предложить контрагенту дополнительные товары, которые он, с большой долей вероятности, может приобрести.
Предположим, контрагент оформляет следующую покупку:

[471]
Тогда менеджер, нажав на кнопку "Предложение", может открыть список товаров, которые, с большой долей вероятности, также имеет смысл предложить этому клиенту:

[472]
Пример интерактивного обмена в распределенной информационной базе
Для построения распределенной информационной базы нам понадобится создать еще один объект конфигурации План обмена, который мы назовем "Отделения".
Для этого плана обмена мы установим свойство "Распределенная информационная база":
Установим свойство "Распределенная информационная база"...

Перейдем на закладку "Прочее" и определим тот же состав данных для обмена, что и в плане обмена "Филиалы": отметим все объекты конфигурации, относящиеся к подсистеме "УчетУслугИМатериалов".
Запустим 1С:Предприятие в режиме отладки. [429]
Откроем план обмена "Отделения" и зададим параметры центрального узла (предопределенный элемент плана обмена): код "ЦБ" и наименование "Центральная база". После этого создадим новый узел с кодом "Отд" и наименованием "Отделение". Обратите внимание, что для созданного нами узла стали доступны три иконки в командной панели формы плана обмена: "Создать начальный образ" "Записать изменения" и "Прочитать изменения":

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

[430]
На следующем шаге укажем каталог информационной базы и нажмем "Готово". Система создаст в указанном каталоге начальный образ информационной базы нашего отделения.
Запустим 1С:Предприятие, подключим новую базу нашего отделения и откроем ее в конфигураторе. Обратите внимание на то, что конфигурация нашего отделения стала защищена от изменений средствами управления распределенной информационной базой:
Конфигурация подчиненного узла защищена от изменений средствами управления распределенной информационной базой...

[431]
Запустим базу отделения в режиме отладки и откроем план обмена "Отделения":

Обратите внимание, что в базе подчиненного узла сам подчиненный узел является предопределенным узлом плана обмена, а узел центральной базы отмечен красной пиктограммой, указывающей на то, что он является главным для информационной базы отделения. Кроме этого для узла центральной базы доступны только команды "Записать изменения" и "Прочитать изменения".
Теперь проверим работу обмена данными. Откроем список констант и зададим значение константы "ПрефиксНумерации" - "ОТ".
После этого откроем справочник клиентов и добавим в него нового клиента. Затем выполним запись изменений для центральной базы (указав каталог обмена).
Перейдем в центральную базу и выполним чтение изменений в центральной базе. Убедимся, что новый клиент, созданный в базе отделения, присутствует и в центральной базе.
Теперь посмотрим, как будут переноситься изменения конфигурации между главным и подчиненным узлом. В конфигураторе центральной базы создадим новую константу с именем "НоваяКонстанта". Выполним обновление конфигурации базы данных и запустим 1С:Предприятие в режиме отладки. Откроем план обмена "Отделения" и выполним запись изменений для подчиненного узла. [432]
После этого закроем конфигуратор информационной базы отделения, и выполним чтение изменений в базе подчиненного узла. По окончании чтения система выдаст следующее сообщение:

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

[453]
Результат анализа будет выглядеть следующим образом:

[454]
Программный обмен в распределенной информационной базе
Все описанные выше действия по обмену данными в распределенной информационной базе можно выполнить программно.
Мы создадим обработку, которая будет программно выполнять для выбранного узла все те действия, которые были рассмотрены в предыдущем разделе. [433]
Для этого в конфигураторе центральной базы создадим новый объект конфигурации Обработка с именем "ОбменСОтделениями". Создадим основную форму обработки и расположим на ней поле ввода с именем "ПолеВводаОтделение", подписью "Отделение:" и типом ПланОбменаСсылка.Отделения:

После этого расположим в форме три кнопки: "Создать начальный образ" с именем "КнопкаСоздатьНачальныйОбраз", "Записать изменения" с именем "КнопкаЗаписатьИзменения" и "Прочитать изменения" с именем "КнопкаПрочитатьИзменения":

[434]
Начнем с создания обработчика нажатия кнопки "Создать начальный образ". Текст обработчика будет выглядеть следующим образом:
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога);
Диалог.Заголовок = "Укажите каталог информационной базы:";
Если Диалог.Выбрать() Тогда
ПланыОбмена.СоздатьНачальныйОбраз(ПолеВводаОтделение,"File=" + Диалог.Каталог);
Предупреждение("Создание начального образа узла завершено.");
КонецЕсли;
КонецПроцедуры
Теперь создадим обработчик нажатия кнопки "Записать изменения":
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Диалог.Заголовок = "Укажите файл обмена:";
Если Диалог.Выбрать() Тогда
// Создать и проинициализаровать объект ЗаписьХМL
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(Диалог.ПолноеИмяФайла);
// Создать объект ЗаписьСообщенияОбмена и начать запись сообщения
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, ПолеВводаОтделение);
// Записать содержимое тела сообщения обмена данными распределенной ИБ
ПланыОбмена.ЗаписатьИзменения(ЗаписьСообщения);
// Закончить запись сообщения и запись ХМL
ЗаписьСообщения.ЗакончитьЗапись(); [435]
ЗаписьXML.Закрыть();
Предупреждение("Запись изменений завершена.");
КонецЕсли;
КонецПроцедуры

Следует отметить, что метод ЗаписатьИзменения() позволяет задать максимальное число элементов данных, которые помещаются в сообщение в рамках одной транзакции базы данных. По умолчанию все данные помещаются в сообщение в рамках одной транзакции. Такой режим является рекомендуемым, так как гарантирует согласованность данных, помещаемых в сообщение.
Но при создании сообщения в многопользовательском режиме могут быть конфликты блокировок между транзакцией, в которой данные помещаются в сообщение, и транзакциями, выполняемыми другими пользователями. Для снижения вероятности возникновения таких конфликтов можно задать значение этого параметра, отличное от значения по умолчанию. Чем меньше значение параметра, тем меньше вероятность конфликта блокировок, но выше вероятность помещения в сообщение несогласованных данных.
Учитывая все вышесказанное, идеальным вариантом является выполнение обмена данными в монопольном режиме. Однако такой вариант не всегда приемлем, в силу специфики организации работы конкретных информационных баз. [436]
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Заголовок = "Укажите файл обмена:";
Если Диалог.Выбрать() Тогда
// Создать и проинициализаровать объект ЧтениеХМL
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(Диалог.ПолноеИмяФайла);
// Создать объект ЧтениеСообшенияОбмена и начать чтение сообщения
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Прочитать содержимое тела сообщения
ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения);
// Закончить чтение сообщения и чтение XML
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
Предупреждение("Чтение изменений завершено.");
КонецЕсли;
КонецПроцедуры
Проверить работу нашей обработки можно на примере, аналогичном приведенному в разделе универсального обмена Данными.[437]
Следует лишь сделать несколько заключительных замечаний.
При использовании механизма распределенных информационных баз становятся доступными четыре события объект ПланОбменаОбъект, которые позволяют управлять отправкой \ приемом данных на уровне отдельных элементов данных:
| · | ПриОтправкеДанныхГлавному(), |
| · | ПриОтправкеДанныхПодчиненному(), |
| · | ПриПолученииДанныхОтГлавного(), |
| · | ПриПолученииДанныхОтПодчиненного(). |
Сообщить("ПриОтправкеДанныхГлавному "+ЭлементДанных);
КонецПроцедуры
Процедура ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента)
Сообщить("ПриОтправкеДанныхПодчиненному "+ЭлементДанных);
КонецПроцедуры
Процедура ПриПолученииДанныхОтГлавного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
Сообщить("ПриПолученииДанныхОтГлавного "+ЭлементДанных);
КонецПроцедуры
Процедура ПриПолученииДанныхОтПодчиненного(ЭлементДанных, ПолучениеЭлемента, ОтправкаНазад)
Сообщить("ПриПолученииДанныхОтПодчиненного "+ЭлементДанных);
КонецПроцедуры
Параметр "ОтправкаЭлемента" позволяет управлять тем, какая информация будет помещена в сообщение. Он может принимать три значения:
| · | ОтправкаЭлементаДанных.Авто - значение по умолчанию - указывает на то, что элемент данных будет помещен в сообщение, |
| · | ОтправкаЭлементаДанных.Удалить - в сообщение будет помещено значение, предназначенное для удаления этого элемента данных, |
| · | ОтправкаЭлементаДанных.Игнорировать - в сообщение не будет помещено ничего, связанного с этим элементом данных. |
| · | ПолучениеЭлементаДанных.Авто - значение по умолчанию. Если элемент данных получен от главного узла - он будет записан всегда. Если элемент данных получен от подчиненного узла, он будет записан только в случае, если не зарегистрированы изменения для этого элемента данных, |
| · | ПолучениеЭлементаДанных.Принять - полученный элемент данных будет записан всегда, |
| · | ПолучениеЭлементаДанных.Игнорировать - проигнорировать получение элемента данных и ничего не записывать. |
В заключение следует сказать о том, что механизм распределенных информационных баз содержит программное средство реконфигурирования структуры узлов распределенной базы.
Для этого следует использовать метод УстановитьГлавныйУзел() объекта ПланыОбменаМенеджер. В параметре этого метода передается ссылка на узел плана обмена распределенной информационной базы, который устанавливается главным для текущей базы. Также в этом параметре может быть передано значение Неопределено, и это приведет к тому, что у текущей информационной базы будет отсутствовать главный узел.
Рассмотрим несколько вариантов реконфигурирования структуры узлов распределенной информационной базы.
Допустим, необходимо переместить один из подчиненных узлов в корень дерева:

Для этого следует выполнить следующие действия:
ПланыОбменаМенеджер.УстановитьГлавныйУзел(Неопределено); [440]
// В информационной базе Узла1
ПланыОбменаМенеджер.УстановитьГлавныйУзел(Узел2);
Таким же образом, используя значение параметра метода Неопределено, мы можем отключать от дерева отдельную информационную базу или целое поддерево:

ПланыОбменаМенеджер.УстановитьГлавныйУзел(Неопределено); [441]

ПланыОбменаМенеджер.УстановитьГлавныйУзел(Узел1); [442]
Проверка работы обмена данными
Прежде всего создадим новый каталог, в котором будет размещаться база нашего филиала и сохраним в этот каталог нашу конфигурацию (Конфигурация


После этого откроем план обмена "Филиалы" и зададим параметры узла по умолчанию - т.е. параметры нашей базы. Код базы будет "ЦБ", а наименование - "Центральная база".
Не забудьте, что именно код идентифицирует узлы обмена в различных базах, поэтому в базе филиала мы будем создавать узлы с такими же кодами.

[422]
Затем создадим новый узел, который будет соответствовать базе филиала, присвоим ему код "Фил" и наименование "Филиал":

Теперь вызовем обработку "ОбменДанными" и нажмем "Выполнить". В окне сообщений появится следующий текст:

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

Первым делом зададим значение константы "ПрефиксНомеров" "ФЛ":

Затем откроем план обмена "Филиал" и опишем предопределенный узел (узел текущей информационной базы) кодом "Фил" и наименованием "Филиал":

После этого создадим новый узел плана обмена с кодом "ЦБ", наименованием "Центральная база" и признаком "Главный":

[424]
Теперь, для большей наглядности откроем список справочника "Клиенты". Сейчас в этом справочнике нет ни одного элемента. Запустим обработку "ОбменДанными" и нажмем "Выполнить".
Справочник будет заполнен элементами, а в окне сообщений появится текст:

Теперь проверим, как будет происходить обмен в другую сторону. Создадим в справочнике "Клиенты" нового клиента с произвольным наименованием. После этого снова нажмем "Выполнить" в открытой форме обработки "ОбменДанными". Затем перейдем в центральную базу, также выполним обмен данными и убедимся, что клиент, созданный в базе филиала перенесен в центральную базу.[425]
Работа с запросами
Для работы с запросами используется объект встроенного языка Запрос. Он позволяет получать информацию, хранящуюся в полях базы данных, в виде выборки, сформированной по заданным правилам.
Реорганизация справочника Номенклатура
Откроем конфигуратор и создадим сначала новый объект конфигурации Перечисление с именем "ВидыНоменклатуры".
На закладке "Данные" добавим два значения перечисления: "Материал" и "Услуга":

Затем добавим в справочник "Номенклатура" новый реквизит "ВидНоменклатуры" с типом ПеречислениеСсылка.ВидыНоменклатуры:

[132]
После этого запустим 1С:Предприятие в режиме отладки и зададим для каждого элемента справочника "Номенклатура" соответствующее значение реквизита "ВидНоменклатуры":

Теперь посмотрим, как можно использовать новые данные, полученные благодаря использованию перечисления "ВидыНоменклатуры". [133]
Создание документа НачисленияСотрудникам
Для того, чтобы иметь возможность регистрировать в базе данных начисления производимые сотрудникам OOO "На все руки мастер", нам понадобится специальный документ.
Откроем конфигуратор и создадим новый документ. Назовем его "НачисленияСотрудникам".
Этот документ будет иметь табличную часть "Начисления", содержащую следующие реквизиты:
| · | "Сотрудник", тип СправочникСсылка.Сотрудники, |
| · | "ГрафикРаботы", тип СправочникСсылка.ВидыГрафиковРаботы, |
| · | "ДатаНачала", тип Дата, |
| · | "ДатаОкончания", тип Дата, |
| · | "ВидРасчета", тип ПланВидовРасчетаСсылка.ОсновныеНачисления, |
| · | "Результат", тип Число, длина 15, точность 2. |
Реквизиты "ДатаНачала" и "ДатаОкончания" понадобятся нам для того, чтобы задавать период, в котором должна действовать запись расчета.
На закладке "Движения" запретим оперативное проведение документа, отметим, что документ будет создавать движения по регистру расчета "Начисления" и запустим конструктор движений.[341]
В окне конструктора выберем табличную часть "Начисления" нажмем "ЗаполнитьВыражения". Для реквизитов "ПериодДействияКонец" и "БазовыйПериодКонец" укажем выражение "КонецДня(ТекСтрокаНачисления.ДатаОкончания)"
Реквизиту "ИсходныеДанные" поставим в соответствие реквизит табличной части "Результат", а для реквизита "Результат" наоборот удалим выражение, присвоенное ему конструктором:

Нажмем "ОК" и посмотрим текст обработчика, созданный конструктором:
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаНачисления Из Начисления Цикл
// регистр Начисления
Движение = Движения.Начисления.Добавить();[342]
Движение.Сторно = Ложь;
Движение.ВидРасчета = ТекСтрокаНачисления.ВидРасчета;
Движение.ПериодДействияНачало = ТекСтрокаНачисления.ДатаНачала;
Движение.ПериодДействияКонец = КонецДня(ТекСтрокаНачисления.ДатаОкончания);
Движение.ПериодРегистрации = ТекСтрокаНачисления.ДатаНачала;
Движение.БазовыйПериодНачало = ТекСтрокаНачисления.ДатаНачала;
Движение.БазовыйПериодКонец = КонецДня(ТекСтрокаНачисления.ДатаОкончания);
Движение.Сотрудник = ТекСтрокаНачисления.Сотрудник;
Движение.ГрафикРаботы = ТекСтрокаНачисления.ГрафикРаботы;
Движение.ИсходныеДанные = ТекСтрокаНачисления.Результат;
КонецЦикла;
// записываем движения регистров
Движения.Начисления.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Начислим оклад за март всем сотрудникам OOO "На все руки мастер", как показано на рисунке:

[343]
Проведем документ и посмотрим, какие движения он сформировал в регистре "Начисления":


Обратите внимание на то, что платформа привела период регистрации каждой записи к началу периода регистра расчета (в обработчике проведения мы указывали значение даты документа - 08.04.2004). Кроме этого заметьте, что с каждой записью мы сохранили в реквизите "ИсходныеДанные" размер оклада сотрудника, введенный в документе, чтобы в дальнейшем рассчитать сумму оплаты по окладу.
Для дальнейшего изучения работы регистра расчета нам понадобится служебный отчет, с помощью которого мы сможем посмотреть содержимое записей перерасчета.[344]
Создание движений документа ПриходнаяНакладная
Начнем с простого: доработаем движения документа "ПриходнаяНакладная". Для этого нам достаточно будет воспользоваться конструктором движений документа и заменить старые движения документа на новые, по трем регистрам.
Откроем конфигуратор. В окне редактирования объекта конфигурации Документ "ПриходнаяНакладная", на закладке "Движения" запустим конструктор движений документа.
В список регистров добавим регистр "РегистрБухгалтерии.Управленческий". В качестве источника данных выберем табличную часть документа "ПриходнаяНакладная" - "Материалы". Счет дебета установим равным "ПланыСчетов.Основной.Товары" (41), а счет кредита - "ПланыСчетов.Основной.РасчетыСПоставщиками" (60).[303]
Нажмем кнопку "Заполнить выражения". У вас должен получиться следующий результат:

Нажмем "ОК" и посмотрим, какой текст платформа добавила в обработчик проведения документа "ПриходнаяНакладная":
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр ОстаткиМатериалов Приход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.НаборСвойств = ТекСтрокаМатериалы.НаборСвойств;
Движение.Склад = Склад;
Движение.Количество = ТекСтрокаМатериалы.Количество;
КонецЦикла;
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр СтоимостьМатериалов Приход
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход; [304]
Движение.Период = Дата;
Движение.Материал = ТекСтрокаМатериалы.Материал;
Движение.Стоимость = ТекСтрокаМатериалы.Сумма;
КонецЦикла;
Для Каждого ТекСтрокаМатериалы Из Материалы Цикл
// регистр Управленческий
Движение = Движения.Управленческий.Добавить();
Движение.СчетДт = ПланыСчетов.Основной.Товары;
Движение.СчетКт = ПланыСчетов.Основной.РасчетыСПоставщиками;
Движение.Период = Дата;
Движение.Сумма = ТекСтрокаМатериалы.Сумма;
Движение.КоличествоДт = ТекСтрокаМатериалы.Количество;
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконто.Материалы] = ТекСтрокаМатериалы.Материал;
КонецЦикла;
// записываем движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Управленческий.Записать();
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Дело в том, что количество субконто как по дебету, так и по кредиту у каждой записи движения регистра будет различное, в зависимости от того, как определены счета в используемом плане счетов. Поэтому для каждой записи движения регистра бухгалтерии платформа хранит две коллекции значений: коллекцию субконто дебета и коллекцию субконто кредита. Каждая из этих коллекций содержит ровно столько элементов, сколько указано использовать видов субконто для соответствующего счета (дебета или кредита) в плане счетов. Обратиться к элементу коллекции можно, указав в квадратных скобках ссылку на соответствующий вид характеристик, либо указав через точку имя предопределенного вида характеристик. [305]
Другими словами, запись:
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконто.Материалы]
равносильна записи:
Движение.СубконтоДт.Материалы
Запустим 1С:Предприятие в режиме отладки, откроем документ ПриходнаяНакладная №1 и перепроведем его.
Посмотрим, какие движения сформировал документ в регистре бухгалтерии Управленческий:

Обратите внимание, что, поскольку, на счете 60 ("РасчетыСПоставщиками") отсутствует аналитика и ведется только суммовой учет, в записях движений регистра "СубконтоКт1", "СубконтоКт2" и "КоличествоКт" не указаны.
После этого перепроведем документ ПриходнаяНакладная №2 и посмотрим, какие движения сформирует он.
Теперь перейдем к более сложной задаче - добавлению движений по регистру "Управленческий" в документ "ОказаниеУслуги".[306]
Создание функции РозничнаяЦена()
Сначала мы создадим функцию, которая будет возвращать нам актуальную розничную цену номенклатуры. Откроем конфигуратор, в ветке Общие

Разместим в нем следующий текст:
//создать вспомогательный объект Отбор
Отбор = Новый Структура("Номенклатура", ЭлементНоменклатуры);
//получить актуальные значения ресурсов регистра
ЗначенияРесурсов = РегистрыСведений.Цены.ПолучитьПоследнее(АктуальнаяДата, Отбор);
Возврат ЗначенияРесурсов.Цена;
КонецФункции // РозничнаяЦена(...)
| · | АктуальнаяДата - параметр типа Дата, который будет определять точку на оси времени, на которую нас интересует значение розничной цены |
| · | ЭлементНоменклатуры - ссылка на элемент справочника "Номенклатура", для которого мы хотим получить розничную цену. |
В теле процедуры мы создаем сначала вспомогательный объект Отбор, с помощью которого определяем, что нас будут интересовать записи регистра, в которых измерение "Номенклатура" равно переданной в процедуру ссылке на элемент справочника.
Во второй строке мы обращаемся к менеджеру регистра сведений "Цены" (РегистрыСведений.Цены) и выполняем метод ПолучитьПоследнее(), который возвращает нам значения ресурсов наиболее поздней записи регистра, которая соответствует передаваемой дате ("АктуальнаяДата") и значениям измерений регистра ("Отбор"). [124]
Значения ресурсов возвращаются в структуре, поэтому в следующей строке мы получаем искомую нами розничную цену просто указав имя нужного нам ресурса регистра через точку (ЗначенияРесурсов.Цена).
Теперь проверим, как работает эта функция. [125]
Создание интерфейсов
Для того, чтобы понять, какие интерфейсы нужно создать в нашей конфигурации, следует определиться с тем, какие группы пользователей собираются работать с нашим прикладным решением.
Скорее всего, это будут руководители, мастера и бухгалтеры. В соответствии с этим мы создадим три различных интерфейса: "Руководитель", "Мастер" и "Бухгалтер". Кроме этого, следует не забыть про то, что у каждой базы данных, как правило, есть администратор - специально выделенный человек, отвечающий за непрерывное функционирование базы, сохранность и достоверность данных. Поскольку администратору нужно предоставить возможность осуществлять обслуживание базы данных - для него мы тоже создадим отдельный интерфейс - "Администратор". [384]
Создадим новый объект конфигурации Интерфейс, и на экране появится конструктор главного меню:

Он содержит два списка: список подменю и список команд выделенного подменю. В этих списках перечислены те пункты подменю и те команды в них, которые предлагается создать по умолчанию. Разработчик может вручную отметить или снять отметку с тех или иных подменю и команд или воспользоваться возможностью построения интерфейса на основе подсистем, существующих в конфигурации.
По умолчанию предлагается сформировать списки подменю и команд по всем подсистемам конфигурации, но, нажав кнопку "По подсистемам", можно указать только некоторые подсистемы. Тогда конструктор построит меню, основываясь на тех объектах конфигурации, которые относятся к указанным подсистемам.
Мы так и поступим. Первый интерфейс, который мы будем создавать, будет интерфейс "Бухгалтер". Поэтому выберем подсистемы "Бухгалтерия" и "РасчетЗарплаты" и нажмем "Установить". В конструкторе меню обновится список команд и используемых подменю. Нажмем "Построить" и зададим имя интерфейса - "Бухгалтер". Укажем, что этот интерфейс будет относиться к подсистемам "Бухгалтерия" и "РасчетЗарплаты". [385]
Вместе с палитрой свойств на экране открылось окно редактор-интерфейса - остановимся на нем подробнее:

Окно редактора интерфейса состоит из трех частей: панель инструментов, список панелей интерфейса и редактора панели. У каждого интерфейса может быть всего одна панель главного меню и несколько панелей инструментов.
Сейчас наш интерфейс "Бухгалтер" содержит только панель главного меню, пункты которого отображены в редакторе панели. При нажатии на любой пункт меню открывается список подменю, содержащий команды этого пункта. [386]
В данном случае нас все устраивает, за исключением пункта "Прочие", в котором для команды "Основной" мы дадим более понятный текст - "План счетов Основной":
Изменим текст пункта подменю

Теперь создадим интерфейс "Мастер". Для него в конструкторе меню выберем подсистему "УчетУслугИМатериалов" и укажем, что сам он тоже будет относиться к подсистеме "УчетУслугИМатериалов".
Два последних интерфейса, будем создавать следующим образом: меню интерфейса "Руководитель" построим по всем трем подсистемам конфигурации:

А при создании меню интерфейса "Администратор" мы не будем выбирать никаких подсистем, а сразу построим меню. Обратите внимание, что в этом случае система включила в меню пункты стандартных действий: "Файл", "Операции", "Сервис", "Окна" и [387] "Справка". Скорее всего, они понадобятся будущему администратору информационной базы.
Разработчик, по своему усмотрению может добавлять, изменять и удалять пункты меню. Эти действия просты и не требуют специальных описаний. И поскольку создание удобного и эргономичного меню - задача творческая - мы лишь показали возможность быстрого создания некоей заготовки, которую разработчик может впоследствии самостоятельно доработать под нужды конкретной группы пользователей. [388]
Создание константы ПрефиксНомеров
Объект конфигурации Константа является прикладным объектом и предназначен для создания в базе данных структур, в которых будет храниться информация, которая не изменяется во времени или изменяется очень редко. Каждый объект конфигурации Константа описывает структуру для хранения одного значения.
Теперь приступим к созданию константы, в которой мы будем хранить значение префикса номеров. Откроем конфигуратор и создадим новый объект конфигурации Константа с именем "ПрефиксНумерации". Определим тип значения константы - Строка, с фиксированной длиной 2 символа.
Создание наборов свойств
Откроем элемент справочника "Номенклатура" - "Кабель электрический". Перейдем на закладку "Свойства" и создадим набор свойств этого элемента под названием "Белый".[273]
Он будет состоять их следующих характеристик:
| · | "Цвет" - "Белый", |
| · | "Сечение, мм2" - 2,5: |

Затем создадим набор свойств для элемента справочника "Номенклатура" - "Шланг резиновый". [274]
Этот набор свойств будет называться "Польша" и состоять из следующих характеристик:
"Цвет" - "Черный",
"Производитель" - "Fagumit":

Теперь откроем документ ПриходнаяНакладная №2 и укажем, что был закуплен белый электрический кабель в количестве 2 шт. и польский резиновый шланг.[275]
Затем скопируем первую строку документа и укажем, что был закуплен еще и черный электрический кабель в количестве 3 шт. (в процессе ввода нам придется создать еще один набор свойств для электрического кабеля - "Черный", у которого "Цвет" - "Черный" и "Сечение" - 2,5):

Проведем документ и посмотрим на движения документа по регистру "ОстаткиМатериалов":

[276]
Кроме этого посмотрим на записи, которые содержатся в регистре сведений "ЗначенияСвойствНоменклатуры":

Создание новых объектов конфигурации
Как мы уже говорили, нам понадобится создать несколько новых объектов конфигурации. Создадим объект конфигурации Справочник с именем "ВариантыНоменклатуры" и укажем, что он будет подчинен справочнику "Номенклатура".
Затем создадим еще один объект конфигурации Справочник с именем "ДополнительныеСвойстваНоменклатуры".
После этого создадим объект конфигурации План видов характеристик с именем "СвойстваНоменклатуры". Тип значения характеристик установим следующим:
| · | Число, длина 15, точность 3, |
| · | Строка, длина 25, |
| · | Дата, |
| · | Булево, |
| · | СправочникСсылка.ДополнительныеСвойстваНоменклатуры: |

[259]
Справочнику "ДополнительныеСвойстваНоменклатуры" укажем владельца - план видов характеристик "СвойстваНоменклатуры" После этого определим, что дополнительные значения характеристик плана видов характеристик будут располагаться в справочнике "ДополнительныеСвойстваНоменклатуры":

В заключение создадим объект конфигурации Регистр сведений с именем "ЗначенияСвойствНоменклатуры".
Измерения регистра:
"НаборСвойств", ведущее, тип СправочникСсылка.ВариантыНоменклатуры,
"ВидСвойства", тип ПланВидовХарактеристикСсылка.СвойстваНоменклатуры.
Ресурс регистра:
"Значение", тип Характеристика.СвойстваНоменклатуры
Обратите внимание, что мы имеем возможность определить тип значения ресурса регистра, как Характеристика.<имя>. По сути, это [260] определение представляет собой составной тип данных, как он задан в типе значения соответствующего плана видов характеристик. To есть ресурс регистра может иметь значение любого типа из тех, которые описаны в типе значения плана видов характеристик.
Создание объекта конфигурации План счетов Основной
Приступим к созданию плана счетов OOO "На все руки мастер". Как мы говорили в начале этой главы, бухгалтерский учет в нашем OOO сильно упрощен и план счетов, по которому работает бухгалтерия, содержит всего три счета: "Товары", "Капитал" и "Дебиторская задолженность".
Откроем конфигуратор и создадим новый объект конфигурации План счетов. Присвоим ему имя - "Основной".
На закладке "Данные" создадим признак учета "Количественный". Перейдем на закладку "Субконто" и укажем, что субконто для этого плана счетов будут находиться в плане видов характеристик "ВидыСубконто". Максимальное количество субконто на счете установим равным двум. Также создадим признак учета субконто "Количественный" и сразу откроем закладку "Прочее".[296]
Нажмем кнопку "Предопределенные" и создадим четыре предопределенных счета:
| · | "Товары", код 41, активный, с количественным учетом в разрезе материалов: |

[297]
| · | "Расчеты с поставщиками", код 60, активно/пассивный: |

| · | "Дебиторская задолженность", код 62, активно/пассивный, с учетом в разрезе клиентов: |

[298]
| · | "Капитал", с кодом 90, активно/пассивный: |

В результате план счетов нашего OOO "На все руки мастер" будет выглядеть следующим образом:

Теперь, мы можем перейти к знакомству с последним объектом конфигурации, который понадобится нам для организации бухгалтерского учета - регистром бухгалтерии.

Для плана счетов можно установить свойство "Автопорядок no коду". Это свойство используется для того, чтобы указать системе, что упорядочивание no полю Порядок должно всегда подставляться в [299] тех случаях, когда пользователь или разработчик выбирает упорядочивание no коду. Его нужно использовать, прежде всего, тогда, когда с точки зрения пользователя нужно упорядочивать план счетов по коду с учетом разделителей кода счета. Например, если счета "10.11" и "10.2" упорядочивать no коду счета, то счета будут располагаться так:
"10.11"
"10.2"
Это правильно с точки зрения сортировки строк, но не соответствует логическому смыслу кодов.
Но если заданы значения поля Порядок "10.11" и "10. 2" и установлено свойство "Автопорядок no коду", то при выборе упорядочивания no коду пользователь будет, фактически, получать порядок, учитывающий разделители:
"10.2"
"10.11".
Если свойство не устанавливать, то нужно будет в явном виде выбирать упорядочивание no полю Порядок.[300]
Создание объекта конфигурации План видов характеристик ВидыСубконто
Приступим к созданию плана видов характеристик, который будет содержать описания объектов аналитического учета - субконто.
Откроем конфигуратор и создадим новый объект конфигурации План видов характеристик. Зададим его имя - "ВидыСубконто".
Поскольку нам понадобится некий вспомогательный справочник, в котором пользователи будут осуществлять "свободное творчество" по созданию значений новых объектов аналитического учета - создадим объект конфигурации Справочник и назовем его "Субконто". [291]
Затем на закладке "Владельцы" укажем, что этот справочник подчинен плану видов характеристик "ВидыСубконто":

Закроем окно редактирования справочника и вернемся к нашему плану видов характеристик.[292]
Зададим тип значения характеристик. Для этого нажмем на кнопку с многоточием и создадим составной тип данных, в который будут входить типы:
| · | СправочникСсылка.Клиенты, |
| · | СправочникСсылка.Номенклатура, |
| · | СправочникСсылка.Субконто: |

Бухгалтерия нашего OOO "На все руки мастер" ведет учет движения денежных средств только в разрезе материалов и клиентов, но не исключено, что в дальнейшем понадобится дополнительная аналитика (поэтому мы используем и справочник "Субконто"). Обратите внимание, что тот справочник, который будет использован в качестве дополнительных значений характеристик, тоже должен входить в составной тип данных типа значений характеристик, иначе конфигуратор выдаст сообщение об ошибке.
Затем укажем, что дополнительные значения характеристик будут находиться в справочнике "Субконто".
После этого перейдем на закладку "Прочее" и начнем ввод предопределенных значений плана видов характеристик.
Создадим предопределенный вид субконто: "Материалы", с кодом "00001" и типом СправочникСсылка.Номенклатура, и затем [293] создадим вид субконто: "Клиенты", с кодом "00002" и типом СправочникСсылка.Клиенты:

На этом создание видов субконто завершено, и мы можем перейти к знакомству со следующим объектом конфигурации, который будет использован нами, - планом счетов. [294]
Создание оборотного регистра накопления Продажи
Когда мы создавали регистры "ОстаткиМатериалов" "СтоимостьМатериалов", мы специально не останавливались на двух видах регистров накопления, которые существуют в системе 1С:Предприятие. Сейчас пришло время сказать об этом пару слов.
Регистры накопления могут быть регистрами остатков и регистрами оборотов.
Существующие в нашей учебной конфигурации регистры "ОстаткиМатериалов" и "СтоимостьМатериалов" являются регистрами остатков. Если вы вспомните момент, когда мы создавали отчет "Материалы", то в конструкторе отчета мы видели, что для таких регистров система создает три виртуальные таблицы: таблица остатков, оборотов и совокупная таблица остатков и оборотов.
Оборотный регистр накопления очень похож на, знакомый уже нам, регистр остатков, для которого понятие "остаток" не имеет смысла. Оборотный регистр накапливает только обороты, остатки ему безразличны. Поэтому единственной виртуальной таблицей, которую будет создавать система для такого регистра, будет таблица оборотов.
В остальном оборотный регистр ни чем не отличается от регистра остатков.
Следует сказать об одной особенности конструирования регистров накопления, напрямую связанной с возможностью получения остатков.
При создании оборотного регистра накопления нет особой сложности в определении того, какие именно параметры должны являться измерениями регистра - мы можем назначить в качестве его измерений любые нужные нам параметры.
Совсем иная ситуация в случае регистра накопления поддерживающего накопление остатков. Для него выбор измерений должен выполняться исходя из того, что движения регистра могут быть осуществлены "в две стороны": приход и расход. Таким образом, в качестве измерений нужно выбирать те параметры, по которым движения точно будут осуществляться как в одну, так и в другую сторону. [154]
Например, если ведется учет материалов в разрезах номенклатуры и склада - очевидно, что и номенклатура и склад могут быть измерениями, поскольку как приход, так и расход материалов всегда будет осуществляться с указанием конкретной номенклатуры и конкретного склада. Если же в этой ситуации появляется желание отразить учет материалов еще и в разрезе поставщика, то здесь уже нужно исходить из конкретной схемы учета, принятой на предприятии.
Скорее всего, при поступлении материалов поставщик будет указан, а вот при расходе материалов, с большой долей вероятности поставщик указываться не будет, так как в большинстве случаев это совершенно лишняя информация. Значит, поставщика следует добавить как реквизит регистра накопления.
Если же при расходе материалов поставщик будет указываться наверняка, тогда имеет смысл добавить поставщика в измерения регистра.
Иными словами, по каждому из измерений регистра накопления остатков изменение ресурсов обязательно должно осуществляться в обе стороны: приход и расход.
Для реквизитов регистра этот принцип неважен, по реквизитам регистра ресурсы могут только приходоваться или только расходоваться.
Нарушение этого принципа построения регистров накопления будет вести к непроизводительному использованию ресурсов системы и, как следствие, замедлению работы и падению производительности.
Теперь, когда мы знаем "практически все" о регистрах накопления, откроем конфигуратор и создадим новый объект конфигурации регистр накопления. Назовем его "Продажи" и определим вид регистра - "Обороты".
На закладке "Данные" создадим измерения регистра:
| · | "Номенклатура", тип СправочникСсылка.Номенклатура, |
| · | "Клиент", тип СправочникСсылка.Кпиенты, |
| · | "Мастер", тип СправочникСсылка.Сотрудники. [155] |
| · | "Количество", тип Число, длина 15, точность 3, |
| · | "Выручка",тип Число, длина 15, точность 2, |
| · | "Стоимость", тип Число, длина 15, точность 2. |
Запустим 1С:Предприятие в режиме отладки и откроем формы списка регистров накопления "Продажи" и "ОстаткиМатериалов". Обратите внимание, что формы практически одинаковы, за исключением состава измерений и ресурсов. [156]
Создание обработки ОбменДанными
Откроем конфигуратор и создадим новый объект конфигурации Обработка с именем "ОбменДанными". Перейдем на закладку "Прочее" и откроем модуль объекта. Создадим в нем процедуру "ОбменСФилиалами":
Процедура ОбменСФилиалами() Экспорт
ВыборкаУзлов = ПланыОбмена.Филиалы.Выбрать();
Пока ВыборкаУзлов.Следующий() Цикл
// Произвести обмен данными со всеми узлами,
// кроме текущего (ЭтотУзел)
Если ВыборкаУзлов.Ссылка <> ПланыОбмена.Филиалы.ЭтотУзел() Тогда
УзелОбъект = ВыборкаУзлов.ПолучитьОбъект();
// Получить сообщение
УзелОбъект.ПрочитатьСообщениеСИзменениями();
// Сформировать сообщение
УзелОбъект.ЗаписатьСообщениеСИзменениями();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Алгоритм работы этой процедуры заключается в следующем: В цикле мы перебираем узлы, которые содержатся в плане обмена "Филиалы", и для всех узлов, кроме себя самого, производим сначала чтение сообщений, поступивших из других узлов обмена (процедуру [406] "ПрочитатьСообщенияСИзменениями" мы создадим позднее), а затем формируем для них сообщения, предназначенные для передачи и содержащие измененные данные для этого узла (процедура "ЗаписатьСообщениеСИзменениями" также будет создана нами позднее).
Теперь создадим основную форму обработки и в обработчик события нажатия кнопки "Выполнить" - "КнопкаВыполнитьНажатие" вставим вызов процедуры ОбменСФилиалами():
Процедура КнопкаВыполнитьНажатие(Кнопка)
ОбменСФилиалами();
КонецПроцедуры
Создание отчета ДиаграммаНачислений
Создадим новый объект конфигурации Отчет и назовем его "ДиаграммаНачислений". Создадим основную форму отчета и разместим на ней элемент управления диаграмма Ганта с именем "ДиаграммаГанта":

Откроем модуль формы отчета и в обработчик события "Нажатие" кнопки сформировать вставим заготовку запроса:
Запрос = Новый Запрос;
Запрос.Текст =
КонецПроцедуры
| · | "НачисленияФактическийПериодДействия.Сотрудник", |
| · | "НачисленияФактическийПериодДействия.ВидРасчета", |
| · | "НачисленияФактическийПериодДействия.ПериодДействияНачало", |
| · | "НачисленияФактическийПериодДействия.ПериодДействияКонец", |
| · | "НачисленияФактическийПериодДействия.Результат", |
| · | "НачисленияФактическийПериодДействия.Регистратор", |
| · | "НачисленияФактическийПериодДействия.Регистратор.Представление": |

Все, запрос готов. Теперь нажмем "ОК" и добавим в процедуру следующий текст:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияФактическийПериодДействия.Сотрудник,
| НачисленияФактическийПериодДействия.ВидРасчета,
| НачисленияФактическийПериодДействия.ПериодДействияНачало,
| НачисленияФактическийПериодДействия.ПериодДействияКонец,
| НачисленияФактическийПериодДействия.Результат,
| НачисленияФактическийПериодДействия.Регистратор,
| НачисленияФактическийПериодДействия.Регистратор.Представление [367]
|ИЗ
| РегистрРасчета.Начисления.ФактическийПериодДействия КАК НачисленияФактическийПериодДействия";
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
Диаграмма = ЭлементыФормы.ДиаграммаГанта;
// Запретить обновление диаграммы
Диаграмма.Обновление = Ложь;
Диаграмма.Очистить();
Диаграмма.ОтображатьЗаголовок = Ложь;
//заполнить диаграмму
Пока ВыборкаРезультата.Следующий() Цикл
//получить серию, точку н значение для них
ТекущаяСерия=Диаграмма.УстановитьСерию(ВыборкаРезультата.ВидРасчета,ВыборкаРезультата.ВидРасчета);
ТекущаяТочка = Диаграмма.УстановитьТочку(ВыборкаРезультата.Сотрудник, ВыборкаРезультата.Сотрудник);
ТекущееЗначение = Диаграмма.ПолучитьЗначение(ТекущаяТочка,ТекущаяСерия);
// создать нужные нам интервалы в значении
ТекущийИнтервал = ТекущееЗначение.Добавить();
ТекущийИнтервал.Начало = ВыборкаРезультата.ПериодДействияНачало;
ТекущийИнтервал.Конец = ВыборкаРезультата.ПериодДействияКонец;
ТекущийИнтервал.Текст = ВыборкаРезультата.РегистраторПредставление;
ТекущийИнтервал.Расшифровка = ВыборкаРезультата.Регистратор;
КонецЦикла;
//раскрасить серии своими цветами
Для Каждого Серия Из Диаграмма.Серии Цикл
Если Серия.Значение = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
Серия.Цвет = WEBЦвета.Желтый;
ИначеЕсли Серия.Значение = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
Серия.Цвет = WEBЦвета.Зеленый;
ИначеЕсли Серия.Значение = ПланыВидовРасчета.ОсновныеНачисления.Невыход Тогда
Серия.Цвет = WEBЦвета.Красный;
КонецЕсли;
КонецЦикла;
//разрешить обновление диаграммы
Диаграмма.Обновление = Истина;
КонецПроцедуры [368]
Затем в цикле по выборке запроса мы заполняем диаграмму. Сначала, используя методы УстановитьСерию() и УстановитьТочку() мы получаем либо существующие, либо новые точку и серию. Точки и серии однозначно идентифицируются своими значениями, в качестве которых мы используем сотрудника и вид расчета из результата запроса.
После того, как точка и серия получены, с помощью метода ПолучитьЗначение() мы получаем соответствующее им значение диаграммы.
Затем мы добавляем в значение диаграммы новый интервал, задаем его начало и конец, задаем текст интервала, который будет показываться во всплывающей подсказке, и задаем расшифровку интервала, которая будет выполняться при двойном щелчке мышью на этом интервале.
После того, как все значения диаграммы сформированы, мы раскрашиваем серии своими цветами. Серии диаграммы представляют собой коллекцию значений, которую мы перебираем при помощи конструкции Для каждого ... Цикл.
Запустим 1С:Предприятие в режиме отладки и посмотрим на результат работы отчета:

[369]
А теперь посмотрим, как выглядит механизм вытеснения По периоду действия "в действии". Откроем документ Начисления сотрудникам №3 и вместо одного прогула с 1 по 10 число зададим Гусакову два прогула: с 3 по 7 число и с 12 по 15 число.
Проведем документ и снова нажмем "Сформировать" в отчете:

Теперь вы наглядно видите, как записи вида расчета "Невыход" вытеснили по периоду действия запись расчета "Оклад", изменив ее фактический период действия.
Следует отметить, что существует также возможность интерактивной настройки параметров диаграммы Ганта, доступная через пункт контекстного меню "Шкала времени и масштаб...".[370]
Создание отчета НачисленияСотрудникам
Теперь мы посмотрим, каким образом можно использовать данные, хранящиеся в регистре расчета, для получения в отчете итоговой информации о начислениях сотрудникам.
Создадим в конфигураторе новый объект конфигурации Отчет. Назовем его "НачисленияСотрудникам".
Запустим конструктор выходной формы. Выберем следующие поля таблицы регистра расчета "Начисления":

На закладке "Объединения/Псевдонимы" определим следующие псевдонимы выбранных полей:

[357]
На закладке "Порядок" отметим автоупорядочивание. На закладке "Итоги" зададим получение общих итогов и промежуточных итогов по сотруднику:

В заключение на закладке "Отчет" сбросим флаг "Использовать построитель отчета". Нажмем "ОК" и запустим 1С:Предприятие в режиме отладки.
В результате работы отчета мы получим следующую таблицу:

[358]
Создание отчета ОборотноСальдоваяВедомость
Теперь нам осталось только создать отчет для бухгалтерии OOO "На все руки мастер" и наше знакомство с использованием регистра бухгалтерии будет закончено.
Единственный отчет, которым пользуется бухгалтерия нашего OOO - это отчет "Оборотно-сальдовая ведомость".
Для того чтобы сформировать этот отчет, откроем конфигуратор и создадим новый объект конфигурации Отчет с именем "ОборотноСальдоваяВедомость". На закладке "Макеты" откроем конструктор выходной формы, и посмотрим, что нам предлагает платформа для выбора.
Бухгалтерский отчет "Оборотно-сальдовая ведомость" представляет собой таблицу, в строках которой перечислены все [312] имеющиеся в плане счетов счета, а в колонках - начальное сальдо, оборот и конечное сальдо по дебету и кредиту каждого счета.
Поэтому нам, для построения такого отчета, понадобятся две исходные таблицы: объектная (ссылочная) таблица плана счетов "Основной" и виртуальная таблица регистра бухгалтерии "Управленческий.ОстаткиИОбороты":

Из таблицы "Основной" мы выберем поля "Код" и "Наименование", а из таблицы "УправленческийОстаткиИОбороты", мы выберем следующие поля:
| · | "СуммаНачальныйРазвернутыйОстатокДт", |
| · | "СуммаНачальныйРазвернутыйОстатокКт", |
| · | "СуммаОборотДт", |
| · | "СуммаОборотКт", |
| · | "СуммаКонечныйРазвернутыйОстатокДт", |
| · | "СуммаКонечныйРазвернутыйОстатокКт": |

[313]
Перейдем на закладку "Связи" и укажем, что из таблицы "Основной" мы будем выбирать все записи, а из таблицы регистра -только те, которые соответствуют условию связи:

Затем на закладке "Объединения/Псевдонимы" зададим псевдонимы полей регистра: "СальдоНачДт", "СальдоНачКт", "ОборотДт", "ОборотКт", "СальдоКонДт" и СальдоКонКт":

После этого на закладке "Порядок" укажем, что результат запроса должен быть отсортирован по возрастанию поля "Код", а на закладке "Итоги" укажем, что должны быть сформированы общие итоги, представляющие собой суммарные значения полей регистра:

[314]
В заключение на закладке "Отчет" сбросим флаг "Использовать построитель отчета".
Наш отчет готов. Нажмем "ОК", запустим 1С:Предприятие в режиме отладки и посмотрим, как работает наш отчет:

[315]
Создание отчета РейтингКлиентов
Создадим в конфигураторе новый объект конфигурации Отчет "РейтингКлиентов". Затем создадим основную форму отчета и расположим на ней поле выбора с именем "ПолеВыбора", подписью "Тип диаграммы:" и подсказкой "Выбор типа диаграммы" (Форма


[198]
Затем разместим под ним диаграмму с именем "Диаграмма". Изменим размеры областей диаграммы, и зададим текст области заголовка - "Рейтинг клиентов":

В модуле формы создадим процедуру "Сформировать" с заготовкой для текста запроса:
// Вставить содержимое обработчика.
Запрос = Новый Запрос;
Запрос.Текст =
;
КонецПроцедуры

Затем добавим новое поле (иконка "Добавить" в командной панели над списком полей) и при помощи построителя выражений определим его как разность между выручкой и стоимостью:

В результате список выбранных полей будет иметь следующий вид:

На закладке "Объединения/Псевдонимы" укажем, что поле "ПродажиОбороты.Клиент.Представление" будет иметь псевдоним "Клиент", а вычисляемое поле - псевдоним "Доход":

[200]
На закладке "Порядок" укажем, что строки результата нужно упорядочивать по убыванию значения поля "Доход". Нажмем "ОК" и посмотрим, какой текст сформировал конструктор запроса:
// Вставить содержимое обработчика.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиОбороты.Клиент.Представление КАК Клиент,
| ПродажиОбороты.ВыручкаОборот - ПродажиОбороты.СтоимостьОборот КАК Доход
|ИЗ
| РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
|
|УПОРЯДОЧИТЬ ПО
| Доход УБЫВ";
КонецПроцедуры
| ПродажиОбороты.ВыручкаОборот - ПродажиОбороты.СтоимостьОборот КАК Доход
...
Добавим в процедуру следующий текст (добавленный текст выделен жирным шрифтом):
// Вставить содержимое обработчика.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиОбороты.Клиент.Представление КАК Клиент,
| ПродажиОбороты.ВыручкаОборот - ПродажиОбороты.СтоимостьОборот КАК Доход
|ИЗ
| РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты [201]
|
|УПОРЯДОЧИТЬ ПО
| Доход УБЫВ";
ВыборкаРезультатаЗапроса = Запрос.Выполнить().Выбрать();
Диаграмма = ЭлементыФормы.Диаграмма;
//запретить обновление и автотранспонирование диаграммы
Диаграмма.Обновление = Ложь;
Диаграмма.АвтоТранспонирование = Ложь;
//создать единственную точку диаграммы
ТочкаДиаграммы = Диаграмма.УстановитьТочку("Доход");
//перебрать выборку результата запроса и создать серии
//и значения
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
ТекущаяСерияДиаграммы = Диаграмма.УстановитьСерию(ВыборкаРезультатаЗапроса.Клиент);
Диаграмма.УстановитьЗначение(ТочкаДиаграммы,ТекущаяСерияДиаграммы,ВыборкаРезультатаЗапроса.Доход);
КонецЦикла;
//разрешить обновление и автотранспонирование диаграммы
Диаграмма.Обновление = Истина;
Диаграмма.АвтоТранспонирование = Истина;
КонецПроцедуры
Перед началом заполнения мы отключаем обновление и автотранспонирование диаграммы для того, чтобы заполнение данными выполнялось быстрее.
После этого добавляем в диаграмму единственную точку.
Затем мы организуем цикл по выборке из результата запроса и в цикле добавляем серии в нашу диаграмму. Каждому клиенту будет соответствовать своя серия. После этого мы устанавливаем значение точки, передавая методу УстановитьЗначение() точку, серию, для которой устанавливается значение в этой точке, и само значение.
После заполнения диаграммы данными мы включаем свойство "Обновление", чтобы новое состояние диаграммы было отображено, и [202] "АвтоТранспонирование" для того, чтобы различные типы диаграмм, которые будут выбраны в поле выбора, отображались правильно.

Следует сделать несколько замечаний no оптимизации заполнения диаграммы данными.
Во-первых, перед началом заполнения диаграммы данными следует отключать обновление диаграммы (свойство диаграммы "Обновление"). Это значительно ускорит процесс заполнения, поскольку при включенном обновлении диаграмма будет выполнять пересчет и отрисовку автоматически. После того, как диаграмма будет заполнена данными, обновление диаграммы нужно снова включить.
Во-вторых, перед началом заполнения диаграммы данными следует также отключать автотранспонирование диаграммы (свойство диаграммы "АвтоТранспонирование"). Автотранспонирование позволяет диаграмме анализировать данные и выбирать наиболее подходящее представление в зависимости от заданного типа диаграммы. Например, круговая диаграмма отображает значения нескольких серий в одной точке, а обычный график - как раз наоборот - значения одной серии в нескольких точках. Обратите внимание, что автотранспонирование диаграммы доступно только в режиме "ручного" заполнения данными. При использовании источника данных это свойство недоступно. После того, как диаграмма будет заполнена данными, автотранспонирование диаграммы можно снова включить, если в этом есть необходимость.
//Заполним список поля выбора
ПолеВыбора = ТипДиаграммы.Гистограмма;
ЭлементыФормы.Диаграмма.ТипДиаграммы = ПолеВыбора;
Сформировать();
КонецПроцедуры [203]
СписокВыбора.Добавить(ТипДиаграммы.График, "График");
СписокВыбора.Добавить(ТипДиаграммы.Гистограмма, "Гистограмма");
СписокВыбора.Добавить(ТипДиаграммы.ГистограммаОбъемная, "Гистограмма 3D");
СписокВыбора.Добавить(ТипДиаграммы.ГистограммаГоризонтальная,"Гистограмма горизонтальная");
СписокВыбора.Добавить(ТипДиаграммы.ГистограммаГоризонтальнаяОбъемная,"Гистограмма горизонтальная 3D");
СписокВыбора.Добавить(ТипДиаграммы.Круговая, "Круговая");
СписокВыбора.Добавить(ТипДиаграммы.КруговаяОбъемная,"Круговая объемная");
СписокВыбора.Добавить(ТипДиаграммы.Изометрическая,"Изометрическая");
СписокВыбора.Добавить(ТипДиаграммы.ИзометрическаяНепрерывная,"Изометрическая непрерывная");
СписокВыбора.Добавить(ТипДиаграммы.ИзометрическаяЛента, "Изометрическая лента");
СписокВыбора.Добавить(ТипДиаграммы.ИзометрическаяПирамида, "Изометрическая пирамида");
ЭлементыФормы.Диаграмма.ТипДиаграммы = ПолеВыбора;
КонецПроцедуры [204]

Теперь изменим тип диаграммы на "Круговая объемная":

Только что мы рассмотрели с вами общий случай заполнения Диаграммы данными. Однако если исходные данные могут быть получены в виде таблицы значений или области ячеек табличного Документа, существует более простой и эффективный способ [205] заполнения диаграммы данными, используя свойство диаграммы - "ИсточникДанных".
Вернемся в модуль формы отчета "РейтингКлиентов" и все строки, которыми мы добавляли в диаграмму данные:
Диаграмма = ЭлементыФормы.Диаграмма;
//запретить обновление и автотранспонирование диаграммы
Диаграмма.Обновление = Ложь;
Диаграмма.АвтоТранспонирование = Ложь;
//создать единственную точку диаграммы
ТочкаДиаграммы = Диаграмма.УстановитьТочку("Доход");
//перебрать выборку результата запроса и создать серии и значения
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
ТекущаяСерияДиаграммы = Диаграмма.УстановитьСерию(ВыборкаРезультатаЗапроса.Клиент);
Диаграмма.УстановитьЗначение(ТочкаДиаграммы,ТекущаяСерияДиаграммы, ВыборкаРезультатаЗапроса.Доход);
КонецЦикла;
//разрешить обновление и автотранспонирование диаграммы
Диаграмма.Обновление = Истина;
Диаграмма.АвтоТранспонирование = Истина;
Запустите 1С:Предприятие в режиме отладки и проверьте работу отчета. Обратите внимание на то, что некоторые типы диаграмм выглядят "некрасиво" (график) или не отображаются совсем (изометрическая непрерывная, изометрическая лента). Это связано с тем, что при использовании источника данных нет возможности использовать свойство диаграммы "АвтоТранспонирование" и нужно [206] обрабатывать транспонирование диаграммы "вручную" (используя свойство СерииВСтроках).
Таким образом, на примере этого отчета мы продемонстрировали как создавать запросы, используя конструктор запросов, и как использовать диаграмму для визуализации результата запроса. [207]
Создание периодического регистра сведений Цены
Приступим к созданию периодического регистра сведений, который будет хранить развернутые во времени розничные цены материалов и стоимости услуг, оказываемых нашим OOO "На все руки мастер".
Откроем конфигуратор и создадим новый объект конфигурации Регистр сведений. Назовем его "Цены". Установим периодичность этого регистра в пределах секунды.
Перейдем на закладку "Данные" и создадим измерение регистра "Номенклатура" с типом СправочникСсылка.Номенклатура. Укажем, что это измерение будет ведущим.
Создадим измерение "Номенклатура" и укажем, что оно будет ведущим...

Свойство "Ведущее" имеет смысл использовать лишь тогда, когда измерение имеет тип ссылки на объект базы данных. Установка свойства "Ведущее" будет говорить о том, что запись регистра сведений представляет интерес, только пока существует этот объект. При удалении объекта, все записи регистра сведений по этому объекту тоже будут автоматически удалены. Кроме того, в форме списка [122] справочника появляется кнопка командной панели "Перейти", по которой возможен переход к записям регистра, отобранным по значению выбранного элемента справочника.
После этого создадим новый ресурс "Цена", тип Число, длина 15, точность 2, неотрицательное.
Теперь запустим 1С:Предприятие в режиме отладки и посмотрим, как работает наш периодический регистр сведений Цены.
Зададим стоимость услуг нашего ООО "На все руки мастер" следующим образом:

После этого зададим розничные цены на материалы:

Итак, мы с вами имеем очень полезную возможность в нашей программе - возможность установки цен на услуги и материалы. Поскольку цены хранятся с привязкой к дате, мы можем заранее установить новые цены и быть уверенными в том, что новые цены вступят в действие не раньше указанной для них даты.
Теперь посмотрим, как можно использовать заданные нами цены в Документе "ОказаниеУслуги". [123]
Создание плана обмена Филиалы
Теперь займемся созданием "центра" любого алгоритма обмена данными, вокруг которого группируются прочие механизмы - плана обмена. Откроем конфигуратор и создадим новый объект конфигурации ПланОбмена с именем "Филиалы". На закладке "Данные" создадим реквизит плана обмена "Главный", имеющий тип Булево.
Этот реквизит понадобится нам для того, чтобы разрешать коллизии при обмене данными. Под коллизией понимается ситуация, когда один и тот же объект обмена данными был изменен одновременно в двух узлах. В этом случае мы будем анализировать значение реквизита "Главный" и принимать изменения только в том случае, если они сделаны в главном узле. В случае коллизии, изменения, произведенные не в главном узле, мы будем отвергать.
Теперь перейдем на закладку "Прочее" и определим состав объектов обмена данными (кнопка "Состав").
Установим отбор по подсистеме "УчетУслугИМатериалов" и включим в обмен все объекты, относящиеся к этой подсистеме. Проверьте, что константа "ПрефиксНумерации" не участвует в обмене, поскольку ее значение должно быть уникальным для каждой базы, участвующей в обмене.[403]
Состав данных обмена должен выглядеть следующим образом:

Теперь создадим с помощью конструктора основную форму узла, для того, чтобы описать в ней некоторые действия, которые должны выполняться при создании нового узла обмена.
Суть этих действий будет заключаться в том, что при создании нового узла обмена мы должны будем сформировать для него все необходимые записи регистрации изменений для всех объектов конфигурации, входящих в данный план обмена. Это будет, своего рода, начальная синхронизация узла обмена всеми данными обмена.
Прежде всего, опишем в модуле формы узла служебную переменную, которая будет хранить признак того, является ли записываемый узел новым, или нет:
РегистрацияВНовыйУзел = ЭтоНовый();
КонецПроцедуры [404]
Если РегистрацияВНовыйУзел Тогда
//Регистрация изменений всех данных для узла
ПланыОбмена.ЗарегистрироватьИзменения(Ссылка);
КонецЕсли;
КонецПроцедуры
В заключение, создадим обработчик события формы "ПередОткрытием" для того, чтобы запретить установку реквизита "Главный" для предопределенного узла, соответствующего данной информационной базе:
Если Ссылка = ПланыОбмена.Филиалы.ЭтотУзел() Тогда
ЭлементыФормы.Главный.Доступность = Ложь;
КонецЕсли;
КонецПроцедуры
На этом создание плана обмена завершено, и мы можем перейти непосредственно к созданию процедур обмена данными. [405]
Создание плана видов расчета ОсновныеНачисления
Приступим теперь к созданию плана видов расчета "ОсновныеНачисления", который будет использоваться в нашей конфигурации.
Откроем конфигуратор и создадим новый объект конфигурации План видов расчета. Зададим его имя - "ОсновныеНачисления".
Сразу перейдем на закладку "Расчет" и укажем, что он будет использовать период действия и зависеть от базы по периоду действия.
В качестве базового плана видов расчета укажем его самого, поскольку все наши виды расчетов будут храниться в единственном плане видов расчета.
Определим использование периода действия, зависимость от базы и базовые планы видов расчета...

Перейдем на закладку "Прочее" и зададим предопределенные виды расчета. Как и в случае с бухгалтерией, расчеты в нашем OOO "На все [325] руки мастер" будут "скромные", поэтому мы создадим всего три элемента:
| · | Невыход - с именем и наименованием "Невыход" и кодом "Невых", |
| · | Оклад - с именем, кодом и наименованием "Оклад" и вытесняющим его видом расчета "Невыход", |
| · | Премия - с именем, кодом и наименованием "Премия", с базовым видом расчета "Оклад" и ведущими видами расчета "Невыход" и "Оклад". |

Теперь мы перейдем к рассмотрению второго объекта, используемого при реализации механизмов сложных периодических расчетов - регистра расчета. [326]
Создание подсистем
Нашу конфигурацию, которую мы создавали на протяжении всей книги, нельзя назвать крупной, однако и в ней присутствует несколько функциональных частей представляющих собой отдельные предметные области. Так можно выделить в отдельную подсистему все, что имеет отношение к бухгалтерскому учету. Кроме этого, отдельной предметной областью является расчет зарплаты сотрудников предприятия и все остальное по-видимому, можно отнести к области учета материалов и услуг.
Поэтому мы создадим в нашей конфигурации три новых объекта конфигурации Подсистема, которые будут иметь имена: "Бухгалтерия", "РасчетЗарплаты" и "УчетУслугИМатериалов".
Теперь все объекты нашей конфигурации следует отнести к той или иной подсистеме. В следующей таблице представлено соответствие объектов конфигурации и созданных нами подсистем.
терия














































Теперь, при перемещении по дереву конфигурации, в окне будет отображаться состав подсистем, в которые входит выделенный объект конфигурации:
Зададим принадлежность объектов конфигурации к подсистемам

[376]
Создание процедур обмена данными
Для инициализации обмена данными мы используем объект конфигурации Обработка. Этот объект раньше не встречался нам, поэтому следует сказать о нем несколько слов. С точки зрения структуры и организации работы обработка ничем не отличается от отчета. Разница состоит лишь в том, что обработка обычно используется для того, чтобы выполнить какие-либо действия над информационной базой, а отчет - чтобы получить некоторое визуальное представление данных.
Создание процедуры чтения данных
Порядок создания процедуры чтения данных обмена будет таким же, как и ранее: сначала мы сформируем имя файла, содержащего данные обмена:[410]
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Теперь добавим в процедуру команды чтения найденного файла с данными обмена:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными."); [411]
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла);
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Для этого мы создаем новый объект ЧтениеXML с помощью которого открываем найденный файл для чтения. В случае успеха мы выводим сообщение о начале загрузки данных из файла. В конце процедуры мы также прекращаем чтение XML-данных из файла методом Закрыть().
Полученные таким образом данные должны являться некоторым сообщением обмена данными. Для того, чтобы представить их в терминах сообщений, мы добавим в процедуру следующий код:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла); [412]
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Теперь, когда мы представили данные обмена в виде сообщения и получили его заголовок, можно произвести одну проверку перед тем, как начать собственно обрабатывать данные:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------"); [413]
Сообщить(" - Считывается файл " + ИмяФайла);
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Сообщение предназначено не для этого узла
Если ЧтениеСообщения.Отправитель <> Ссылка Тогда
ВызватьИсключение "Неверный узел";
КонецЕсли;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Если все в порядке, то перед тем, как начать чтение данных следует удалить все записи регистрации изменений, которые были сделаны для этого узла и соответствовали номерам сообщений меньше или равным тому, который указан в обрабатываемом нами сообщении как номер принятого. Это делается затем, чтобы исключить повторную посылку данных, которые уже были ранее посланы этому узлу и им обработаны:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл [414]
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла);
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Сообщение предназначено не для этого узла
Если ЧтениеСообщения.Отправитель <> Ссылка Тогда
ВызватьИсключение "Неверный узел";
КонецЕсли;
// Удаляем регистрацию изменений
// для узла отправителя сообщения
//*** служба регистрации изменений
ПланыОбмена.УдалитьРегистрациюИзменений(
ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
УдалитьРегистрациюИзменений() для выполнения описанных действий.
Теперь, наконец, мы можем приступить к чтению непосредственно самих данных, содержащихся в сообщении:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" + [415]
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла);
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
//читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Сообщение предназначено не для этого узла
Если ЧтениеСообщения.Отправитель <> Ссылка Тогда
ВызватьИсключение "Неверный узел";
КонецЕсли;
// Удаляем регистрацию изменений
// для узла отправителя сообщения
//*** служба регистрации изменений
ПланыОбмена.УдалитьРегистрациюИзменений(
ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
// Читаем данные из сообщения
//*** XML-сериалшация
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры [416]
И первое, что нам нужно сделать - представить данные XML в виде некоторого значения, имеющего тип 1С:Предприятия. Для этого мы используем метод глобального контекста ПрочитатьXML():
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла);
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Сообщение предназначено не для этого узла
Если ЧтениеСообщения.Отправитель <> Ссылка Тогда
ВызватьИсключение "Неверный узел";
КонецЕсли;
// Удаляем регистрацию изменений [417]
// для узла отправителя сообщения
//*** служба регистрации изменений
ПланыОбмена.УдалитьРегистрациюИзменений(
ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
// Читаем данные из сообщения
//*** XML-сериалшация
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
// Читаем очередное значение
Данные = ПрочитатьXML(ЧтениеXML);
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Теперь, после того, как объект 1С:Предприятия получен, следует разрешить возможную коллизию:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла); [418]
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Сообщение предназначено не для этого узла
Если ЧтениеСообщения.Отправитель <> Ссылка Тогда
ВызватьИсключение "Неверный узел";
КонецЕсли;
// Удаляем регистрацию изменений
// для узла отправителя сообщения
//*** служба регистрации изменений
ПланыОбмена.УдалитьРегистрациюИзменений(
ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
// Читаем данные из сообщения
//*** XML-сериалшация
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
// Читаем очередное значение
Данные = ПрочитатьXML(ЧтениеXML);
// Не переносим изменение полученное в главный из неглавного
// если есть регистрация изменения
Если Не ЧтениеСообщения.Отправитель.Главный И
ПланыОбмена.ИзменениеЗарегистрировано(ЧтениеСообщения.Отправитель, Данные) Тогда
Сообщить("- Изменения отклонены");
Продолжить;
КонецЕсли;
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Теперь единственное, что нам осталось сделать - записать полученные данные:
Каталог = КаталогВременныхФайлов();
// Сформировать имя файла
ИмяФайла = Каталог + ?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(Ссылка.Код) + "_" + СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + ".xml";
Файл = Новый Файл(ИмяФайла);
Если Не Файл.Существует() Тогда
Возврат;
КонецЕсли;
//*** Чтение документов XML
// Попытаться открыть файл
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Исключение
Сообщить("Невозможно открыть файл обмена данными.");
Возврат;
КонецПопытки;
Сообщить("------- Загрузка из " + Строка(ЭтотОбъект) + "-------");
Сообщить(" - Считывается файл " + ИмяФайла);
// Загрузить из найденного файла
//*** Инфраструктура сообщений
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
// читать заголовок сообщения обмена данными - файла XML
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Сообщение предназначено не для этого узла
Если ЧтениеСообщения.Отправитель <> Ссылка Тогда
ВызватьИсключение "Неверный узел";
КонецЕсли;
// Удаляем регистрацию изменений
// для узла отправителя сообщения
//*** служба регистрации изменений [420]
ПланыОбмена.УдалитьРегистрациюИзменений(
ЧтениеСообщения.Отправитель, ЧтениеСообщения.НомерПринятого);
// Читаем данные из сообщения
//*** XML-сериалшация
Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
// Читаем очередное значение
Данные = ПрочитатьXML(ЧтениеXML);
// Не переносим изменение полученное в главный из неглавного
// если есть регистрация изменения
Если Не ЧтениеСообщения.Отправитель.Главный И
ПланыОбмена.ИзменениеЗарегистрировано(ЧтениеСообщения.Отправитель, Данные) Тогда
Сообщить("- Изменения отклонены");
Продолжить;
КонецЕсли;
// Записать полученные данные
Данные.ОбменДанными.Отправитель = ЧтениеСообщения.Отправитель;
Данные.ОбменДанными.Загрузка = Истина;
Данные.Записать();
КонецЦикла;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
УдалитьФайлы(ИмяФайла);
Сообщить("------------ Конец загрузки ------------");
КонецПроцедуры
Кроме этого, в параметрах обмена данными мы устанавливаем свойство "Загрузка", информирующее систему о том, что запись объекта будет происходить в режиме обновления данных, полученных в результате обмена. Такое указание позволяет системе упростить процедуру записи объекта, отказавшись от ряда стандартных проверок и исключив изменения связанных данных, которые выполняются при, обычной записи.
На этом создание процедуры получения и обработки данных обмена закончено. [421]
Создание процедуры расчета записей регистра Начисления
До сих пор мы с вами просто заносили в регистр расчета "Начисления" записи о том, что необходимо выполнить какой-либо вид расчета. Но каким именно образом получать эти результаты мы не говорили. Теперь настало время описать алгоритмы формирования различных видов расчетов.
Поскольку эти алгоритмы нам понадобится использовать не только в документе "Начисление сотрудникам", удобнее всего будет разместить их в отдельном общем модуле.
Откроем в конфигураторе текст обработчика проведения документа "НачислениеСотрудникам" и добавим в него вызов процедуры из общего модуля:
//{{__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!
Для Каждого ТекСтрокаНачисления Из Начисления Цикл
// регистр Начисления
Движение = Движения.Начисления.Добавить();
Движение.Сторно = Ложь;
Движение.ВидРасчета = ТекСтрокаНачисления.ВидРасчета;
Движение.ПериодДействияНачало = ТекСтрокаНачисления.ДатаНачала;
Движение.ПериодДействияКонец = КонецДня(ТекСтрокаНачисления.ДатаОкончания);
Движение.ПериодРегистрации = ТекСтрокаНачисления.ДатаНачала;
Движение.БазовыйПериодНачало = ТекСтрокаНачисления.ДатаНачала;
Движение.БазовыйПериодКонец = КонецДня(ТекСтрокаНачисления.ДатаОкончания);
Движение.Сотрудник = ТекСтрокаНачисления.Сотрудник;
Движение.ГрафикРаботы = ТекСтрокаНачисления.ГрафикРаботы;
Движение.ИсходныеДанные = ТекСтрокаНачисления.Результат;
КонецЦикла;
// записываем движения регистров
Движения.Начисления.Записать();
// получим список всех сотрудников, содержащихся в документе
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| НачисленияСотрудникамНачисления.Сотрудник [349]
|ИЗ
| Документ.НачисленияСотрудникам.Начисления КАК НачисленияСотрудникамНачисления
|ГДЕ
| НачисленияСотрудникамНачисления.Ссылка = &ТекущийДокумент");
Запрос.УстановитьПараметр("ТекущийДокумент", Ссылка);
//сформируем список сотрудников
ТаблЗнач = Запрос.Выполнить().Выгрузить();
МассивСотрудников = ТаблЗнач.ВыгрузитьКолонку("Сотрудник");
СписокСотрудников = Новый СписокЗначений;
СписокСотрудников.ЗагрузитьЗначения(МассивСотрудников);
РасчитатьНачисления(Движения.Начисления, ПланыВидовРасчета.ОсновныеНачисления.Оклад, СписокСотрудников);
Движения.Начисления.Записать(,Истина);
РасчитатьНачисления(Движения.Начисления, ПланыВидовРасчета.ОсновныеНачисления.Премия, СписокСотрудников);
Движения.Начисления.Записать(,Истина);
//}}__КОНСТРУКТОР_ДВИЖЕНИЙ_РЕГИСТРОВ
КонецПроцедуры
Перед вызовом процедуры из общего модуля мы формируем список сотрудников, содержащихся в документе, чтобы передать его в вызываемую процедуру. [350]
Теперь создадим в ветке "Общие" новый общий модуль "ПроведениеРасчетов". Добавим в него заготовку процедуры "РасчитатьНачисления":
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
КонецЕсли;
КонецПроцедуры
При расчете первичных записей нам понадобятся данные графика из регистра расчета, поэтому добавим в первую ветку условия запрос по виртуальной таблице регистра расчета "РегистрРасчета.Начисления.ДанныеГрафика":
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияДанныеГрафика.ЗначениеПериодДействия КАК Норма,
| НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия КАК Факт,
| НачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.ДанныеГрафика(
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);[351]
Запрос.УстановитьПараметр("ВидРасчета", ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников",СписокСотрудников);
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
КонецЕсли;
КонецПроцедуры
Теперь добавим обход переданного в процедуру набора записей и расчет записей, для которых получены значения графика:
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияДанныеГрафика.ЗначениеПериодДействия КАК Норма,
| НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия КАК Факт,
| НачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.ДанныеГрафика(
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ВидРасчета", ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников",СписокСотрудников);[352]
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл
СтруктураНомер = Новый Структура("НомерСтроки");
СтруктураНомер.НомерСтроки = ЗаписьРегистра.НомерСтроки;
ВыборкаРезультата.Сбросить();
Если ВыборкаРезультата.НайтиСледующий(СтруктураНомер) Тогда
Если ВыборкаРезультата.Норма = 0 Тогда
Сообщить("Вид расчета: Оклад - Нет рабочих дней в заданном периоде",);
ЗаписьРегистра.Результат = 0;
Иначе
// рассчитать оклад по фактическому периоду и исходным данным
ЗаписьРегистра.Результат = (ЗаписьРегистра.ИсходныеДанные / ВыборкаРезультата.Норма) * ВыборкаРезультата.Факт;
Сообщить("Выполнен расчет "+ЗаписьРегистра.Регистратор+" - "+ЗаписьРегистра.ВидРасчета+" - "+ЗаписьРегистра.Сотрудник,);
КонецЕсли;
КонецЕсли;
КонецЦикла;
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
КонецЕсли;
КонецПроцедуры
Теперь добавим текст запроса во вторую ветку условия Если... с той лишь разницей, что теперь мы будем получать значения базы, используя виртуальную таблицу регистра расчета "РегистрРасчета.Начисления.БазаНачисления":
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
...
// Рассчитать вторичные записи [353]
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияБазаНачисления.РезультатБаза КАК База,
| НачисленияБазаНачисления.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.БазаНачисления(
| &ИзмеренияОсновного,
| &ИзмеренияБазового,
| ,
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияБазаНачисления";
Измер = Новый Массив(1);
Измер[0] = "Сотрудник";
Запрос.УстановитьПараметр("ИзмеренияОсновного", Измер);
Запрос.УстановитьПараметр("ИзмеренияБазового", Измер);
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ВидРасчета",ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников", СписокСотрудников);
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
КонецЕсли;
КонецПроцедуры
В заключение осталось добавить во второе условие Если... обход набора записей регистра расчета и вычисление результата вторичных записей:
//Рассчитать первичные записи
Если ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Оклад Тогда
... [354]
//Рассчитать вторичные записи
ИначеЕсли ТребуемыйВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Премия Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| НачисленияБазаНачисления.РезультатБаза КАК База,
| НачисленияБазаНачисления.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.БазаНачисления(
| &ИзмеренияОсновного,
| &ИзмеренияБазового,
| ,
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчета
| И Сотрудник В (&СписокСотрудников)) КАК НачисленияБазаНачисления";
Измер = Новый Массив(1);
Измер[0] = "Сотрудник";
Запрос.УстановитьПараметр("ИзмеренияОсновного", Измер);
Запрос.УстановитьПараметр("ИзмеренияБазового", Измер);
Запрос.УстановитьПараметр("Регистратор", НаборЗаписейРегистра.Отбор.Регистратор.Значение);
Запрос.УстановитьПараметр("ВидРасчета",ТребуемыйВидРасчета);
Запрос.УстановитьПараметр("СписокСотрудников", СписокСотрудников);
ВыборкаРезультата = Запрос.Выполнить().Выбрать();
Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра Цикл
СтруктураНомер = Новый Структура("НомерСтроки");
СтруктураНомер.НомерСтроки = ЗаписьРегистра.НомерСтроки;
ВыборкаРезультата.Сбросить();
Если ВыборкаРезультата.НайтиСледующий(СтруктураНомер) Тогда
ЗаписьРегистра.Результат = ВыборкаРезультата.База * (10/100);
Сообщить("Выполнен расчет "+ЗаписьРегистра.Регистратор+" - "+ЗаписьРегистра.ВидРасчета+" - "+ЗаписьРегистра.Сотрудник,);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и проверим правильность работы процедуры расчета.
Отменим проведение документа Начисление сотрудникам №3 и перепроведем документы Начисление сотрудникам №1 и №2. Регистр расчета Начисления должен выглядеть следующим образом:

Гусакову и Деловому начислена премия в размере 10% от суммы начисления по окладу.
Проведем документ Начисление сотрудникам №3, а затем №1 и№2. Состояние регистра изменится следующим образом:

В результате невыхода Гусакова на работу, сумма его оплаты по окладу будет уменьшена и соответствующим образом уменьшится начисленная ему премия. [356]
Создание процедуры записи данных
Сами процедуры записи и чтения данных обмена мы разместим в модуле объекта План обмена "Филиалы". Сначала создадим процедуру, которая используется нами при обмене данными - "ЗаписатьСообщениеСИзменениями". Порядок создания этой процедуры будет следующим: сначала мы сформируем имя файла, который будет содержать данные для обмена:
Сообщить("------------ Выгрузка в узел" + Строка(ЭтотОбъект) + "------------");
Каталог = КаталогВременныхФайлов();
// Сформировать имя временного файла
ИмяФайла = Каталог +?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + "_" + СокрЛП(Ссылка.Код) + ".xml";
Сообщить("------------ Конец выгрузки ------------");
КонецПроцедуры
После этого обратимся к механизмам записи/чтения XML документов и создадим новый объект ЗаписьXML с помощью которого откроем новый XML файл для записи, запишем в него [407] объявление XML, и в конце процедуры завершим запись закроем файл:
Сообщить("------------ Выгрузка в узел" + Строка(ЭтотОбъект) + "------------");
Каталог = КаталогВременныхФайлов();
// Сформировать имя временного файла
ИмяФайла = Каталог +?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + "_" + СокрЛП(Ссылка.Код) + ".xml";
// Создать объект записи XML
//*** запись XML документов
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.Закрыть();
Сообщить("------------ Конец выгрузки ------------");
КонецПроцедуры
Сообщить("------------ Выгрузка в узел" + Строка(ЭтотОбъект) + "------------");
Каталог = КаталогВременныхФайлов();
// Сформировать имя временного файла
ИмяФайла = Каталог +?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + "_" + СокрЛП(Ссылка.Код) + ".xml";
// Создать объект записи XML
//*** запись XML документов
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
ЗаписьXML.ЗаписатьОбъявлениеXML();
//*** инфраструктура сообщений
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьХМL, Ссылка);
Сообщить(" Номер сообщения; " + ЗаписьСообщения.НомерСообщения); [408]
ЗаписьСообщения.ЗакончитьЗапись();
ЗаписьXML.Закрыть();
Сообщить("------------ Конец выгрузки ------------");
КонецПроцедуры
При формировании выборки мы передаем вторым параметром номер сообщения, которым эти данные будут переданы:
Сообщить("------------ Выгрузка в узел" + Строка(ЭтотОбъект) + "------------");
Каталог = КаталогВременныхФайлов();
// Сформировать имя временного файла
ИмяФайла = Каталог +?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + "_" + СокрЛП(Ссылка.Код) + ".xml";
// Создать объект записи XML
//*** запись XML документов
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
ЗаписьXML.ЗаписатьОбъявлениеXML();
//*** инфраструктура сообщений
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Ссылка);
Сообщить(" Номер сообщения; " + ЗаписьСообщения.НомерСообщения);
// Получить выборку измененных данных
//*** механизм регистрации изменений
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(
ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения);
ЗаписьСообщения.ЗакончитьЗапись();
ЗаписьXML.Закрыть();
Сообщить("------------ Конец выгрузки ------------");
КонецПроцедуры [409]
Сообщить("------------ Выгрузка в узел" + Строка(ЭтотОбъект) + "------------");
Каталог = КаталогВременныхФайлов();
// Сформировать имя временного файла
ИмяФайла = Каталог +?(Прав(Каталог, 1) = "\","", "\") + "Message" +
СокрЛП(ПланыОбмена.Филиалы.ЭтотУзел().Код) + "_" + СокрЛП(Ссылка.Код) + ".xml";
// Создать объект записи XML
//*** запись XML документов
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ИмяФайла);
ЗаписьXML.ЗаписатьОбъявлениеXML();
//*** инфраструктура сообщений
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, Ссылка);
Сообщить(" Номер сообщения; " + ЗаписьСообщения.НомерСообщения);
// Получить выборку измененных данных
//*** механизм регистрации изменений
ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(
ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения);
Пока ВыборкаИзменений.Следующий() Цикл
// Записать данные в сообщение
//***XML-сериализация
ЗаписатьXML(ЗаписьXML, ВыборкаИзменений.Получить());
КонецЦикла;
ЗаписьСообщения.ЗакончитьЗапись();
ЗаписьXML.Закрыть();
Сообщить("------------ Конец выгрузки ------------");
КонецПроцедуры
Создание регистра бухгалтерии Управленческий
Откроем конфигуратор и создадим новый объект конфигурации Регистр бухгалтерии. Зададим его имя - "Управленческий". Укажем, что с ним будет связан план счетов "Основной". Установим флаг "Корреспонденция". Этот флаг будет говорить о том, что создаваемый нами регистр поддерживает корреспонденции. Это означает, что каждая запись регистра имеет дебетовую и кредитовую часть, что позволит нам получать информацию не только об остатках и оборотах по счетам , но и о корреспонденциях между счетами.
Регистры, не поддерживающие корреспонденцию, используются тогда, когда не нужно использовать принцип двойной записи, регламентированный в бухгалтерском учете, и, соответственно, контролировать баланс хозяйственных средств и их источников.
Теперь перейдем на закладку "Данные" и создадим два ресурса:
| · | "Сумма", длина 15, точность 2, балансовый, |
| · | "Количество", длина 15, точность 3, небалансовый, признак учета - количественный, признак учета субконто - количественный. |
На этом создание нашего регистра бухгалтерии завершено. Теперь откроем окна редактирования документов "ПриходнаяНакладная" и "ОказаниеУслуги" и отметим, что эти документы будут создавать движения и по регистру бухгалтерии "Управленческий" (закладка "Движения").
Запустим 1С:Предприятие в режиме отладки и откроем регистр бухгалтерии "Управленческий". Как видите, платформа (при создании структуры хранения данных) добавила к созданным нами реквизитам регистра еще ряд полей, которые явились следствием использования плана счетов "Основной". Прежде всего, это поля "СчетДт", "СубконтоДт1", "СчетКт" и "СубконтоКт1". Кроме этого, если прокрутить окно вправо до конца, то вы обнаружите две колонки "Количество". Это "КоличествоДт" и "КоличествоКт". Для измерений и ресурсов регистра, связанных с признаками учета, платформа создает пару полей для хранения значения ресурса отдельно по дебету и отдельно по кредиту проводки.[302]
Создание регистра расчета Начисления
Прежде, чем мы начнем создавать объект конфигурации Регистр расчета "Начисления", нам потребуется создать два дополнительных объекта конфигурации - регистр сведений "ГрафикиРаботы" и справочник "ВидыГрафиковРаботы". Справочник понадобится нам для того, чтобы хранить информацию о том, какие графики работы существуют в OOO "На все руки мастер", а регистр сведений - для указания того, какие дни в месяце являются рабочими, поскольку сумма оплаты по окладу будет рассчитываться исходя из того, сколько дней отработал сотрудник в расчетном месяце. Откроем конфигуратор и создадим новый объект конфигурации Справочник с именем "ВидыГрафиковРаботы".
В этом справочнике у нас будет два предопределенных графика работы - "ГрафикАдминистрации" и "ГрафикМастеров".

После этого создадим объект конфигурации Регистр сведений с именем "ГрафикиРаботы". Этот регистр будет иметь два измерения:
| · | "ГрафикРаботы", тип СправочникСсылка.ВидыГрафиковРаботы, |
| · | "Дата", тип Дата. |
Затем создадим единственный ресурс регистра - "Значение", с типом Число, длиной 1.
Запустим 1С:Предприятие в режиме отладки и заполним регистр данными о рабочих днях марта графика мастеров. Чтобы проще выполнить эту довольно однообразную работу, можете воспользоваться возможностью добавления элементов в справочник [335] копированием (Действия


Теперь все готово для создания регистра расчета.
Создадим новый объект конфигурации Регистр расчета с именем "Начисления". В качестве плана видов расчета, используемого регистром, выберем план видов расчетов "ОсновныеНачисления". Установим, что регистр будет использовать период действия, график будет задаваться в регистре сведений "ГрафикиРаботы", значение графика будет находиться в ресурсе "Значение", а дата графика - в измерении "Дата".[336]
Укажем, что регистр расчета будет использовать базовый период, и периодичность регистра будет "Месяц".

Затем перейдем на закладку "Данные" и создадим:
| · | измерение "Сотрудник", тип СправочникСсылка.Сотрудники, базовое, |
| · | ресурс "Результат", тип Число, длина 15, точность 2, |
| · | реквизит "ГрафикРаботы", тип СправочникСсылка.ВидыГрафиковРаботы, связь с графиком по измерению "ГрафикРаботы", |
| · | реквизит "ИсходныеДанные", тип Число, длина 15, точность 2. |
Теперь перейдем на закладку "Перерасчеты". Создадим объект конфигурации Перерасчет, который так и назовем - "Перерасчет", у него будет единственное измерение - "Сотрудник", для которого в установке связи мы укажем измерение регистра "Сотрудник" и в качестве данных ведущих регистров выберем то же самое измерение "Сотрудник" регистра расчета "Начисления".
На этом создание объекта конфигурации Регистр расчета "Начисления" завершено.[338]
Создание регистра СтоимостьМатериалов
Регистр "СтоимостьМатериалов" совсем не сложен, поэтому мы не будем подробно останавливаться на его создании. Этот регистр будет иметь всего одно измерение - "Материал" с типом СправочникСсылка.Номенклатура и один ресурс - "Стоимость" с длиной 15 и точностью 2.
После создания, регистр "СтоимостьМатериалов" должен выглядеть в дереве конфигурации следующим образом:

Теперь мы можем приступить к внесению изменений в процедуры проведения документов.
Начнем с самого простого - документа "ПриходнаяНакладная". [140]
Создание ролей
При создании ролей исходят, как правило, из того, какие полномочия требуются различным группам пользователей на доступ к информации. Для этого ролей мы воспользуемся подсистемами, которые значительно облегчат нашу задачу. Первая роль, которую мы создадим, будет роль "Администратор". Она должна включать в себя полные права на работу с данными информационной базы. [379]
Создадим новый объект конфигурации Роль с именем "Администратор". Откроется окно редактирования прав:

Слева, в списке объектов, перечислены все объекты и виды объектов конфигурации, а справа, в окне прав, перечислены доступные права для выбранного объекта или видов объектов конфигурации. Пробежав по списку объектов, вы обнаружите, что по умолчанию новая роль имеет полные права на все объекты и виды объектов. В данном случае нас это устраивает, поскольку администратор и должен иметь такие права. Единственное, что следует сделать - снять разрешение на интерактивное удаления для всех объектов. Это необходимо для того, чтобы администратор случайно не мог удалить какой-либо объект базы данных.
Следующей ролью, которую мы создадим, будет роль "ТолькоПросмотр". Создадим новый объект конфигурации Роль с именем "ТолькоПросмотр" и в открывшемся окне редактирования прав выполним команду Действия

Теперь нам останется лишь пройти по видам объектов конфигурации и установить для них права "Чтение", "Просмотр" и "Использование". Вторая роль нашей конфигурации готова.
Следующая роль, которую мы создадим, будет роль "Мастер". Снова создадим новый объект конфигурации Роль с именем "Мастер" и снимем все права в окне редактирования прав. После этого, Выполним команду Действия

Если теперь установить фильтр объектов по подсистем "УчетМатериаловИУслуг", то можно, при необходимости, внести уточнения в установленные права:
Установим фильтр по подсистеме...

В частности, для справочника "Сотрудники" мы запретим добавление, изменение и удаление. Обратите внимание, что при запрете права "Добавление" исчезла отметка и у права "Интерактивное добавление", т.к. оно является "уточнением" права "Добавление". Точно также "уточненные" права запрещаются и при отмене прав на изменение и удаление.
Кроме этого мы снова снимем разрешения на интерактивное удаление для всех объектов базы данных. [382]
В заключение нам с вами осталось создать две роли: "Бухгалтер" и "Расчетчик". Мы разделим права по расчету зарплаты и по ведению бухгалтерского учета. Дело в том, что в OOO "На все руки мастер" есть бухгалтер и помощник бухгалтера. Помощник бухгалтера занят, в основном, расчетом зарплаты, но иногда это делает и главный бухгалтер. Поэтому ему необходимо будет назначить обе роли, в то время как помощнику - только роль "Расчетчик".
Создадим новый объект конфигурации Роль с именем "Расчетчик". В окне редактирования прав снимем все права и затем установим их по подсистеме "РасчетЗарплаты" (и не забудем запретить интерактивное удаление).
В заключение создадим объект конфигурации Роль с именем "Бухгалтер". В окне редактирования прав снимем все права и затем установим их по подсистеме "Бухгалтерия". После этого отфильтруем список объектов по этой подсистеме и для справочника "Номенклатура" запретим добавление, изменение и удаление. Также запретим интерактивное удаление для всех объектов.
Список прав для каждой роли можно получить, выполнив в окне редактирования прав команду Действия

Теперь мы можем перейти к созданию интерфейсов. [383]
Создание универсального отчета
Мы с вами рассмотрим один из вариантов использования построителя отчета, в котором результаты отчета будут выводиться в сводную таблицу.
Создадим в конфигураторе новый объект конфигурации Отчет "Универсальный". Этот отчет будет иметь реквизит "ПостроительОтчета", с типом ПостроительОтчета.
В модуле отчета создадим текст запроса для построителя отчета. Для этого вставим в модуль следующие строки:
;

В качестве таблицы выберем виртуальную таблицу регистра накопления "Продажи.Обороты". Из этой таблицы выберем все поля:

Ha закладке "Итоги" укажем получение общих итогов и выберем все ресурсы регистра:

[211]
Нажмем "OK". B модуле отчета появится текст сформированного запроса:
"ВЫБРАТЬ
| ПродажиОбороты.Номенклатура,
| ПродажиОбороты.Номенклатура.Представление,
| ПродажиОбороты.Клиент,
| ПродажиОбороты.Клиент.Представление,
| ПродажиОбороты.Мастер,
| ПродажиОбороты.Мастер.Представление,
| ПродажиОбороты.КоличествоОборот КАК КоличествоОборот,
| ПродажиОбороты.ВыручкаОборот КАК ВыручкаОборот,
| ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
|ИТОГИ
| СУММА(КоличествоОборот),
| СУММА(ВыручкаОборот),
| СУММА(СтоимостьОборот)
|ПО
| ОБЩИЕ";
"ВЫБРАТЬ
| ПродажиОбороты.Номенклатура,
| ПродажиОбороты.Номенклатура.Представление,
| ПродажиОбороты.Клиент,
| ПродажиОбороты.Клиент.Представление,
| ПродажиОбороты.Мастер,
| ПродажиОбороты.Мастер.Представление,
| ПродажиОбороты.КоличествоОборот КАК КоличествоОборот,
| ПродажиОбороты.ВыручкаОборот КАК ВыручкаОборот,
| ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
|{ИТОГИ ПО Номенклатура, Клиент, Мастер}
|ИТОГИ
| СУММА(КоличествоОборот),
| СУММА(ВыручкаОборот),
| СУММА(СтоимостьОборот)
|ПО
| ОБЩИЕ";[212]


Расположим в форме поле табличного документа

Затем установим курсор в верхнюю левую ячейку поля табличного документа и выполним Таблица


После этого создадим обработчик события формы отчета "При открытии", и добавим в него следующий текст:
СводнаяТаблица = ЭлементыФормы.ПолеТабличногоДокумента.ВстроенныеТаблицы.СводнаяТаблица1;
СводнаяТаблица.ИсточникДанных = ПостроительОтчета;
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и откроем отчет "Универсальный". На экране появится форма отчета, и окно выбора полей сводной таблицы:

Поместим значение ресурса "ВыручкаОборот" в данные, измерение "Номенклатура" в строки, а измерение "Мастер" в колонки. Отчет примет вид:

[214]
Теперь в окне выбора полей сводной таблицы раскроем группу "Номенклатура" и добавим значение "(Без иерархии)" в строки, а измерение "Клиент" добавим в колонки. Отчет изменит свой вид:

Таким образом, используя построитель отчета, мы предоставили пользователю возможность самостоятельно формировать отчет по регистру "ОказанныеУслуги" в том виде, который ему нужен.[215]
Универсальный отчет
На примере создания универсального отчета мы познакомимся с объектом встроенного языка ПостроительОтчета и узнаем как работать со сводной таблицей.
Выполнение перерасчета записей регистра расчета
Итак, в нашем алгоритме работы с данными расчета осталось одно "узкое" место - контроль актуальности данных, содержащихся в регистре расчета. До сих пор мы с вами использовали служебный отчет "Перерасчет" для того, чтобы определить, являются ли данные в регистре расчета актуальными или же они требуют перерасчета.
Теперь мы с вами создадим специальную процедуру, которая будет определять, требуется ли перерасчет данных регистра расчета и, если такая необходимость есть - выполнять перерасчет.
Поскольку единственным способом получения итоговой информации о начислениях сотрудникам в нашей конфигурации является отчет "НачисленияСотрудникам", для вызова этой процедуры мы добавим кнопку "Перерасчитать" в командную панель "ДействияФормы":

В обработчик события нажатия кнопки вставим текст вызова процедуры перерасчета:
ПерерасчитатьНачисления(ПланыВидовРасчета.ОсновныеНачисления.Оклад);
ПерерасчитатьНачисления(ПланыВидовРасчета.ОсновныеНачисления.Премия);
КонецПроцедуры
//здесь следует выбрать из набора записей перерасчета, записи
//в следующей последовательности:
//записи документа1 для сотрудников из списка, [359]
//записи документа2 для сотрудников из списка,
//и т.д.
Запрос = Новый Запрос(
"ВЫБРАТЬ
| НачисленияПерерасчет.ОбъектПерерасчета КАК ОбъектПерерасчета,
| НачисленияПерерасчет.Сотрудник
|ИЗ
| РегистрРасчета.Начисления.Перерасчет КАК НачисленияПерерасчет
|ГДЕ
| НачисленияПерерасчет.ВидРасчета = &ТребуемыйВидРасчета
|ИТОГИ ПО
| ОбъектПерерасчета");
Запрос.УстановитьПараметр("ТребуемыйВидРасчета", ТребуемыйВидРасчета);
СписокСотрудников = Новый СписокЗначений;
//перебрать группировку по регистратору
ВыборкаПоРегистратору = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаПоРегистратору.Следующий() Цикл
Регистратор = ВыборкаПоРегистратору.ОбъектПерерасчета;
//перебрать группировку по сотрудникам
//для выбранного регистратора
//и создать список сотрудников
ВыборкаПоСотрудникам = ВыборкаПоРегистратору.Выбрать();
СписокСотрудников.Очистить();
Пока ВыборкаПоСотрудникам.Следующий() Цикл
СписокСотрудников.Добавить(ВыборкаПоСотрудникам.Сотрудник);
КонецЦикла;
// получить набор записей регистра расчета
//для выбранного регистратора
НаборЗаписей = РегистрыРасчета.Начисления.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Значение = Регистратор;
НаборЗаписей.Прочитать();
РасчитатьНачисления(НаборЗаписей, ТребуемыйВидРасчета, СписокСотрудников);
НаборЗаписей.Записать(,Истина);
//очистить перерасчитанные записи в перерасчете
НаборЗаписейПерерасчета = РегистрыРасчета.Начисления.Перерасчеты.Перерасчет.СоздатьНаборЗаписей();
НаборЗаписейПерерасчета.Отбор.ОбъектПерерасчета.Значение = Регистратор;
НаборЗаписейПерерасчета.Записать();
КонецЦикла;
КонецПроцедуры [360]
Запустим 1С:Предприятие и проверим, как выполняется перерасчет записей регистра расчета.
Отменим проведение всех документов "Начисления сотрудникам" и проведем документ Начисления сотрудникам №1 и затем №2. Сформируем отчет "Начисления сотрудникам" (здесь и далее колонки отчета с 4 по 6 скрыты, в целях экономии места):

Теперь откроем документ Начисления сотрудникам №1, изменим оклад Гусакова на 10 000 и проведем документ. В отчете [361] "НачисленияСотрудникам" нажмем кнопку "Перерасчитать". Будет выполнен перерасчет начисления премии Гусакову и Деловому:

Результат работы отчета будет содержать новые значения премии Гусакова:

И, наконец, проведем документ Начисления сотрудникам №3 и нажмем "Перерасчет" в отчете "НачисленияСотрудникам". Снова будет произведен перерасчет оклада и премии Гусакова:

А данные отчета будут содержать актуальные значения начисления оклада и премии:

[363]
XML-сериализация
Термином XML-сериализация обозначается механизм, позволяющий представить объект 1С:Предприятия в виде последовательности данных в формате XML. Кроме этого XML-сериализация позволяет выполнить и обратное преобразование - представить последовательность данных формата XML в виде объекта 1С:Предприятия, если существует подходящий тип данных.
Дело в том, что объект обмена, являющийся в системе 1С:Предприятие единым целым, на самом деле представляет собой совокупность данных различных типов, определенным образом связанных между собой. Например, элемент справочника может содержать, кроме кода и наименования, некоторое количество реквизитов различного типа и некоторое количество табличных [398] частей, содержащих в свою очередь некоторое количество реквизитов различного типа. В результате XML-сериализации вся эта совокупность данных представляется в виде последовательности соответствующих данных формата XML. B результате обратного преобразования производится "сборка" объекта, при условии, что существует подходящий тип данных 1С:Предприятия.
Зачем нужен периодический регистр сведений?
Начнем мы с того, что обратим ваше внимание на документ "ОказаниеУслуги". Как вы помните, в этом документе мы выбираем услугу, которая оказывается, и затем указываем цену.
Очевидно, что в OOO "На все руки мастер" существует перечень услуг, который определяет стоимость каждой услуги. Казалось бы, что стоимость услуги является неотъемлемым свойством самой услуги и поэтому стоимость услуги следует добавить в качестве реквизита справочника "Номенклатура".
Однако стоимость услуг имеет особенность меняться со временем, и может сложиться такая ситуация, что когда нам потребуется внести изменения или уточнения в один из ранее проведенных документов "ОказаниеУслуги", мы не сможем получить правильную стоимость услуги, поскольку в реквизите справочника будет храниться последнее введенное значение.
Кроме того, не исключена ситуация, что руководство ООО "На все руки мастер" пожелает видеть, как зависит прибыль предприятия от изменения стоимости оказываемых услуг. В этом случае просто необходимо будет иметь возможность анализировать изменение стоимости услуг во времени.
Поэтому для хранения стоимости услуг мы используем новый пока еще для нас объект - регистр сведений. [119]
Зачем нужен план видов расчета и регистр расчета
В этой главе мы рассмотрим возможности системы 1С:Предприятие, которые она предоставляет для автоматизации сложных периодических расчетов.
Такие расчеты используются, прежде всего, при расчете заработной платы. Поэтому дальнейшее рассмотрение этих возможностей мы будем строить на примере расчета заработной платы сотрудников, которые работают в нашем OOO "На все руки мастер".
В общем случае, сумма заработной платы сотрудника складывается из множества частей (например, оплата по окладу, премии, штрафы, оплаты по больничному листу, разовые выплаты и т.д.). Каждая из этих частей рассчитывается по некоторому алгоритму, присущему только этой части. Например, сумма штрафа может определяться просто фиксированной суммой, сумма премии может рассчитываться как процент от оклада, а сумма оплаты по окладу рассчитывается исходя из количества рабочих дней в месяце и количества дней, отработанных сотрудником. Поэтому для обозначения каждой такой части мы будем использовать термин вид расчета.
Алгоритм каждого вида расчета опирается в общем случае на две категории параметров: период, за который нужно получить конечные данные и набор некоторых исходных данных, используемых при расчете.
Как правило, в реальной жизни различные виды расчета существуют не сами по себе, а оказывают некоторое влияние на другие виды расчета. Исходя из того, что вид расчета опирается на две различные категории параметров, такое влияние тоже имеет двойственный характер.
Во-первых, это может быть влияние на исходные данные, используемые при расчете. В качестве примера можно привести начисление премии в виде процента от оплаты по окладу. При изменении оплаты по окладу размер премии тоже должен быть пересчитан, исходя из новой суммы начисленного оклада. Другими словами, сумма начисленного оклада является базой для расчета премии. Причем, поскольку оклад рассчитывается за некоторый период, то при расчете премии нам интересно знать не значение [318] оклада вообще, а сумму, которая начислена в том периоде, который влияет на расчет премии. Такой период мы будем называть базовым, а подобную зависимость между видами расчета мы будем называть зависимостью по базовому периоду.
В качестве примера рассмотрим начисление премии за апрель. Премия должна начисляться в размере 10% от суммы, начисленной в качестве оплаты по окладу. Следовательно, необходимо проанализировать все записи о начислениях оплаты по окладу, которые попадают в интересующий нас базовый период, а именно апрель. Допустим, общая сумма таких начислений составила 8000 рублей - в этом случае премия должна быть начислена в размере 800 рублей:
Зависимость премии от оклада по базовому периоду

Во-вторых, это влияние может быть не на исходные данные, а на сам период, за который производится расчет. В качестве примера можно привести расчет оплаты по окладу и невыход на работу. Предположим, что мы начислили сотруднику оплату по окладу за март месяц. В этом случае период действия такого расчета будет с 01.03.2004 по 31.03.2004. После этого мы получили информацию от руководителя отдела, что, оказывается, сотрудник отсутствовал на работе с 1 по 10 марта по неизвестной причине. В этом случае нам нужно будет произвести расчет "Невыход" (в котором можно рассчитать какие-то удержания с сотрудника). Но кроме этого, нам [319] нужно будет пересчитать и оклад сотрудника, исходя из того, что фактический период действия расчета "Оклад" стал теперь с 11.03.2004 по 31.03.2004. Такое влияние мы будем называть вытеснением по периоду действия. В результате, если за полный месяц работы сотруднику должно было быть начислено 9300 рублей то теперь, за фактический период работы начисление составит 6300 рублей:

Таким образом, исходя из двух видов взаимного влияния расчетов, можно сказать, что в общем случае с каждым видом расчета будет связано три периода: период действия, фактический период и базовый период.
Период действия является "запрашиваемым" периодом, т.е. указывая период действия, мы говорим что "мы хотели бы, чтобы результат действовал в этом периоде".
Фактический период - это то, что получилось из периода действия после анализа всех периодов действия расчетов, которые вытесняют наш по периоду действия. [320]
Базовый период - это период, в котором мы анализируем результаты других расчетов, которые влияют на наш по базовому периоду.
Как видите, взаимное влияние между видами расчетов может быть довольно разнообразным и, что самое сложное, это влияние может быть многоуровневым. To есть один вид расчета может влиять на другой, который, в свою очередь, влияет на третий и т.д.
Очевидно, что в этой ситуации требуется некий универсальный механизм, позволяющий описать каждый из видов расчетов (его алгоритм, влияние на другие виды расчетов, зависимость от других видов расчетов), обеспечить хранение данных, полученных в результате этих расчетов и контроль необходимости перерасчета результатов зависимых расчетов в случае изменения результатов "первичных" расчетов.
В системе 1С:Предприятие такой универсальный механизм реализован при помощи планов видов расчета и регистров расчета. И первым объектом конфигурации, с которым мы начнем знакомиться в этой главе, будет План видов расчета. [321]
Зачем нужно проведение документа по нескольким регистрам?
До сих пор мы с вами учитывали только количественное движение материалов в OOO "На все руки мастер". Для этих целей мы создали регистр накопления "ОстаткиМатериалов". Однако, как вы, наверное, догадываетесь, одного только количественного учета совершенно недостаточно для нужд нашего ООО.
Очевидно, что необходимо также знать, какие денежные средства были затрачены на приобретение тех или иных материалов, и каковы материальные запасы OOO "На все руки мастер" в денежном выражении.
После того, как мы начали автоматизировать наше предприятие, руководство ООО "На все руки мастер" высказало пожелание, чтобы весь суммовой учет материалов велся бы теперь по средней стоимости. To есть, при закупке материалов они должны учитываться в ценах приобретения, а при расходе - по средней стоимости, которая рассчитывается исходя из общей суммы закупок данного материала и общего количества этого материала, находящегося в OOO.
Поскольку подобная информация имеет совершенно другую структуру, нежели количественный учет, для хранения данных об общей стоимости тех или иных материалов мы будем использовать еще один регистр накопления "СтоимостьМатериалов".
Таким образом, документы "ПриходнаяНакладная" и "ОказаниеУслуги" должны будут создавать движения не только в регистре "ОстаткиМатериалов", но, одновременно, и в регистре "СтоимостьМатериалов", отражая изменения суммового учета. [139]
Зачем нужно создавать еще один регистр
Продолжим рассматривать работу нашего документа "Оказание Услуги". До сих пор мы создавали в регистрах накопления движения только для строк документа, которые содержат материалы. Услуги, содержащиеся в документе, мы никак не учитывали.
Дело в том, что при учете услуг важны совершенно другие критерии, нежели при учете материалов. Прежде всего, бессмысленно говорить о том, сколько услуг было и сколько их осталось, важна только сумма и количество услуг, которые были оказаны за определенный промежуток времени. Кроме этого интересны следующие моменты:
| · | какие именно услуги были оказаны (чтобы составить рейтинг услуг) |
| · | какому именно клиенту оказывались услуги (чтобы предоставить ему скидку от объема оплаченных ранее услуг, например) |
| · | какой мастер предоставлял услуги (чтобы начислить ему заработную плату) |
Очевидно, что существующие регистры накопления совершенно не подходят для решения таких задач. Поэтому мы создадим еще одно "хранилище" данных, которое будет использоваться в нашей программе - оборотный регистр накопления "Продажи". [153]
Зачем нужны подсистемы?
В конфигураторе 1С:Предприятия существует возможность определить логическую структуру создаваемого прикладного решения, описав ее в виде различных, по своей функциональности, частей, которые в совокупности составляют данное прикладное решение.
Для описания такой структуры существуют объекты конфигурации Подсистема. Эти объекты располагаются в ветке объектов "Общие" и позволяют строить древовидную структуру, состоящую из подсистем и подчиненных подсистем.
Большинство объектов конфигурации имеют соответствующее свойство "Подсистемы", с помощью которого объект конфигурации можно отнести к тем или иным подсистемам. Такая привязка объектов конфигурации к логической структуре прикладного решения имеет две полезных возможности использования.
Во-первых, при разработке достаточно крупных прикладных решений, зачастую возникает необходимость оперировать не всеми объектами конфигурации, а только теми, которые относятся к разрабатываемой в данный момент логической части конфигурации. В этом случае разработчик имеет возможность отфильтровать содержимое дерева конфигурации по тем подсистемам, которые интересуют его в данный момент.
Во-вторых, принадлежность объектов конфигурации к определенной подсистеме позволяет легко создавать пользовательские интерфейсы и роли, поскольку пользователи, как правило, осуществляют какой-либо определенный набор действий, который определяется некоторым набором прав.
Подсистемы позволяют описывать прикладное решение в виде иерархического дерева функциональных блоков, поскольку каждая подсистема может состоять, в свою очередь, из нескольких других подсистем. [373]
Запись/чтение документов XML
В отличие от XML-сериализации, механизмы записи/чтения документов XML позволяют работать с данными формата XML на "базовом" уровне, без привязки к объектам 1С:Предприятия. В частности они позволяют открывать файлы XML для чтения, читать данные из файлов, создавать новые файлы XML и записывать в них данные. [399]
1С-Предприятие 8.0. Специальные приемы разработки
Алгоритм организации подборов
Для иллюстрации механизма подбора информации в форме мы будем использовать задачу подбора элементов справочника в табличную часть документа, как наиболее распространенную. Поскольку механизм подбора реализован на уровне форм, то в других случаях просто будут задействованы иные прикладные объекты, сам механизм подбора не изменится.
Для организации подбора в форму документа следует открыть форму справочника как подчиненную форме документа, либо элементу управления, расположенному в форме документа. Способ получения формы справочника может быть любым, также как и сама форма справочника, которая будет использована. Важно лишь то, что эта форма должна быть открыта как подчиненная.
Результат подбора будет доступен в обработчике события "Обработка выбора" формы документа или элемента управления (в зависимости от подчинения формы справочника).
Событие "Обработка выбора" будет вызвано в двух случаях:
| · | когда в форме справочника будет выполнен интерактивный выбор, |
| · | когда в форме справочника будет вызван метод ОповеститьОВыборе(). |
Различные способы подбора мы проиллюстрируем на примере подбора элементов справочника "Номенклатура" в документ "ПриходнаяНакладная".
Часть III. Специальные приемы разработки
Третья часть нашей книги будет посвящена некоторым конкретным приемам использования тех или иных объектов конфигурации которые могут потребоваться разработчику в процессе создания и модификации конфигурации. [486]
Данные и элементы управления
Важной особенностью платформы 1С:Предприятие 8.0 является механизм представления данных в формах. Ключевым моментом здесь является то, что принадлежность формы к тому или иному объекту конфигурации никоим образом не определяет состав данных, которые форма будет отображать. Например, можно создать общую форму, которая не будет подчинена ни одному из объектов конфигурации, но которая, в зависимости от содержимого, будет либо отображать список справочника, либо позволять редактировать документ. Однако такую форму уже нельзя будет назначить основной для выполнения определенных действий.
Форма сама по себе и ее элементы управления обособлены от объектов конфигурации. Для того чтобы форма отображала какие-либо данные, необходимо задать связь самой формы и большинства из ее элементов управления с данными. При использовании конструктора форм, конфигуратор создает такие связи автоматически. Если разработчик создает форму вручную - он может определить эти связи путем задания свойств формы и элементов управления. В любом случае, эти связи могут быть изменены средствами встроенного языка в процессе выполнения программы.
Связь формы и элементов управления с данными осуществляется при помощи реквизитов формы. Список существующих реквизитов формы доступен на закладке "Реквизиты" окна редактирования формы.
Среди всех реквизитов формы, как правило, существует один основной реквизит (он выделен жирным шрифтом). Основной реквизит определяет источник данных для формы в целом. От типа значения основного реквизита формы зависит не только то, какие данные будут отображены в элементах управления формы, но и поведение самой формы. Например, если основному реквизиту формы указать тип значения ДокументОбъект.ПриходнаяНакладная, то при закрытии формы программа будет запрашивать подтверждение записи и проведения документа. Если же основному реквизиту формы указать тип значения СправочникСписок.Номенклатура, то подобного подтверждения при закрытии формы возникать не будет. [502]
Похожее влияние источники данных оказывают и на элементы управления. Например, состав колонок табличного поля будет различным, если в качестве источника данных этого поля указать реквизит формы с типом значения СправочникСписок.Номенклатура или РегистрНакопленияСписок.ОстаткиКомплектующих. To же самое справедливо и для элемента управления командная панель. При установленном свойстве командной панели "Автозаполнение", смена источника данных (а точнее говоря, источника действий) будет приводить к изменению состава команд, которые отображает командная панель.
Возможность связать форму и элементы управления с различными данными является причиной того, что у формы и у элементов управления существует несколько расширений. Расширение представляет собой набор дополнительных свойств, методов и событий, появляющихся у объекта. Наличие того или иного расширения определяется либо типом данных, которые отображает объект, либо расположением его в других объектах.
Рассмотрим этот механизм на примере элемента управления Поле ввода, расположенного в колонке "Вид номенклатуры" формы списка справочника "Номенклатура":

Поскольку форма отображает данные объекта СправочникСписок.Номенклатура, к свойствам, методам и [503] событиям объекта Форма добавляется расширение формы списка справочника:

В результате этого у формы появляются такие свойства как ПараметрТекущаяСтрока, ПараметрВыборПоВладельцу и т.п. [504]
Затем, поскольку данными, отображаемыми в табличном поле, будет список справочника "Номенклатура", к свойствам, методам и событиям табличного поля добавляется расширение табличного поля списка справочника. Но, поскольку это табличное поле расположено в форме, к его свойствам, методам и событиям добавляется также и расширение элементов управления, расположенных в форме:

[505]
И в заключение, поскольку поле ввода будет отображать значение реквизита справочника типа Перечисление.ВидыНоменклатуры, к свойствам и событиям поля ввода добавляется расширение поля ввода перечисления. А раз это поле ввода расположено в табличном поле, то к его свойствам и событиям добавляется также расширение элементов управления, расположенных в табличном поле:

Теперь, когда мы представляем, что такое расширение, рассмотрим более подробно расширение элементов управления, расположенных в форме.
В числе прочего, это расширение добавляет элементам управления одно важное свойство - Данные. Это свойство имеет тип Строка и [506] должно содержать путь к данным. Путем к данным может являться либо имя реквизита формы, либо путь к одному из свойств реквизита
Например, если в форме существует элемент управления табличное поле, можно в качестве данных указать ему имя реквизита "СправочникСписок", который имеет тип значения СправочникСписок.Номенклатура. [507]
Если на этой же форме разместить поле ввода, то его свойство Данные может иметь значение СправочникСписок.Отбор.Ссылка.Значение.

[508]
Таким образом свойство Данные позволяет связать элемент управления с теми данными, которые он должен отображать.
Следует заметить, что при определении свойства Данные в конфигураторе, предоставляется возможность выбрать только из тех реквизитов, которые имеют подходящий тип для отображения в конкретном элементе управления.
Следующим важным свойством, которым обладают элементы управления расположенные в форме, является свойство "ТипЗначения". Это свойство содержит тип реквизита, данные которого отображает элемент управления. При выборе в конфигураторе значения свойства Данные, свойство Тип значения заполняется автоматически, на основании типа выбранных данных.
При установленной связи с данными свойство Тип значения становится недоступным для изменения. Однако, если связь с данными не задана, можно изменять свойство Тип значения. Такой способ используется иногда для связи элемента управления не с самими данными, а с некоторым типом данных. Причем, если указать тип, допускающий однозначный выбор данных (например, СправочникСписок.Номенклатура), то эти данные даже будут отображены в элементе управления.
В качестве примера можно создать форму, не имеющую ни одного реквизита, разместить в ней табличное поле и указать, что его тип значения будет равен СправочникСписок.Номенклатура. При открытии этой формы в режиме 1С:Предприятия мы увидим, что табличное поле содержит данные элементов справочника "Номенклатура".
Говоря о связи элементов управления и данных, следует отдельно упомянуть поле ввода, поскольку это элемент управления имеет одну особенность - свойство ОграничениеТипа.
Использование этого свойства позволяет ограничить пользователя в выборе возможных типов данных значений, вводимых в поле ввода. Например, если реквизит формы имеет составной тип данных:
| · | Число, |
| · | Строка, |
| · | Дата, |
| · | СправочникСсылка.Клиенты, |
| · | СправочникСсылка.Сотрудники, [509] |
| · | СправочникСсылка.Номенклатура, |
| · | Число, |
| · | Дата, |
| · | Строка: |

[510]
Интересной особенностью здесь является то, что типы данных, заданные в свойстве ОграничениеТипа поля ввода, могут не совпасть с типом данных реквизита, отображаемого в поле ввода.
Например, как в приведенном выше примере, когда в реквизите уже хранится значение типа СправочникСсылка.Клиенты. В этом случае ограничение типа будет игнорироваться, т.е. тип отображаемых данных будет обладать "большим весом", чем поле ввода, эти данные отображающее. Такое решение вполне логично, поскольку именно реквизит содержит данные, а поле ввода - всего лишь инструмент для их отображения. [511]
Общие приемы
Существует ряд приемов использования объектов конфигурации, которые нельзя отнести только к какому-то одному виду объектов. Такие приемы мы собрали в этой главе. [487]
Формы
В этой главе мы собрали приемы работы, которые имеют отношение к формам объектов. Кроме этого в начале главы дается краткое пояснение того, каким образом в системе 1С:Предприятие данные отображаются в формах. [501]
Использование метода ОповеститьОВыборе()
Метод формы ОповеститьОВыборе() используется в тех случаях, когда алгоритм формирования данных подбора сложен, и кроме собственно выбора элемента справочника от пользователя требуется указание некоторой дополнительной информации. В этом случае метод ОповеститьОВыборе() вызывается тогда, когда вся необходимая информация подбора сформирована.
Также метод ОповеститьОВыборе() может использоваться в тех случаях, когда требуется передать в форму документа не только [491] выбранный элемент справочника (или массив элементов), а некоторую произвольную структуру данных. [492]
Изменение данных табличного поля путем установки типа значения
Как мы уже говорили выше, путем установки типа значения элемента управления также можно изменять отображаемые данные, если данные используемого типа значения могут быть однозначно отображены в элементе управления. В следующем примере мы посмотрим, как можно изменять содержимое табличного поля, не используя реквизиты формы.
Нашей задачей будет создание в форме списка аналогичного механизма отображения движений документов "ОказаниеУслуги" в регистрах накопления.
Откроем конфигуратор и создадим основную форму списка документа "ОказаниеУслуги" с помощью конструктора. Расположим на ней переключатель из трех кнопок:

Зададим следующие выбираемые значения переключателей:
| · | "ОстаткиМатериалов" - "Остатки", |
| · | "СтоимостьМатериалов" - "Стоимость", |
| · | "Продажи" - "Продажи". [520] |
Под переключателем расположим табличное поле с именем "ТабличноеПоле", типом ТаблицаЗначений и пустым свойством Данные:

Создадим процедуру обработки события "При открытии" формы и установим в ней начальное значение переключателя и начальное содержимое табличного поля:
ОстаткиМатериалов = "Остатки";
Массив = Новый Массив;
Массив.Добавить(Тип("РегистрНакопленияСписок.ОстаткиМатериалов"));
НашеОписание = Новый ОписаниеТипов(Массив);
ТабПоле = ЭлементыФормы.ТабличноеПоле;
ТабПоле.ТипЗначения = НашеОписание;
ТабПоле.СоздатьКолонки();
ТабПоле.Значение.Отбор.Регистратор.Установить(, Истина);
КонецПроцедуры
Затем создадим процедуру обработки события "ПриИзменении" переключателя, в которой, в зависимости от установленного значения переключателя, будем изменять свойство ТипЗначения табличного поля:
Если ОстаткиМатериалов = "Остатки" Тогда
НужныйТип = Тип("РегистрНакопленияСписок.ОстаткиМатериалов");
ИначеЕсли ОстаткиМатериалов = "Стоимость" Тогда
НужныйТип = Тип("РегистрНакопленияСписок.СтоимостьМатериалов");
ИначеЕсли ОстаткиМатериалов = "Продажи" Тогда
НужныйТип = Тип("РегистрНакопленияСписок.Продажи");
КонецЕсли;
Массив = Новый Массив();
Массив.Добавить(НужныйТип);
НашеОписание = Новый ОписаниеТипов(Массив);
ТабПоле = ЭлементыФормы.ТабличноеПоле;
ТабПоле.ТипЗначения = НашеОписание;
ТабПоле.СоздатьКолонки();
НашОтбор = ТабПоле.Значение.Отбор;
ЗначениеОтбора = ЭлементыФормы.ДокументСписок.ТекущаяСтрока;
НашОтбор.Регистратор.Установить(ЗначениеОтбора, Истина);
КонецПроцедуры
Теперь осталось только создать обработчик события "ПриАктивизацииСтроки" табличного поля "ДокументСписок":
НашОтбор = ЭлементыФормы.ТабличноеПоле.Значение.Отбор;
Если Элемент.ТекущиеДанные = Неопределено Тогда
НашОтбор.Регистратор.Установить(, Истина);
Иначе
НашОтбор.Регистратор.Установить(Элемент.ТекущаяСтрока, Истина);
КонецЕсли;
КонецПроцедуры
Запустите 1С:Предприятие и проверьте работу списка документа "ОказаниеУслуги". [523]
Изменение источника данных табличного поля
В процессе разработки форм периодически возникает необходимость в изменении данных табличного поля расположенного в форме, в зависимости от желания пользователя или алгоритмов работы программы. Только что мы с вами показали в форме списка документа "ПриходнаяНакладная" движения по регистру остатков "ОстаткиМатериалов". Нашим пользователям очень понравилась такая возможность, и они захотели также иметь возможность видеть на этой форме и движения по регистру остатков "СтоимостьМатериалов".
Добавление в форму еще одного такого же табличного поля нежелательно, поскольку это будет отвлекать внимание от списка документов, и занимать много места на экране. Поэтому мы воспользуемся возможностью изменения источника данных у элемента управления.
Откроем в конфигураторе форму списка документа "ПриходнаяНакладная", сдвинем табличное поле вниз и на освободившемся пространстве расположим элемент управления переключатель, состоящий из двух кнопок:

[516]
После того, как мы укажем заголовок первой кнопки - "Остатки материалов" - система автоматически сформирует имя этой кнопки "ОстаткиМатериалов". Отметим, что эта кнопка будет первой в группе, и напишем подсказку - "Отобразить движения по регистру "Остатки материалов".
Затем создадим вторую кнопку с заголовком "Стоимость материалов". Напишем подсказку - "Отобразить движения по регистру "Стоимость материалов".
Нажмем "ОК" и расположим кнопки в форме:

Откроем палитру свойств кнопки "ОстаткиМатериалов" и укажем, что тип выбираемого значения будет Строка, а выбираемое значение будет равно "Остатки".

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

Сейчас нас устраивает автоматический порядок обхода элементов и поэтому мы создадим обработчик события "ПриОткрытии" формы, и зададим в нем начальное значение нашего переключателя:
ОстаткиМатериалов = "Остатки";
КонецПроцедуры

Укажем его тип РегистрНакопленияСписок.СтоимостьМатериалов.
В заключение создадим процедуру обработки события "При изменении" для кнопки "Остатки материалов":
Если ОстаткиМатериалов = "Остатки" Тогда
ЭлементыФормы.ТабличноеПоле.Данные = "ТабличноеПоле";
Иначе
ЭлементыФормы.ТабличноеПоле.Данные = "РегистрСписок";
КонецЕсли;
ЭлементыФормы.ТабличноеПоле.СоздатьКолонки();
ДокументСписокПриАктивизацииСтроки(ЭлементыФормы.ДокументСписок);
КонецПроцедуры [518]
Откройте 1С:Предприятие в режиме отладчика и проверьте работу списка документа "ПриходнаяНакладная". [519]
Множественный подбор
При множественном подборе форма справочника будет открыта до тех пор, пока пользователь не закроет ее интерактивно или пока не будет вызван метод формы Закрыть().
Для разнообразия создадим форму списка справочника "Номенклатура" и затем в форме документа "ПриходнаяНакладная", в обработчик события нажатия кнопки "Подбор" внесем следующие изменения:
Процедура КоманднаяПанельМатериалыПодбор(Кнопка)
ФормаПодбора = Справочники.Номенклатура.ПолучитьФормуСписка( ,ЭлементыФормы.Материалы);
ФормаПодбора.РежимВыбора = Истина;
ФормаПодбора.ЗакрыватьПриВыборе = Ложь;
ФормаПодбора.Открыть();
КонецПроцедуры
Свойство "ЗакрыватьПриВыборе" как раз и будет задавать режим множественного выбора. Установка же свойства "РежимВыбора" понадобилась нам, так как в этом примере для получения подчиненной формы мы используем метод ПолучитьФормуСписка(). Полученная этим методом форма будет иметь свойство "РежимВыбора" установленным в Ложь (в отличие от получения формы методом ПолучитьФормуВыбора(), когда "РежимВыбора" устанавливается в Истина).
Запустите 1С:Предприятие в режиме отладки и проверьте работу множественного подбора.
Объект конфигурации Критерий отбора
Объект конфигурации Критерий отбора предназначен для задания правил, по которым может выполняться отбор объектов.
Этот объект используется в случае поиска различной информации, когда, например, требуется отобрать все документы, в которых используется (в реквизитах и в табличных частях) определенный контрагент, при этом можно учитывать также и другие условия отбора информации (например, поиск ведется только среди проведенных документов или в определенном интервале дат).
Объекты, введенные на основании
Наряду с тем, что платформа содержит механизмы, позволяющие создавать одни объекты на основании других, каких-либо специальных механизмов для анализа цепочек связанных объектов платформа не содержит.
Для решения подобной задачи, мы дадим некоторые рекомендации, которые могут быть положены в основу конкретного решения.
Для построения цепочек связанных объектов необходимо у каждого объекта, который будет вводиться на основании, создать служебный реквизит для хранения ссылки на объект-основание. Затем следует создать объект конфигурации КритерийОтбора, который будет использоваться для установки отбора по требуемому значению служебного реквизита. В дальнейшем, для получения всех объектов, введенных на основании, достаточно будет установить нужное значение отбора в критерии отбора.
Одиночный подбор
При одиночном подборе форма справочника будет закрываться сразу после выбора элемента. Для выбора следующего элемента необходимо будет снова инициировать подбор. [488]
Создадим основную форму выбора справочника "Номенклатура". Затем добавим в состав командной панели табличного поля документа "ПриходнаяНакладная" кнопку "Подбор".
Добавим кнопку "Подбор"

В форме документа, в обработчик события нажатия кнопки "Подбор" добавим следующий текст:
Процедура КоманднаяПанельМатериалыПодбор(Кнопка)
ФормаПодбора = Справочники.Номенклатура.ПолучитьФормуВыбора( ,ЭлементыФормы.Материалы);
ФормаПодбора.Открыть();
КонецПроцедуры
Затем создадим обработчик события "Обработка выбора" табличного поля "Материалы", расположенного в форме документа "ПриходнаяНакладная":
Процедура МатериалыОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
НоваяСтрока = Материалы.Добавить();
НоваяСтрока.Материал = ВыбранноеЗначение;
ЭлементыФормы.Материалы.ТекущаяСтрока = НоваяСтрока;
КонецПроцедуры [489]
Запустите 1С:Предприятие в режиме отладки и проверьте работу одиночного подбора.
Оформление строк табличного поля
Одним из полезных свойств элемента управления "Табличное поле" является возможность настройки оформления его строк программным способом.
Для иллюстрации этой возможности мы снова воспользуемся формой справочника "Номенклатура" и придадим ей "нестандартный" вид.
Откроем в конфигураторе форму списка справочника "Номенклатура" и создадим обработчик события формы "При открытии" со следующим текстом:
СписокСправочника = ЭлементыФормы.СправочникСписок;
//задать режим чередования цветов строк
СписокСправочника.ЦветФонаЧередованияСтрок = WEBЦвета.Бежевый;
СписокСправочника.ЧередованиеЦветовСтрок = Истина;
//скрыть линии сетки
СписокСправочника.ВертикальныеЛинии = Ложь;
СписокСправочника.ГоризонтальныеЛинии = Ложь;
КонецПроцедуры
Затем мы скрываем линии разделяющие колонки и строки.
Теперь откроем обработчик события "ПриВыводеСтроки" табличного поля списка справочника, и добавим в него следующие строки:
//для элементов отобразим цену и ...
Если Не ДанныеСтроки.ЭтоГруппа Тогда
ОтборНоменклатуры = Новый Структура;
ОтборНоменклатуры.Вставить("Номенклатура", ДанныеСтроки.Ссылка);
ОформлениеСтроки.Ячейки.Цена.ОтображатьТекст = Истина;
АктуальнаяЦена = РегистрыСведений.Цены.ПолучитьПоследнее(, ОтборНоменклатуры).Цена;
ОформлениеСтроки.Ячейки.Цена.Текст = АктуальнаяЦена;
//низкие цены выделим другим цветом
Если АктуальнаяЦена < 500 Тогда
ОформлениеСтроки.Ячейки.Цена.ЦветТекста = WEBЦвета.Васильковый;
КонецЕсли;
//... раздвинуть строку если длинное наименование
Если СтрДлина(СокрЛП(ДанныеСтроки.Наименование)) > 30 Тогда
ОформлениеСтроки.Ячейки.Наименование.АвтоВысотаЯчейки = Истина;
ОформлениеСтроки.Ячейки.Наименование.ВысотаЯчейки = 3;
КонецЕсли;
КонецЕсли;
КонецПроцедуры [527]
Запустим 1С:Предприятие в режиме отладки и посмотрим на результат:

[528]


Организация подборов
Задача организации подбора заключается, как правило, в заполнении табличной части информацией, которую выбирает пользователь в списке какого-либо объекта.
Отбор объектов, введенных на основании
Поскольку задача получения всех объектов, введенных на основании какого-либо другого объекта чаще всего возникает при анализе документов, мы рассмотрим применение описанной выше методики на примере получения списка документов, введенных на основании элемента справочника "Клиенты". [497]
Создадим новый объект конфигурации "КритерийОтбора" с именем "ОказаниеУслуги". На закладке "Данные" выберем тип используемого критерия - СправочникСсылка.Клиенты.
На закладке "Состав" в качестве объектов, входящих в критерий, выберем реквизит "Основание" документа "ОказаниеУслуги":

На закладке "Формы" создадим основную форму списка при помощи конструктора. [498]
Запустите 1С:Предприятие в режиме отладки и проверьте работу критерия отбора:
Кнопка "Перейти" открывает форму списка критерия отбора...

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

ФормаКритерия = КритерииОтбора.ОказаниеУслуги.ПолучитьФорму();
ФормаКритерия.Открыть();
СписокКритерияОтбора = ФормаКритерия.ЭлементыФормы.Список.Значение;
СписокКритерияОтбора.Отбор.ЗначениеОтбора.Значение = ЭлементыФормы.СправочникСписок.ТекущаяСтрока;
МассивСсылок = КритерииОтбора.ОказаниеУслуги.Найти(ЭлементыФормы.СправочникСписок.ТекущаяСтрока);
Для Каждого НужнаяСсылка Из МассивСсылок Цикл
Сообщить(НужнаяСсылка);
КонецЦикла;
КонецПроцедуры


Подбор с использованием множественного выбора
Еще одним способом организации подбора является возможность использования свойства формы "Множественный выбор". Это свойство разрешает множественный выбор в табличных полях формы. В этом случае в форму документа будет возвращен не элемент справочника, а массив элементов, выбранных в табличном поле формы справочника. [490]
В форме документа "ПриходнаяНакладная" внесем в обработчик события нажатия кнопки "Подбор" следующие изменения:
Процедура КоманднаяПанельМатериалыПодбор(Кнопка)
ФормаПодбора = Справочники.Номенклатура.ПолучитьФормуСписка( ,ЭлементыФормы.Материалы);
ФормаПодбора.РежимВыбора = Истина;
//ФормаПодбора.ЗакрыватьПриВыборе = Ложь;
ФормаПодбора.МножественныйВыбор = Истина;
ФормаПодбора.Открыть();
КонецПроцедуры
В обработчик события "Обработка выбора" добавим обход массива переданных элементов:
Процедура МатериалыОбработкаВыбора(Элемент, РезультатВыбора, СтандартнаяОбработка)
Для СчетчикЦикла = 0 по РезультатВыбора.ВГраница() Цикл
НоваяСтрока = Материалы.Добавить();
НоваяСтрока.Материал = РезультатВыбора[СчетчикЦикла];
КонецЦикла;
КонецПроцедуры
Запустите 1С:Предприятие в режиме отладки и проверьте работу множественного подбора (множественный выбор в табличном поле выполняется при нажатой кнопке "Control").
Теперь, если вы удалите комментарий в обработчике события нажатия кнопки "Подбор", то получите вариант "множественного подбора с использованием множественного выбора".
Связанные списки
При создании прикладных решений часто возникает необходимость разместить на одной форме несколько списков, информация в которых должна быть логически связана между собой.
Одним из распространенных примеров является необходимость отобразить в форме списка документов движения, которые имеются в каком-либо регистре. В этом случае требуется в одном списке отобразить перечень документов, а в другом - движения того документа, который выбран в первом списке.
Рассмотрим вариант создания такой связи между списками на примере списка документа "ПриходнаяНакладная", в котором будут отображаться движения документа по регистру "ОстаткиМатериалов". Откроем конфигуратор и создадим основную форму списка документа "ПриходнаяНакладная". Уменьшим высоту табличного поля списка документа и на освободившемся пространстве расположим табличное поле с именем "ТабличноеПоле" и типом РегистрНакопленияСписок.ОстаткиМатериалов:
Добавим на форму табличное поле...

[512]
Таким образом мы определили, какие данные будут содержаться в нижнем списке, осталось только установить между двумя списками связь таким образом, чтобы при изменении выбранного элемента в верхнем списке, содержимое нижнего списка менялось соответствующим образом.
Для этого откроем палитру свойств добавленного нами табличного поля и воспользуемся свойством "Связь по регистратору". Связь по регистратору мы будем устанавливать с обработчиком события "При активизации строки" верхнего поля "ДокументСписок":
Установим связь по регистратору...

[513]
Теперь запустим 1С:Предприятие в режиме отладки и проверим работу связанных списков:

Обратите внимание, что при перемещении в верхнем списке, данные нижнего списка меняются соответствующим образом:

Аналогичную связь можно установить исключительно программными средствами, не используя связь по регистратору. Для этого нужно в обработчике события "При активизации строки" верхнего списка устанавливать отбор нижнего списка по регистратору. [514]
Чтобы выполнить этот пример, уберем для нижнего табличного поля связь по регистратору, а для верхнего создадим обработчик события "При активизации строки":
ЭлементыФормы.ТабличноеПоле.Значение.Отбор.Регистратор.Установить(Элемент.ТекущаяСтрока, Истина);
КонецПроцедуры [515]
Ввод на основании
Механизм ввода на основании может быть использован для ввода новых объектов различного типа (документы, справочники, планы видов характеристик и т.д.). Мы рассмотрим этот механизм на примере ввода новых документов, как наиболее распространенном.
Для каждого объекта конфигурации Документ можно разрешить его ввод на основании других объектов базы данных и возможность являться основанием для других объектов. Действия по заполнению реквизитов при вводе на основании должны быть описаны в модуле объекта Документ, в обработчике события "Обработка заполнения". Есть возможность использовать конструктор ввода на основании, который позволяет визуальными средствами конструировать текст обработчика.
Рассмотрим пример, когда документ "ОказаниеУслуги" будет вводиться на основании элемента справочника "Клиенты".
Откроем окно редактирования объекта конфигурации Документ "ОказаниеУслуги" и добавим новый реквизит документа - "ОбъектОснование" с типом СправочникСсылка.Клиенты. Создание такого реквизита не является обязательной частью механизма ввода на основании и понадобится нам только для того, чтобы в последствии построить цепочку зависимых документов. [493]
Перейдем на закладку "Ввод на основании" и определим состав документов, на основании которых может вводиться документ "ОказаниеУслуги", и основанием для которых он может являться:
Определим состав объектов и вызовем конструктор ввода на основании...

[494]
Затем вызовем конструктор ввода на основании и зададим значения реквизитов документа, создаваемого на основании. Для этого воспользуемся кнопкой "Заполнить выражения":

Обратите внимание, что для заполнения реквизита "ОбъектОснование" конструктор предложил использовать значение Основание.Ссылка. В данном случае такая запись будет избыточной, поскольку в качестве основания будет передана ссылка на элемент справочника. Однако в общем случае событие "Обработка заполнения" возникает при создании нового объекта на основании некоторого переданного значения. Совсем не обязательно, что это значение будет иметь тип ссылки.
Согласимся со всем, что предложил конструктор, и нажмем "ОК".
В модуле документа будет сформирован текст обработчика события "Обработка заполнения":
//{{__КОНСТРУКТОР_ВВОД_НА_ОСНОВАНИИ
// Данный фрагмент построен конструктором.
// При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!![495]
Если ТипЗнч(Основание) = Тип("СправочникСсылка.Клиенты") Тогда
// Заполнение шапки
Клиент = Основание.Ссылка;
ОбъектОснование = Основание.Ссылка;
КонецЕсли;
//}}__КОНСТРУКТОР_ВВОД_НА_ОСНОВАНИИ
КонецПроцедуры
Запустите 1С:Предприятие в режиме отладки и проверьте работу ввода на основании. Обратите внимание, что в командной панели формы списка справочника "Клиенты" появилась кнопка "Ввести на основании":

[496]
Вычисляемые колонки в списках
Необходимость вывода произвольных данных в колонках списка возникает, когда вместе с элементом списка нужно отобразить некоторую вычисляемую информацию.
Мы рассмотрим эту ситуацию на примере отображения актуальной цены в списке справочника "Номенклатура".
Откроем в конфигураторе форму списка справочника "Номенклатура" (или, если ее нет, создадим основную форму списка). Воспользуемся контекстным меню правой кнопки мыши и добавим в табличное поле колонку с именем и текстом шапки "Цена":
В табличное поле списка справочника Номенклатура добавим колонку Цена...

Создадим обработчик события табличного поля "При выводе строки", и добавим в него следующий текст:
Процедура СправочникСписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
//для элементов отобразим цену и ...
Если Не ДанныеСтроки.ЭтоГруппа Тогда
ОтборНоменклатуры = Новый Структура;
ОтборНоменклатуры.Вставить("Номенклатура", ДанныеСтроки.Ссылка); [524]
ОформлениеСтроки.Ячейки.Цена.ОтображатьТекст = Истина;
АктуальнаяЦена = РегистрыСведений.Цены.ПолучитьПоследнее(, ОтборНоменклатуры).Цена;
ОформлениеСтроки.Ячейки.Цена.Текст = АктуальнаяЦена;
//низкие цены выделим другим цветом
Если АктуальнаяЦена < 500 Тогда
ОформлениеСтроки.Ячейки.Цена.ЦветТекста = WEBЦвета.Васильковый;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Обработчик события табличного поля "При выводе строки" передает три параметра: "Элемент" - само табличное поле, для которого было вызвано это событие, "ОформлениеСтроки" - объект, содержащий оформление выводимой строки табличного поля и "ДанныеСтроки" - элемент выборки справочника "Номенклатура", отображаемый в выводимой строке.
Первое, что мы делаем в этом обработчике - проверяем, что выводимый элемент справочника не является группой. В этом случае мы создаем вспомогательную структуру для описания отбора ("ОтборНоменклатуры") и помещаем в ячейку "Цена" актуальное значение цены, полученной из периодического регистра сведений "Цены".
Затем мы анализируем значение выведенной цены и если оно находится в нижнем ценовом диапазоне (менее 500 рублей), выделяем это значение васильковым цветом. Для указания цвета мы используем системный набор значений WEBЦвета.
Запустим 1С:Предприятие в режиме отладки и посмотрим, какой внешний вид примет теперь справочник "Номенклатура":

[525]
При использовании обработчика события "При выводе строки" нужно быть крайне внимательным и всегда стараться минимизировать обращения к данным, которые не содержатся в параметре "ДанныеСтроки".
Дело в том, что обработчик этого события вызывается каждый раз при возникновении необходимости перерисовки видимой области табличного поля и отрабатывает столько раз, сколько строк содержит видимая область. Необходимость перерисовки видимой области табличного поля возникает в результате многих событий, связанных как с самим табличным полем, так и с формой. Если проанализировать работу обработчиков событий формы и табличного поля, можно увидеть, что простое добавление новой строки в табличное поле вызовет, скорее всего, не одну, а несколько перерисовок табличного поля.
Поэтому обращение в этом обработчике не к данным строки, а к данным, содержащимся в базе данных (получение значений через точку, обращение к итогам регистров и т.д.), может сильно замедлить вывод формы на экран. Возможно, в некоторых случаях следует отказаться от создания вычисляемых колонок в списках, и выводить вычисляемые данные только для текущей строки списка в дополнительные поля, расположенные на форме. [526]
1С-Предприятие 8.0. Краткий справочник разработчика
Часть IV. Краткий справочник разработчика
Заключительная часть нашей книги содержит набор кратких справочных статей и описаний групп объектов встроенного языка используемых для работы с теми или иными данными базы данных. [529]


Имена обработчиков событий
Используются имена процедур-обработчиков событий, формируемые системой автоматически:
<имя элемента управления> + <название события>
Имена по умолчанию формируются при нажатии "лупы" около события в окне свойств реквизита диалога.
По таким же правилам следует образовывать имена обработчиков самостоятельно.
Именование функций-флагов
Функции, которые предназначены для проверки чего-либо, и возвращают в качестве результата проверки булево значение, следует именовать так, как называется результат проверки, имеющий тип Истина.
Например, если функция должна проверить наличие дублей строк в табличной части документа, то она должна называться "ЕстьДублиСтрок". Или если функция должна проверить принадлежность документа к накладным, то она должна называться "ЭтоНакладная".
Однако, если функция (или процедура) "ЕстьДублиСтрок" и проверяет наличие дублей строк, и выполняет объединение дублирующих строк, при этом не возвращает значения, ее следует именовать "СвернутьДублиСтрок".
Именование переменных-флагов
В процедурах периодически используются переменные, которые содержат в себе некий флаг. Такие переменные следует называть так, как называется истинное значение этого флага.
Например, если нужна переменная, в которой хранится признак наличия ошибок в процедуре, то такая переменная должна называться "ЕстьОшибки". Или если есть признак того, что товар относится к возвратной таре, то такой признак должен называться "ЭтоТара".
Кэш объектов
Система 1С:Предприятие 8.0 использует механизм кэширования данных объектов, считанных из базы данных при использовании объектной техники. Таким образом, для получения реквизитов какого-либо объекта через ссылку, выполняется обращение к кэшу объектов, расположенному в оперативной памяти.
Кэш объектов состоит из двух частей: транзакционного кэша и обычного кэша. В зависимости от того, происходит ли обращение в рамках транзакции или нет, в действие вступает тот или иной кэш:

Все данные, находящиеся в кэше, предназначены только для чтения (ReadOnly), таким образом чтение любых данных, получаемых через ссылку, выполняется только через кэш объектов, а запись - механизмами самих программных объектов.
Концепция оперативного и не оперативного проведения документов
При разработке конфигураций на платформе 1С:Предприятие 8.0 принято использовать концепцию оперативного и неоперативного проведения документов.
Эта концепция подразумевает, что работа пользователей может происходить в двух принципиально разных, по своей сути, режимах.
Оперативное проведение документов пользователями выполняется в режиме "реального времени", т.е. отображает изменения, факты, свершающиеся в настоящее время. Оперативное проведение особенно актуально при многопользовательской работе. Поэтому при оперативном проведении документов следует осуществлять максимум проверок, способных исключить ошибки при вводе данных пользователями. Например, при оперативном проведении следует выполнять контроль остатков на складе списываемой номенклатуры с тем, чтобы исключить одновременную продажу одного товара несколькими продавцами.
Неоперативное проведение документов подразумевает отражение в базе данных фактов, которые свершились в прошлом, или которые точно будут совершены в будущем. Поэтому задача неоперативного проведения документов заключается в том, чтобы просто отразить в информационной базе данные о совершенных операциях.
При неоперативном проведении документов не производится ряд проверок, в частности контроль остатков. Подразумевается, что если в процессе неоперативного проведения документов были допущены ошибки (например, списано такое количество номенклатуры, которого нет на складе), то анализ полученного состояния базы данных является отдельной задачей, не относящейся к неоперативному проведению и выполняющейся отдельно от него.
Таким образом, оперативное проведение служит для того, чтобы в реальном режиме многопользовательской работы определить возможность или невозможность выполнения той или иной операции (и выполнить ее, если возможно), а неоперативное проведение служит для безусловного отражения в базе операций, которые уже были совершены (или точно будут совершены). [541]


Манипулирование данными объектов
Несмотря на большое разнообразие объектов встроенного языка, предназначенных для работы с информационными структурами, создаваемыми на основе объектов конфигурации, лишь некоторые из объектов встроенного языка позволяют изменять данные, хранящиеся в этих информационных структурах. Такие объекты мы назовем объектами манипулирования данными.
Каждый тип объектов манипулирования данными имеет в конфигураторе соответствующий модуль, который называется либо модулем объекта, либо модулем набора записей, в зависимости от принадлежности к тому или иному объекту конфигурации. Для констант этот модуль называется модулем менеджера значений.
Так вот, модуль объекта манипулирования данными будет всегда выполняться при создании объекта манипулирования данными. Кроме этого, он будет всегда выполняться и при интерактивном обращении пользователя к самой структуре манипулирования данными, поскольку такое обращение будет вызывать создание соответствующего объекта манипулирования данными. Например, при открытии формы элемента справочника будет создаваться объект СправочникОбъект.<имя>.
В модуле объекта манипулирования данными, кроме всего прочего, могут быть описаны процедуры с ключевым словом Экспорт, что подразумевает вызов этих процедур как методов соответствующего объекта манипулирования данными. Здесь важно не путать объект манипулирования данными с другими объектами, позволяющими получить доступ к данным этой информационной структуры.
Например, если мы, для объекта конфигурации Справочник "Клиенты" опишем в модуле объекта процедуру:
КонецПроцедуры; [561]
Клиент.Проверка();
Клиент.Проверка();
Во-первых, для констант указаны три объекта манипулирования данными КонстантаМенеджерЗначения.<имя>, КонстантаМенеджер.<имя> и КонстантыНабор. На самом деле манипулирование данными константы осуществляется при помощи объекта КонстантаМенеджерЗначения.<имя>.
Два других объекта - КонстантаМенеджер.<имя> и КонстантыНабор - также позволяют изменять значения констант, хранящиеся в базе данных, однако они, при выполнении своих методов Установить() и Записать() вызывают создание объекта КонстантаМенеджер.<имя>, который и выполняет непосредственное изменение данных.
При выполнении метода Установить() объекта КонстантаМенеджер.<имя>, будет вызван модуль менеджера значения и обработчики событий ПриЗаписи() и ПередЗаписью() для изменяемой константы. При выполнении метода Записать() объекта НаборКонстант, модуль менеджера значения и соответствующие обработчики будут вызваны для каждой константы, входящей в набор.
Во-вторых, для регистра сведений указаны два объекта манипулирования данными. "В чистом виде" манипулирование данными регистра сведений осуществляется при помощи объекта РегистрСведенийНаборЗаписей.<имя>. [562]
Однако существует возможность манипулирования записями регистра сведений и при помощи объекта
РегистрСведенийМенеджерЗаписи.<имя>. Но объект РегистрСведенийМенеджерЗаписи.<имя> работает с данными регистра не напрямую, а через объект РегистрСведенийНаборЗаписей.<имя>. Таким образом, модуль набора записей, а также обработчики событий ПередЗаписью() и ПриЗаписи() набора записей, будут отрабатывать и при манипулировании объектом РегистрСведенийМенеджерЗаписи.<имя>. Однако процедуры и функции, описанные в модуле набора записей с ключевым словом Экспорт, не будут доступны как методы объекта РегистрСведенийМенеджерЗаписи.<имя>. [563]
структура манипулирования данными
объект манипулирования данными
(КонстантаМенеджер.<имя>, КонстантыНабор)
(РегистрСведенийМенеджерЗаписи.<имя>)


Механизм основных форм
У всех прикладных объектов конфигурации существует некоторое количество основных форм. Они служат для отображения данных объекта в том или ином виде. Если разработчик не назначит в качестве основных форм объекта свои собственные, система будет генерировать необходимые формы объекта самостоятельно, в те моменты, когда к ним происходит обращение. Наличие такого механизма позволяет разработчику не тратить время на создание форм для тестирования своей разработки, а воспользоваться тем, что платформа создаст по умолчанию.
Создание этих форм происходит динамически, в процессе работы системы. Форма создается в тот момент, когда к ней происходит обращение. Причем не важно, интерактивное это обращение или программное. Так для констант форма будет создана как при интерактивном выборе в меню Операции

Константы.ПолучитьФорму();
Также примечательным фактом является то, что состав основных форм, определенных для объекта конфигурации может не совпадать с перечнем тех форм, которые вообще можно создать для данного объекта, используя конструктор формы.
Например, для большинства регистров в конфигураторе можно задать основную форму списка. Однако если открыть конструктор форм для регистра, вы увидите, что кроме формы списка предлагается создать и форму набора записей регистра, которая отсутствует в перечне основных форм.
Дело в том, что состав основных форм определяется исходя из того, какое представление данных может понадобиться в процессе интерактивной работы пользователя. Для этих представлений разработчик может создать свои формы и указать их в качестве основных, а может использовать те формы, которые система создаст автоматически.
Конструктор форм, напротив, исходит из потребностей разработчика. Если разработчик посчитает нужным использовать для [542] какого-либо регистра вместо обычной формы списка форму набора записей - он сможет это сделать, воспользовавшись конструктором и определив ее в качестве основной формы регистра. Но для логики работы системы это не будет иметь принципиального значения [543]


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

[535]
Конфигурация поставщика, находящаяся в информационной базе содержит предыдущее состояние поставки. Возможна ситуация, когда конфигурация находится на поддержке одновременно у нескольких поставщиков, каждый из которых поддерживает только свою часть в виде отдельной конфигурации. В этом случае информационная база будет хранить несколько конфигураций поставщиков (состояние предыдущей поставки для каждого поставщика отдельно).
Файлы новой поставки могут существовать в виде файлов конфигураций (полная поставка) и файлов обновлений (поставка обновлений).
Хранилище конфигурации содержит конфигурацию, предназначенную для групповой разработки. Эта конфигурация хранится не в виде единой конфигурации, а в виде отдельных объектов в разрезе версий конфигурации. Таким образом, мы можем получить из хранилища конфигурацию любой версии - для этого она "собирается" из объектов нужной версии.
Теперь представьте, что между всеми этими видами конфигураций существует возможность сравнения и обновления конфигураций. В этом случае очень легко запутаться и название Основная конфигурация как нельзя лучше отражает конечную цель всех изменений. [536]


Объекты, объекты, объекты...
Что такое объект, применительно к 1С? Этот вопрос зачастую ставит в тупик не только начинающих разработчиков, но и людей, имеющих определенный опыт разработки на платформе 1С.
Основная трудность заключается в том, что всегда нужно ясно представлять себе, в каком контексте употребляется этот термин.
Как правило, термин объект употребляется в одном из трех контекстов:
| · | конфигурация, |
| · | база данных, |
| · | встроенный язык, |
Говоря о конфигурации, термином объект конфигурации мы обозначаем некоторую совокупность описания данных и алгоритмов работы с этими данными. Например, в конфигурации может существовать объект справочник "Сотрудники".
На основании каждого объекта конфигурации в базе данных создается информационная структура, в которой будут храниться данные.
Так вот, когда мы говорим о базе данных, термином объект мы обозначаем всего лишь некий элемент такой информационной структуры. Характерной особенностью такого элемента является то, что на него (как на совокупность данных) существует ссылка, которая может являться значением какого либо поля другой информационной структуры.
Например, в базе данных существует справочник "Сотрудники" в котором есть сотрудник Иванов. В этом случае элемент справочника, содержащий информацию о сотруднике Иванов, будет являться объектом базы данных. И если в документе "ПриходнаяНакладная" будет существовать реквизит "ОтветственноеЛицо", то тип значения этого реквизита будет ссылка на объект базы данных, т.е. на элемент справочника, содержащий информацию об Иванове.
Если же мы начинаем говорить о встроенном языке и о том, каким образом средствами встроенного языка работать со справочниками, то [537] термином объект мы обозначаем тип данных, позволяющий получить доступ к данным и обладающий набором свойств и методов.
Существует целый ряд объектов встроенного языка, позволяющих работать со справочниками (СправочникиМенеджер, СправочникМенеджер.<имя>, СправочникСсылка.<имя> и т.д.). Среди них есть один объект, который предоставляет доступ к объекту справочника в базе данных - СправочникОбъект.<имя>.

[538]


Объекты встроенного языка для работы с документами:

*Заливкой выделен объект манипулирования данными

Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551. [577]


Массив = Документы.ТипВсеСсылки().Типы();
Для Каждого ОчереднойТип Из Массив Цикл
Сообщить(ОчереднойТип);
КонецЦикла;


// [<имя документа>]
// Для Каждого ... Из ... Цикл ... КонецЦикла;
//заполнения
Форма = Документы["ОказаниеУслуги"].ПолучитьФормуНовогоДокумента();
Форма.Открыть();
//Пример: Открыть формы списка всех документов, существующих в
// конфигурации
Для Каждого ОчереднойДокумент Из Документы Цикл
Форма = ОчереднойДокумент.ПолучитьФормуСписка();
Форма.Открыть();
КонецЦикла; [578]


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


Выборка = Документы.ПриходнаяНакладная.Выбрать(НачалоМесяца(ТекущаяДата()),КонецМесяца(ТекущаяДата()));
Пока Выборка.Следующий() Цикл
Сообщить(Выборка);
КонецЦикла;


НовыйДокумент = Документы.ПриходнаяНакладная.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Склад = Справочники.Склады.Основной;
//Заполнить табличную часть
НоваяСтрокаТабличнойЧасти = НовыйДокумент.Материалы.Добавить();
НоваяСтрокаТабличнойЧасти.Материал = Справочники.Номенклатура.НайтиПоКоду(6);
НоваяСтрокаТабличнойЧасти.Количество = 10;
НоваяСтрокаТабличнойЧасти.Цена = 22.5;
НоваяСтрокаТабличнойЧасти.Сумма = 225;
НовыйДокумент.Записать(); [579]


Если Не ПроверитьЗаполнениеРеквизитов(ЭтотОбъект.Ссылка) Тогда
Сообщить("Реквизиты документа не заполнены!");
КонецЕсли;


// Скопировать()
НенужныйДокумент = Документы.ОказаниеУслуги.НайтиПоНомеру(13).ПолучитьОбъект();
НенужныйДокумент.УстановитьПометкуУдаления(Истина);


//текущий месяц
СписокНакладных = Новый СписокЗначений;
Выборка = Документы.ПриходнаяНакладная.Выбрать(НачалоМесяца(ТекущаяДата()),КонецМесяца(ТекущаяДата()));
Пока Выборка.Следующий() Цикл
СписокНакладных.Добавить(Выборка.Ссылка);
КонецЦикла; [580]


Выборка = Документы.ПриходнаяНакладная.Выбрать();
Пока Выборка.Следующий() Цикл
Выборка.ПолучитьОбъект().Удалить();
КонецЦикла;
Объекты встроенного языка для работы с перечислениями:


Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
Использование объектов:


// Перечисления
//Пример: Открыть форму списка перечисления
Форма = Перечисления.ВидыНоменклатуры.ПолучитьФормуСписка();
Форма.Открыть();[584]


// .<имя перечисления>
// [<имя перечисления >]
// Для Каждого ... Из ... Цикл ... КонецЦикла;
//Пример: Открыть форму выбора перечисления
Форма = Перечисления.ВидыНоменклатуры.ПолучитьФормуВыбора();
Форма.Открыть();


// .<имя значения перечисления>
// [<имя значения перечисления>]
// [<индекс элемента коллекции>]
// Для Каждого... Из ... Цикл ... КонецЦикла;
// ПустаяСсылка()
//Пример: Получить пустую ссылку на значение перечисления
...
ПустаяСсылкаПеречисления = Перечисления.ВидыНоменклатуры.ПустаяСсылка();
Если ТекущаяНоменклатура.ВидНоменклатуры = ПустаяСсылкаПеречисления Тогда
//предложить заполнение вида номенклатуры
...
КонецЕсли;
...[585]


Объекты встроенного языка для работы с планами видов характеристик

*Заливкой выделен объект манипулирования данными

Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.[586]
Свойства и методы взаимодействия перечисленных объектов в большинстве своем аналогичны свойствам и методам объектов, предназначенных для работы со справочниками (см. раздел "Объекты встроенного языка для работы со справочниками" на странице 570).

*Заливкой выделен объект манипулирования данными

Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551. [588]
ПланСчетовВидыСубконто.<имя>. Используется для доступа к методам специальной табличной части счета ВидыСубконто в целом.
ПланСчетовВидыСубконтоСтрока.<имя>. Строка специальной табличной части счета ВидыСубконто.
Свойства и методы взаимодействия перечисленных объектов в большинстве своем аналогичны свойствам и методам объектов, предназначенных для работы со справочниками (см. раздел "Объекты встроенного языка для работы со справочниками" на странице 570).

*Заливкой выделен объект манипулирования данными

Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551. [609]
ЗаписьСообщенияОбмена - Объект предназначен для организации записи сообщения обмена данными.
ЧтениеСообщенияОбмена - Объект предназначен для приема сообщений обмена данными. При начале чтения он осуществляет проверку правильности задания заголовка сообщения, и отвергает неправильные сообщения. При завершении чтения данный объект модифицирует значение реквизита "НомерПринятого" соответствующего узла плана обмена в соответствии с номером принятого сообщения.
Свойства и методы взаимодействия перечисленных объектов в большинстве своем аналогичны свойствам и методам объектов, предназначенных для работы со справочниками (см. раздел "Объекты встроенного языка для работы со справочниками" на странице 570).
Объекты встроенного языка для работы с планом видов расчета

*Заливкой выделен объект манипулирования данными [590]

Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
ВытесняющиеВидыРасчета.<имя>. Предопределенная табличная часть вида расчета - список вытесняющих видов расчета. Такая табличная часть определена только для планов видов расчета с признаком ИспользуетПериодДействия. Имеет единственную колонку - ВидРасчета типа ПланВидовРасчетаСсылка.<имя>.
ВытесняющиеВидыРасчетаСтрока.<имя>. Строка предопределенной таблицы вытесняющих видов расчета.
ВедущиеВидыРасчета.<имя>. Предопределенная табличная часть вида расчета - список ведущих видов расчета. Имеет единственную колонку - ВидРасчета типа ПланВидовРасчетаСсылка.<имя>.
ВедущиеВидыРасчетаСтрока.<имя>. Строка предопределенной таблицы ведущих видов расчета.
БазовыеВидыРасчета.<имя>. Предопределенная табличная часть вида расчета - список ведущих видов расчета. Такая табличная часть (свойство БазовыеВидыРасчета) определена только для планов видов расчета со свойством ЗависимостьОтБазы не равным значению "Не зависит". Имеет единственную колонку - ВидРасчета типа ПланВидовРасчетаСсылка.<имя>.
БазовыеВидыРасчетаСтрока.<имя>. Строка предопределенной таблицы базовых видов расчета.
Свойства и методы взаимодействия перечисленных объектов в большинстве своем аналогичны свойствам и методам объектов, предназначенных для работы со справочниками (см. раздел "Объекты встроенного языка для работы со справочниками" на странице 570). [591]
Объекты встроенного языка для работы с регистрами накопления

*Заливкой выделен объект манипулирования данными

Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
РегистрНакопленияКлючЗаписи.<имя>. Представляет собой набор значений, однозначно идентифицирующих запись регистра. [599] Объект используется в тех случаях, когда необходимо сослаться на определенную запись. Например, он выступает в качестве значения свойства "ТекущаяСтрока" табличного поля, отображающего список записей регистра.
Использование объектов:


Форма = РегистрыНакопления.ОстаткиМатериалов.ПолучитьФормуСписка();
Форма.Открыть();


// [<имя регистра накопления >]
// Для Каждого ... Из ... Цикл... КонецЦикла;
УказаннаяДата = ЗаданнаяДата;
ИмяРегистра = "ОстаткиМатериалов";
РегистрыНакопления[ИмяРегистра].УстановитьПериодРассчитанныхИтогов(УказаннаяДата);


СтруктураКлючевыхПолей = Новый Структура;
СтруктураКлючевыхПолей.Вставить("Регистратор", Документы.ПриходнаяНакладная.НайтиПоНомеру("0000002"));
СтруктураКлючевыхПолей.Вставить("НомерСтроки",2);
ЭлементыФормы.ТабличноеПоле1.ТекущаяСтрока = РегистрыНакопления.ОстаткиМатериалов.СоздатьКлючЗаписи(СтруктураКлючевыхПолей); [600]


НужныйДокумент = Документы.ПриходнаяНакладная.НайтиПоНомеру(4);
Движения = РегистрыНакопления.ОстаткиМатериалов.СоздатьНаборЗаписей();
Движения.Отбор.Регистратор.Значение = НужныйДокумент;
Движения.Прочитать();


// ВыбратьПоРегистратору()
Выборка = РегистрыНакопления.ОстаткиМатериалов.Выбрать(НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()));
Пока Выборка.Следующий() Цикл
Сообщить("Регистратор: " + Выборка.Регистратор + " Материал: " + Выборка.Материал + " Кол-во: " + Выборка.Количество);
КонецЦикла;


// Для Каждого ... Из ... Цикл ... КонецЦикла;
НужныйДокумент = Документы.ПриходнаяНакладная.НайтиПоНомеру(4);
Движения = РегистрыНакопления.ОстаткиМатериалов.СоздатьНаборЗаписей();
Движения.Отбор.Регистратор.Значение = НужныйДокумент;
Движения.Прочитать();
Для Каждого ОчередноеДвижение Из Движения Цикл
//алгоритм обработки движений
КонецЦикла; [601]
Объекты встроенного языка для работы с регистрами бухгалтерии

*Заливкой выделен объект манипулирования данными

Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
РегистрБухгалтерииЗапись. Используется для доступа к записи регистра бухгалтерии. Объект не создается непосредственно, а предоставляется другими объектами, отвечающими за регистр [603] бухгалтерии. Например, данный объект представляет записи регистра в наборе записей.
РегистрБухгалтерииСубконто. Коллекция значений субконто записи регистра бухгалтерии. Установка и получение значения конкретного субконто осуществляется через оператор [], в качестве параметра которому передается вид субконто или через имя предопределенного субконто.
РегистрБухгалтерииКлючЗаписи. Набор значений, однозначно идентифицирующий запись регистра. Объект используется в тех случаях, когда необходимо сослаться на определенную запись. Например, он выступает в качестве значения свойства ТекущаяСтрока табличного поля, отображающего список записей регистра.
Свойства и методы взаимодействия перечисленных объектов в большинстве своем аналогичны свойствам и методам объектов, предназначенных для работы с регистрами накопления (см. раздел "Регистры накопления" на странице 599). [604]

*Заливкой выделены объекты манипулирования данными [606]

Узнай больше!
Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
РегистрРасчетаЗапись.<имя>. Используется для доступа к записи регистра расчета. Объект не создается непосредственно, а предоставляется другими объектами, отвечающими за регистр Расчета. Например, данный объект представляет записи регистра в наборе записей.
РегистрРасчетаКлючЗаписи.<имя>. Представляет собой набор значений, однозначно идентифицирующих запись регистра. Объект используется в тех случаях, когда необходимо сослаться на определенную запись. Например, он выступает в качестве значения свойства ТекущаяСтрока табличного поля, отображающего список записей регистра.
РегистрРасчетаПерерасчеты.<имя>. Менеджер всех менеджеров перерасчетов регистра расчетов.
ПерерасчетМенеджер.<имя>. Менеджер перерасчета служит для получения набора записей перерасчета.
ПерерасчетНаборЗаписей.<имя>. Набор записей перерасчета.
ПерерасчетЗапись.<имя>. Объект используется для доступа к записи перерасчета.
ФактическийПериодДействия. Массив значений типа ЭлементФактическогоПериодаДействия.
ЭлементФактическогоПериодаДействия. Элемент фактического периода действия.
Свойства и методы взаимодействия перечисленных объектов в большинстве своем аналогичны свойствам и методам объектов, предназначенных для работы с регистрами накопления (см. раздел "Регистры накопления" на странице 599). [607]
Объекты встроенного языка для работы с регистрами сведений

*Заливкой выделен объект манипулирования данными

Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
РегистрСведенийЗапись.<имя>. Предоставляет доступ к записи регистра сведений. Объект не создается непосредственно, а предоставляется другими объектами, связанными с регистром сведений. Например, данный объект представляет записи регистра в наборе записей.
РегистрСведенийКлючЗаписи.<имя>. Представляет собой набор значений, однозначно идентифицирующих запись регистра. Объект используется в тех случаях, когда необходимо сослаться на определенную запись. Например, он выступает в качестве значения свойства "ТекущаяСтрока" табличного поля, отображающего список записей регистра.
Использование объектов:


Элемент = Справочники.Номенклатура.НайтиПоКоду(4);
Отбор = Новый Структура("Номенклатура",Элемент);
ЗначенияРесурсов = РегистрыСведений.Цены.ПолучитьПоследнее(ТекущаяДата(), Отбор);


// [<имя регистра сведений>]
// Для Каждого ... Из ... Цикл ... КонецЦикла;
ИмяРегистра= "Цены";
Форма = РегистрыСведений[ИмяРегистра].ПолучитьФормуСписка();
Форма.Открыть();[594]


СтруктураКлючевыхПолей = Новый Структура;
СтруктураКлючевыхПолей.Вставить("Период", Дата("20040331000000"));
СтруктураКлючевыхПолей.Вставить("Номенклатура", Справочники.Номенклатура.НайтиПоКоду("0000006"));
ЭлементыФормы.ТабличноеПоле1.ТекущаяСтрока = РегистрыСведений.Цены.СоздатьКлючЗаписи(СтруктураКлючевыхПолей);


//дату и время
Набор = РегистрыСведений.Цены.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(ЗаданнаяДата, Истина);
Набор.Прочитать();
Для Каждого ОчереднаяЗапись Из Набор Цикл
Сообщить("Номенклатура = "+ОчереднаяЗапись.Номенклатура+", цена = "+ОчереднаяЗапись.Цена);
КонецЦикла;


Запись = РегистрыСведений.Цены.СоздатьМенеджерЗаписи();
Запись.Период = ТекущаяДата();
Запись.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("0000005");
Запись.Цена = 568;
Запись.Записать(); [595]


// Для ... По ... Цикл ... КонецЦикла;
//дату и время
Набор = РегистрыСведений.Цены.СоздатьНаборЗаписей();
Набор.Отбор.Период.Установить(ЗаданнаяДата, Истина);
Набор.Прочитать();
Для сч_к = 0 По Набор.Количество() - 1 Цикл
Сообщить("Номенклатура = "+Набор[сч_к].Номенклатура+", цена = "+Набор[сч_к].Цена);
КонецЦикла;


Выборка = РегистрыСведений.Цены.Выбрать(НачалоМесяца(ТекущаяДата()), КонецМесяца(ТекущаяДата()));
Пока Выборка.Следующий() цикл
Выборка.ПолучитьМенеджерЗаписи().Удалить();
КонецЦикла;


// ВыбратьПоРегистратору()
Отбор = Новый Структура("Номенклатура", Справочники.Номенклатура.НайтиПоКоду("0000005"));
Выборка = РегистрыСведений.Цены.Выбрать(НачалоГода(ТекущаяДата()),ТекущаяДата(),Отбор);
Пока Выборка.Следующий() Цикл
Сообщить("Дата = "+Выборка.Период+ ", цена = "+Выборка.Цена);
КонецЦикла; [596]
Объекты встроенного языка для работы с константами:

*Заливкой выделен объект манипулирования данными

Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
КонстантаМенеджерЗначения<имя> - используется для доступа к константе. Любая запись константы (интерактивно в форме, объекты КонстантыНабор и КонстантаМенеджер.<имя>) создает объект этого типа и производит запись с его помощью, что обеспечивает вызов модуля и обработчиков событий этого объекта. [565]


Форма = Константы.ПолучитьФорму();
Форма.Открыть();


// [<имя константы>]
// Для Каждого ... Из ... Цикл ... КонецЦикла;
Результат = Константы.ПрефиксНумерации.Получить();
Сообщить("Значение константы ПрефиксНумерации = "+Результат);
//Пример: Установить значение константы "ПрефиксНумерации" равным "ЦБ"
Константы["ПрефиксНумерации"].Установить("ЦБ");
Сообщить("Новое значение = "+Константы["ПрефиксНумерации"].Получить());
//Пример: Очистить значения всех констант
Для Каждого ОчереднаяКонстанта Из Константы Цикл
ОчереднаяКонстанта.Установить(Неопределено);
КонецЦикла;


Набор = Константы.СоздатьНабор("Руководитель, Бухгалтер");
Набор.Руководитель = "Николаев Денис Павлович";
Набор.Бухгалтер = "Николаева Людмила Сергеевна";
Набор.Записать(); [566]


Для Каждого ОчереднаяКонстанта Из Константы Цикл
ИмяКонст = ОчереднаяКонстанта.СоздатьМенеджерЗначения().Метаданные().Имя;
ЗначениеКонст = ОчереднаяКонстанта.Получить();
Сообщить("Константа "+ИмяКонст+" = "+ЗначениеКонст);
КонецЦикла; [567]
Объекты встроенного языка для работы со справочниками

*Заливкой выделен объект манипулирования данными

Про основные виды объектов встроенного языка можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551. [570]


//в конфигурации
Массив = Справочники.ТипВсеСсылки().Типы();
Для Каждого ОчереднойТип из Массив Цикл
Сообщить(ОчереднойТип);
КонецЦикла;


// [<имя справочника>]
// Для Каждого ... Из ... Цикл ... КонецЦикла;
НоваяГруппа = Справочники.Номенклатура.СоздатьГруппу();
НоваяГруппа.Наименование = "Моя новая группа";
НоваяГруппа.Записать();
//Пример: Открыть форму выбора справочника Номенклатура
Форма = Справочники["Номенклатура"].ПолучитьФормуВыбора();
Форма.Открыть(); [571]


// НайтиПоНаименованию()
// НайтиПоРеквизиту()
// ПустаяСсылка()
// ПолучитьСсылку()
// .<имя предопределенного элемента справочника>
//c кодом 13
Если Справочники.Номенклатура.НайтиПоКоду(13).ПометкаУдаления Тогда
Сообщить("Элемент с кодом 13 помечен на удаление");
КонецЕсли;
//Пример: Является ли элемент справочника Номенклатура с наименованием
//"Услуги" группой
Если Справочники.Номенклатура.НайтиПоНаименованию("Услуги", Истина).ЭтоГруппа Тогда
Сообщить("Элемент Услуги является группой");
КонецЕсли;
//Пример: Проверить, что для всех элементов задан вид номенклатуры
ПустаяСсылкаПеречисления = Перечисления.ВидыНоменклатуры.ПустаяСсылка();
Если Не Справочники.Номенклатура.НайтиПоРеквизиту("ВидНоменклатуры", ПустаяСсылкаПеречисления).Пустая() Тогда
Сообщить(" Есть элементы для которых не задан вид номенклатуры");
КонецЕсли;
//Пример: Передать пустую ссылку в параметр метода
Выборка = Справочники.Номенклатура.Выбрать(Справочники.Номенклатура.ПустаяСсылка()); [572]


// ВыбратьИерархически()
Выборка = Справочники.Номенклатура.Выбрать(Справочники.Номенклатура.ПустаяСсылка());
Пока Выборка.Следующий() Цикл
Если Не Выборка.ЭтоГруппа Тогда
Сообщить(Выборка);
КонецЕсли;
КонецЦикла;
//Пример: Удалить все элементы иерархического справочника
Выборка = Справочники.Номенклатура.ВыбратьИерархически();
Пока Выборка.Следующий() Цикл
Выборка.ПолучитьОбъект().Удалить();
КонецЦикла;


// СоздатьЭлемент()
НовыйЭлемент = Справочники.Сотрудники.СоздатьЭлемент();
НовыйЭлемент.Наименование = "Смирнов Андрей Анатольевич";
//Заполнить табличную часть
НоваяСтрокаТабличнойЧасти = НовыйЭлемент.ТрудоваяДеятельность.Добавить();
НоваяСтрокаТабличнойЧасти.Организация = "OOO НТЦ";
НоваяСтрокаТабличнойЧасти.НачалоРаботы = Дата(2003,05,01);
НоваяСтрокаТабличнойЧасти.ОкончаниеРаботы = Дата(2003,12,31);
НоваяСтрокаТабличнойЧасти.Должность = "Программист";
НовыйЭлемент.Записать(); [573]


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


// Скопировать()
Элемент = Справочники.Номенклатура.НайтиПоКоду(10).ПолучитьОбъект();
Элемент.Наименование = "Мое новое наименование";
Элемент.Записать();
//Пример: Заполнить справочник тестовыми данными
Элемент = Справочники.Номенклатура.СоздатьЭлемент();
Элемент.Наименование = "Тестовый элемент";
Элемент.Записать();
Для сч_к = 1 по 1000 Цикл
НовыйЭлемент = Элемент.Скопировать();
НовыйЭлемент.Записать();
КонецЦикла; [574]


//элементами из указанной группы справочника Номенклатура
Выборка = Справочники.Номенклатура.ВыбратьИерархически(ПолеВвода1);
Пока Выборка.Следующий() Цикл
СсылкаНаНоменклатуру = Выборка.Ссылка;
Если СсылкаНаНоменклатуру.ЭтоГруппа Тогда
Продолжить;
КонецЕсли;
НоваяСтрока = Материалы.Добавить();
НоваяСтрока.Материал = СсылкаНаНоменклатуру;
КонецЦикла;


Выборка = Справочники.Клиенты.Выбрать();
Пока Выборка.Следующий() Цикл
Выборка.ПолучитьОбъект().УстановитьПометкуУдаления(Истина);
КонецЦикла; [575]
Обработчики событий
При работе с событиями в платформе 1С:Предприятие 8.0, следует различать два типа событий: события, связанные с формой и элементами управления, расположенными в форме, и все остальные события.
Разница заключается в том, что обработчики событий, связанных с формой и элементами управления, расположенными в форме назначаемые, а обработчики всех остальных событий фиксированные.
Фиксированный обработчик события должен иметь имя, совпадающие с именем события - только в этом случае он будет вызываться при возникновении соответствующего события.
Назначаемый обработчик может иметь произвольное имя, и если имя процедуры совпадает с именем события формы или элемента управления - этого совсем не достаточно для того, чтобы процедура вызывалась для обработки события с таким именем. Требуется явное назначение этой процедуры обработчиком этого события. Таким образом любая процедура, расположенная в модуле формы может быть назначена обработчиком любого события (или сразу нескольких событий) формы или элемента управления, расположенного в форме. Имя обработчика в этом случае не имеет значения, важно лишь то, что он назначен обрабатывать какое-либо событие.
Назначение обработчика может выполняться интерактивно, при работе с формой в конфигураторе, или программно, используя методы формы и элементов управления - УстановитьДействие(). [546]


Общие требования к имени объекта конфигурации
Имя объекта надо стремиться строить на основе синонима объекта так, как это делает система автоматически: пробелы и пр. недопустимые символы удаляются, первые буквы слов делаются заглавными. Сокращения слов (относительно синонима) допускаются только в крайних случаях, при этом необходимо, чтобы по сокращению можно было восстановить слово обратно. В случае длинных синонимов последние слова могут быть опущены, ели это не искажает смысла.
Для реквизитов объектов допускается переставлять слова из синонима местами, например: синоним "Полное наименование", имя "НаименованиеПолное".
Для ведущих объектов подобное не допускается.
Общие требования к комментарию объекта конфигурации
Комментарий задается только в тех случаях, когда необходимы какие-либо пояснения. Комментарий начинается с большой буквы, точки ставятся только после сокращений. Если в синониме использовано сокращение, в комментарии необходимо его расшифровать, например: "Общероссийский классификатор единиц измерения".
Для реквизитов объектов в комментариях в необходимых случаях должно содержаться уточнение, например: "Сумма со всеми налогами". [534]


Общие требования к синониму объекта конфигурации
Синоним объекта должен быть определен так, чтобы осмысленно описывать объект. Сокращения допускаются только общепринятые, например, "ОКЕИ", "ИНН". Следует избегать излишне длинных синонимов, но и укорачивать их с потерей смысла тоже плохо. Синоним начинается с большой буквы, точки ставятся только после сокращений.
Для ведущих объектов метаданных необходимо стремиться к тому, чтобы название объекта в меню, подпись в диалоговых формах совпадали с синонимом или, как минимум, начинались с него.
Для реквизитов объектов подписи в диалогах могут отличаться "в силу обстоятельств" - синоним надо подбирать так, чтобы он осмысленно описывал реквизит в возможных универсальных формах.
Для форм синоним должен начинаться со слов, генерируемых конструктором при создании формы ("Форма списка...", "Форма элемента..." и т. д.), далее, в случае наличия нескольких форм одного [533] назначения, обязательно должно следовать уточнение, например "Форма элемента полная", "Форма элемента упрощенная".
Для макетов унифицированных форм синоним должен состоять из названия формы, например: "ТОРГ-12".
Обычный кэш
Если при обращении к обычному кэшу требуемых данных в нем нет, то выполняется чтение данных объекта из базы данных и сохранение их в кэше. Уникальным идентификатором для кэша, в данном случае, будет являться ссылка на объект базы данных. Поэтому данные каждого считанного [554] объекта могут существовать в кэше в одном из двух видов: либо все данные объекта, либо представление объекта.
Таким образом, если мы обратимся к кэшу для получения представления объекта, и в кэше есть информация для нашей ссылки, данные будут взяты из кэша (если в кэше весь объект, нужное представление будет получено из данных объекта). Если в кэше нет информации для нашей ссылки - из базы данных в кэш будут считаны только поля, необходимые для формирования представления объекта.
Если мы обратимся к кэшу для получения реквизита объекта, и в кэше есть информация для нашей ссылки, дальнейшие действия будут зависеть от того, что находится в кэше. Если в кэше весь объект - значение реквизита будет получено из кэша. Если в кэше представление объекта - оно будет удалено из кэша и в кэш будут считаны все данные объекта. Если же при получении реквизита объекта в кэше нет информации для нашей ссылки - из базы данных будут считаны все поля объекта.
Считанные данные будут находиться в кэше до тех пор, пока не наступит одно из трех событий:
| · | считанные данные будут вытеснены из кэша другими считанными данными других объектов (переполнение кэша), |
| · | при очередном обращении к кэшу окажется, что считанные данные были изменены в базе данных, |
| · | закончится интервал времени в 20 минут, |
| · | данные будут изменены в базе данных. |
Все считанные данные помещаются в последовательную очередь и, поскольку объем кэша ограничен, наиболее старые данные будут вытесняться из кэша последними считанными данными.
При повторном обращении к кэшу за данными уже считанного объекта будет анализироваться интервал времени, прошедший с момента появления данных в кэше.
Если обращение происходит в пределах 20 секунд после поступления данных в кэш, данные считаются верными (валидными). Если интервал превысил 20 секунд, будет выполняться проверка на то, что версия данных, хранящихся в кэше, соответствует версии данных, находящихся в базе данных. В случае если окажется, что версии данных не совпадают (т.е. произошло изменение данных в базе данных), данные, находящиеся в кэше будут удалены из него и [555] выполнено повторное считывание данных из базы данных. Начиная с этого момента начнется отсчет следующего 20-ти секундного интервала валидности этих данных.
Кроме всех вышеперечисленных событий, считанные данные будут удалены из кэша по истечении 20 минут после их последнего считывания из базы данных.
Таким образом при последовательном выполнении двух операторов (где "Номенклатура" - это ссылка на объект справочника):
В = Номенклатура.ВидНоменклатуры;
Окно редактирования объекта конфигурации и палитра свойств
На первый взгляд окно редактирования объекта и палитра свойств дублируют друг друга. В самом деле, в палитре свойств отображены все свойства объекта конфигурации. Зачем было создавать еще и окно редактирования объекта? И если существует окно редактирования объекта, то зачем тогда палитра свойств, которая содержит все то же самое, только в другом виде?
Окно редактирования объекта конфигурации предназначено в первую очередь для быстрого создания новых объектов. Быстрое создание подразумевает ввод исчерпывающей информации об объекте. Значит нужно очень хорошо знать структуру объекта, а на это требуется время... Выходит, что быстро создать объект не получится? Получится! Окно редактирования объекта имеет в своей основе механизм "мастеров": разработчику в нужной последовательности предлагается ввести необходимые данные. Последовательность ввода данных разработана таким образом, чтобы предыдущие данные могли служить основой для ввода последующих данных. Движение управляется кнопками "Далее" и "Назад". На каждом шаге предлагается ввести группу логически связанных между собой данных.
Но, предположим, что вы уже освоились со структурой объектов или вам просто нужно изменить несколько свойств объекта. Чтобы при этом не нужно было опять "прокручивать" все с самого начала, окно редактирования объекта содержит закладки, которые позволяют вам перейти непосредственно к тому шагу, на котором вводятся интересующие вас данные.
Таким образом окно редактирования объекта помогает быстро создать незнакомый объект конфигурации и в то же время обеспечивает удобный доступ к нужным свойствам при редактировании существующих объектов.
Что же касается палитры свойств, то она предоставляет одну абсолютно незаменимую возможность. Дело в том, что она не привязана по своей структуре к какому-то конкретному виду объектов конфигурации, просто ее содержимое меняется в зависимости от того, какой объект является текущим. За счет этого она может [544] "запоминать", какое свойство объекта в ней выбрано, и при переходе в дереве к другому объекту, она будет подсвечивать "у себя" все то же свойство, но уже другого объекта.
Такая способность палитры свойств абсолютно незаменима, когда, например, среди трех десятков справочников конфигурации вам нужно быстро найти те, которые подчинены какому-нибудь другому справочнику. В этом случае вы выбираете мышью в палитре свойств свойство "Владелец" любого справочника, затем переходите в дерево объектов конфигурации и просто пробегаете его при помощи стрелок




Получение представлений ссылочных объектов
При использовании объекта вида Ссылка в элементах управления, для отображения его на экране всегда используется представление объекта (например, элемент справочника может иметь представление в виде наименования или в виде кода). Поскольку объект вида Ссылка содержит только внутренний идентификатор, выполняется обращение к кэшу объектов за получением представления ссылочного объекта. Если в кэше есть валидное представление - берется оно. Если в кэше есть валидные данные объекта - представление получается из них.
В остальных случаях выполняется чтение в кэш полей объекта, необходимых для формирования представления.
Аналогичный механизм используется при вызове функции:
А = Строка(СсылкаНаЭлементСправочникаНоменклатура);
а также при неявном преобразовании ссылочной переменной к типу Строка.
Теперь, если вспомнить нашу работу с конструктором выходной формы, лишний раз становится понятно, почему конструктор, при выборе ссылочного поля, всегда добавляет к списку выбранных полей представление этого поля. Именно для того, чтобы не выводить в ячейку табличного поля ссылку и не вызывать тем самым преобразования ссылочной переменной к типу Строка со всеми вытекающими отсюда действиями. [558]


Понятие момента времени
Для определения положения документа на оси времени используется реквизит документа "Дата". Дата содержит время с точностью до секунды. Это позволяет контролировать последовательность записи документов. Однако при большом объеме создаваемых документов вероятна ситуация, когда несколько документов будут иметь одинаковое значение даты (т.е. будут созданы в течение одной секунды). Как в этом случае определить последовательность созданных документов?
Для обработки подобных ситуаций было введено понятие момент времени. Момент времени представляет собой совокупность даты, времени и ссылки на объект базы данных. Момент времени позволяет однозначно идентифицировать любой объект ссылочного типа базы данных на оси событий, но имеет смысл, в основном, только для документов. Кроме того, момент времени позволяет идентифицировать и не объектные данные, например, записи регистров, подчиненных регистратору.
Понятие момента времени реализовано во встроенном языке при помощи универсального объекта МоментВремени. Этот объект имеет свойства "Дата" и "Ссылка", которые позволяют получить "составляющие" момента времени, и один метод - Сравнить(), при помощи которого возможно сравнение двух моментов времени между собой. Кроме этого объект МоментВремени имеет конструктор и может быть создан в явном виде для любого объекта базы данных ссылочного типа.
Для нескольких документов, имеющих одинаковую дату и время, последовательность их на оси событий определяется системой исходя из ссылок на эти документы, может не совпадать с последовательностью создания документов, и не доступна для изменения пользователем. [540]


Последовательность событий при записи из формы записи регистра сведений

Замечание. Работа с формой записи регистра сведений осуществляется при помощи объекта РегистрСведенийМенеджерЗаписи.<имя>, который, в свою [597] очередь, использует объект РегистрСведенийНаборЗаписей.<имя>.
Особенности внутренней реализации объекта РегистрСведенийМенеджерЗаписи.<имя> таковы, что в случае записи существующей записи регистра сведений, обработчики события ПередЗаписью() и ПриЗаписи() модуля набора записей будут вызваны дважды: сначала для "старого" набора записей (с количеством записей 0) и затем для "нового" набора записей (с количеством записей 1).
Последовательность событий при записи констант из формы

Замечание. Работа с формой констант осуществляется при помощи объекта КонстантыНабор, который, в свою очередь, использует объект КонстантаМенеджерЗначения.<имя>. [568]
Особенности внутренней реализации объекта КонстантыНабор таковы, что при записи набора констант, обработчики события ПередЗаписью() и ПриЗаписи() модуля менеджера значения константы будут вызваны для каждой константы, входящей в записываемый набор. [569]


Правила образования имен элементов управления
Имена надписей образуются по следующим правилам:
| · | если надпись относится к элементу управления, имя составляет как "Надпись"+ ИмяЭлементаУправления; |
| · | в остальных случаях им составляется как "Надпись"+ИмяНадписи. |
Для имен рамок используется префикс "Рамка". Для командной панели формы используется префикс "КоманднаяПанель". [532]
Для имен командных панелей табличных частей формы используется префикс "КоманднаяПанель"+ИмяТабличнойЧасти, например, "КоманднаяПанельСпецификация".
Элементы управления, связанные с данными, называются так же, как данные.
Правила образования имен переменных
Имена переменных (параметров) следует образовывать от терминов предметной области. При именовании переменных следует использовать только термины, используемые в документации к 1С:Предприятию 8.0 или в методических материалах фирмы "1С" по 1С:Предприятию 8.0.
Из имени переменной должно быть понятно ее назначение. Имена следует образовывать путем "склеивания" слов - удаления пробелов между словами. Каждое отдельное слово в "склеенном" имени пишется с прописной буквы. Предлоги и местоимения из одной буквы также пишутся прописными буквами.
Например:
работа с каталогом - РаботаСКаталогом
количество пачек в коробке - КоличествоПачекВКоробке
Имена переменных не следует начинать с подчеркивания.
Имена переменных ни в коем случае не должны состоять из одного символа. Использование коротких имен переменных допускается только для счетчиков циклов. [530]
Правила образования имен процедур (функций)
Имена процедур в общем случае, следует образовывать от глаголов неопределенного вида, например:
правильно
ПроверитьДублиСтрок(),
неправильно
ПроверкаДублейСтрок();
правильно
ЗагрузитьКонтрагента(),
неправильно
ЗагрузкаКонтрагента().
Имена процедур и функции должны давать представление о характере выполняемых процедурой (функцией) действий.
Примеры хороших имен:
ПроверитьДублиСтрок(), ПодобратьВидРасчета(), ПолучитьИнформациюОПроводке()
Примеры плохих имен:
OK(), Есть(), ЕщеФлажки(), НамПодходит(). [531]
События, связанные с формой
События, обрабатываемые формой, довольно разнообразны и на них стоит остановиться отдельно.
Во-первых, для формы доступна обработка событий, связанных с изменением данных как самой формы, так и подчиненных форм. Поскольку данные формы могут быть самыми различными, определена только категория этих событий, но сами события определяются путем программного назначения обработчика конкретного события. Для этого используется метод объекта Форма - ПодключитьОбработчикИзмененияДанных() (есть и обратный метод - ОтключитьОбработчикИзмененияДанных()). В параметрах этого метода передается имя обработчика данных, а также путь к данным, изменение которых будет отлеживаться этим обработчиком.

В случае, когда в форме объекта редактируются дополнительные, логически связанные данные, существует два способа для отслеживания изменения объекта и синхронизации этих данных:
| 1. | Для синхронизации данных, которые изменяются и записываются синхронно с объектом, нужно использовать событие расширения формы объекта - "ПриИзмененииДанных". |
Примером таких данных могут служить наборы записей регистров у документа, или картинка у справочника.
| 2. | Для синхронизации данных, которые редактируются и записываются отдельно от самого объекта, нужно использовать обработчик события изменения данных назначенный на изменения ссылки объекта. |
Например, для формы справочника валют, в котором редактируется список курсов валюты, он может выглядеть следующим образом:
ПодключитьОбработчикИзмененияДанных( "СправочнжОбъект.Ссылка", "ПриИзмененииСсылки", Ложь); [547]
Сам же обработчик "ПриИзмененииСсылки()" будет выглядеть следующим образом:
Процедура ПриИзмененииСсылки(Путь)
СписокКурсов.Отбор.Валюта.Установить(Ссылка);
КонецПроцедуры
Кроме этого существует ряд событий, позволяющих формам взаимодействовать друг с другом.
Прежде всего это события, связанные с подчиненностью одной формы другой.
Во-первых, форма может обрабатывать событие ОбработкаАктивизацииОбъекта(), которое возникает при изменении активного объекта в одной из подчиненных форм или при вызове в одной из подчиненных форм метода ОповеститьОбАктивизацииОбъекта().
Во-вторых, форма может обрабатывать событие ОбработкаВыбора(), которое возникает при выборе объекта в одной из подчиненных форм или при вызове в одной из подчиненных форм метода ОповеститьОВыбореОбъекта().
В-третьих, форма может обрабатывать событие ОбработкаЗаписиНовогоОбъекта(), которое возникает при записи объекта в одной из подчиненных форм или при вызове в одной из подчиненных форм метода ОповеститьОЗаписиНовогоОбъекта().
Но кроме этих трех событий существует еще одно событие объекта Форма, которое позволяет взаимодействовать не только подчиненным, но вообще любым открытым формам. Это событие ОбработкаОповещения(), которое возникает при оповещении всех открытых форм методом глобального контекста Оповестить(). [548]
В заключение следует отметить одну интересную особенность в обработке события модуля приложения ОбработкаВнешнегоСобытия(). Это событие возникает при посылке внешним приложением сообщения, сформированного в специальном формате. Так вот, внешнее событие сначала будет предложено обработать всем открытым формам (по событию ВнешнееСобытие()), а затем уже это внешнее событие может быть обработано обработчиком модуля приложения. [549]
Способы доступа к данным
Система 1С:Предприятие 8.0 поддерживает два способа доступа к данным, хранящимся в базе данных:
| · | объектный (для чтения и записи), |
| · | табличный (для чтения). |
Объектный способ доступа к данным реализован посредством использования объектов встроенного языка. При этом обращение к какому-либо объекту встроенного языка, является обращением к некоторой совокупности данных, как к единому целому.
Например, объект ДокументОбъект.ОказаниеУслуги будет содержать значения всех реквизитов документа "Оказание услуги" и всех его табличных частей.
Объектная техника обеспечивает сохранение целостности объектов, кэширование объектов, вызов соответствующих обработчиков событий и т.д.
Табличный доступ к данным реализован посредством использования запросов к базе данных. В этой технике разработчик получает возможность оперировать отдельными полями таблиц базы данных, в которых хранятся те или иные данные.
Табличная техника предназначена для получения информации из базы данных по некоторым условиям (отбор, группировка, сортировка, объединение нескольких выборок, расчет итогов и т.д.). Табличная техника оптимизирована для обработки больших объемов информации, расположенной в базе данных, и получения данных, отвечающих заданным критериям. [553]


Способы работы с коллекцией
Многие объекты встроенного языка являются коллекциями Коллекция представляет собой совокупность объектов. Существуют общие принципы работы с любой коллекцией. Во-первых, доступ к каждому объекту коллекции возможен путем перебора элементов коллекции в цикле. Для этого используется конструкция языка Для Каждого ... из ... Цикл ...:
Для Каждого СтрокаТабличнойЧасти из ТабличнаяЧасть Цикл
Сообщить(СтрокаТабличнойЧасти.Услуга);
КонецЦикла;
Во-вторых, возможен доступ напрямую к элементу коллекции, без перебора коллекции в цикле. Здесь возможны различные комбинации двух обращений:
1. Если каждому элементу коллекции можно сопоставить уникальное имя, тогда обращение к элементу коллекции, как правило, возможно по этому имени:
... = Справочники.Сотрудники;
... = Справочники ["Сотрудники"];
2. Если нет смысла в "персонификации" элементов коллекции, тогда обращение к элементу коллекции, как правило, возможно по индексу (индекс первого элемента коллекции - ноль):
ТабличнаяЧасть[0];
Следует отметить, что существуют коллекции, сочетающие оба вида обращений. Например, к коллекции колонок таблицы значений можно обращаться как по именам колонок, так и по индексу. [550]


Справочники и документы
Интересно обратить внимание на разницу в употреблении единственного и множественного числа при именовании объектов вида "Справочник" и объектов вида "Документ". Если вы откроете дерево типовой конфигурации, то увидите, что все объекты, расположенные в ветке "Справочники", как правило, именованы во множественном числе. В ветке же "Документы" все объекты, как правило, именованы в единственном числе. Может сложиться впечатление что, создавая объект "Справочник", мы создаем "хранилище" для записей этого справочника, а, создавая "Документ", мы создаем некий шаблон этого документа. На самом деле это не так.
Создавая в конфигураторе объект вида "Справочник" мы даем ему наименование во множественном числе ("Товары"), подразумевая тем самым, что в базе данных этот объект будет состоять из записей, каждая из которых описывает один товар (в единственном числе).
Создавая в конфигураторе объект вида "Документ" мы даем ему наименование в единственном числе ("Приходная накладная"), однако на самом деле мы создаем такое же "хранилище", как и в случае со справочником. Каждая запись этого "хранилища" будет описывать одну приходную накладную (в единственном числе). Поэтому концептуально правильно было бы в конфигураторе задавать наименование объекта вида "Документ" во множественном числе, подчеркивая тем самым описание набора документов этого вида (например, "Приходные накладные").
Однако, психология человека такова, что, открывая ветку "Документы", он ожидает увидеть перечисление их в единственном числе, а никак не во множественном. Так происходит потому, что в реальной жизни трудно найти подходящий термин для описания совокупности документов одного вида (совокупность записей одного вида обозначить гораздо проще - справочник, план и т.д.). Поэтому соответствующая ветка объектов конфигурации имеет название "Документы", а объекты, создаваемые в этой ветке, именуются в единственном числе, хотя, по сути, сама ветка содержит описания "хранилищ" документов разных видов, а каждый элемент в этой ветке описывает набор всех документов одного вида. [539]


Стандарты именования переменных, процедур и объектов конфигурации
Фирма "1С" использует ряд стандартов, регламентирующих порядок разработки типовых конфигураций на платформе "1С:Предприятие 8.0". В этой главе мы дадим некоторые выдержки из этих стандартов, которые касаются формирования имен объектов конфигурации, переменных, процедур, функций, элементов управления и т. д.
Транзакционный кэш
Если обращение к данным происходит в рамках транзакции, то оно переадресуется транзакционному кэшу. Транзакционный кэш, по сути, представляет собой ту же последовательную очередь, что и обычный кэш, за исключением того, что все данные, находящиеся в транзакционном кэше, являются валидными (гарантированно актуальными). При считывании данных в транзакционный кэш устанавливается блокировка на данные в базе данных, поэтому они гарантированно не могут быть изменены до окончания транзакции.
Транзакционный кэш хранит считанные данные до тех пор, пока они не будут вытеснены более поздними считанными данными, или пока не закончится транзакция.
По окончании транзакции транзакционный кэш очищается, однако действия, выполняемые при этом, зависят от состояния завершения транзакции. [556]
Если транзакция завершена успешно (Commit), данные всех объектов, содержащиеся в транзакционном кэше, переносятся в обычный кэш, а транзакционный кэш очищается.
Commit

Если был выполнен отказ от изменений (Rollback), то просто очищается транзакционный кэш.
Rollback

[557]
Виды объектов встроенного языка
Для обеспечения доступа к информационным структурам базы данных встроенный язык содержит набор унифицированных объектов. Их можно разделить на несколько видов, в зависимости от их назначения.
Менеджер информационных структур одного вида - этот вид объектов является коллекцией значений, содержащей менеджеры всех информационных структур этого вида, существующих в базе данных (например, менеджер справочников - СправочникиМенеджер - коллекция значений, содержащая объекты СправочникМенеджер.<имя>). Предназначен для доступа к отдельным менеджерам информационных структур.
Менеджер конкретной информационной структуры - этот вид объектов предоставляет средства для работы с конкретной информационной структурой (например, менеджер документа Приходная накладная - ДокументМенеджер.ПриходнаяНакладная).
Объект - с помощью объектов этого вида возможна манипуляция данными информационной структуры. Предоставляют доступ к объекту информационной структуры и позволяют изменять информацию в базе данных. Применяются для тех информационных структур, на объекты которых могут существовать ссылки (справочники - СправочникОбъект.<имя>, документы - ДокументОбъект.<имя> и т.д.).
Набор записей - с помощью объектов этого вида также возможна манипуляция данными информационной структуры. Предоставляют доступ к объекту информационной структуры и позволяют изменять информацию в базе данных. Применяются для тех информационных структур, ссылки на объекты которых в принципе не могут использоваться в базе данных (регистры - РегистрНакопленияНаборЗаписей.<имя>, перерасчеты - ПерерасчетНаборЗаписей.<имя> и т.д.).
Ссылка - объекты этого вида служат для указания ссылки на объект базы данных, и кроме этого предоставляют некоторую [551] информацию об этом объекте (например, документ ДокументСсылка.<имя>).
Выборка - объекты этого вида представляют собой набор данных содержащий данные объектов одной информационной структуры отобранных по определенному критерию. Обход выборки выполняется методом Следующий() и считывание данных из базы данных происходит динамически, по мере продвижения по выборке. Получение ссылки на объект возможно при помощи свойства Ссылка, а получение объекта - методом ПолучитьОбъект() (справочник - СправочникВыборка.<имя>).
Список - объекты этого вида предназначены для управления списком объекта, отображаемым в табличном поле (перечисление - ПеречислениеСписок.<имя>). Использовать эти объекты имеет смыл только при выводе информации в табличное поле. [552]


Виртуальные таблицы запросов
Как вы теперь знаете, при создании запроса система предоставляет нам в качестве источников данных некоторое количество виртуальных таблиц. Название "виртуальные" полностью соответствует их сути, поскольку эти таблицы, в свою очередь, также являются результатом запроса, который система формирует в момент выполнения соответствующего участка кода.
По большому счету разработчик может самостоятельно получить те же самые данные, которые система предоставляет ему в качестве виртуальных таблиц, однако алгоритм получения этих данных не будет оптимизирован в силу следующих двух причин.
Во-первых, все виртуальные таблицы параметризованы, т.е. разработчику предоставляется возможность задать некоторые параметры, которые система будет использовать при формировании запроса создания виртуальной таблицы. Примечательным здесь является то, что задание параметров виртуальной таблицы не всегда приводит к простой подстановке указанных разработчиком значений в текст запроса. В зависимости от того, какие параметры виртуальной таблицы указаны разработчиком, система может формировать РАЗЛИЧНЫЕ запросы для получения одной и той же виртуальной таблицы, причем эти запросы будут оптимизированы с точки зрения переданных параметров.
Во-вторых, не всегда разработчик имеет возможность получить доступ к тем данным, к которым имеет доступ система. Например, при использовании виртуальных таблиц регистров сведений, разработчику доступна, по большому счету, вся та же информация о данных регистров, которую использует система при формировании запроса виртуальной таблицы. Совсем иная картина с виртуальными таблицами регистров накопления, где система динамически формирует запрос в зависимости не только от переданных параметров, но и от периода рассчитанных итогов регистра, причем в запросе она использует данные рассчитанных итогов, которые просто не доступны для разработчика при создании запроса.
Конечно, разработчик может самостоятельно перебрать все записи регистра накопления и в итоге получить те же самые данные, которые система предоставляет в виде виртуальной таблицы, однако очевидно, [559] что такой запрос будет менее эффективным и потребует от разработчика гораздо больше трудозатрат. [560]


1С-Предприятие 8.0. Системные константы, процедуры и функции
Документ
В версии 7.7 была предопределенная процедура ВводНового(). Что-то не могу найти ее в версии 8.0...
Теперь факт интерактивного ввода нового объекта (элемента справочника, документа и т.д.) не выделяется в отдельное событие.
В версии 8.0 для анализа аналогичного факта следует использовать событие объекта Форма - "При открытии". Для того чтобы в обработчике этого события проанализировать, выполняется ли ввод нового объекта, или открыт уже существующий, нужно вызвать метод прикладного объекта ЭтоНовый(). Метод вернет значение Истина, если вводится новый объект, и Ложь - в противном случае.
В качестве примера можно посмотреть процедуру "СвойстваПередНачаломДобавления" формы элемента справочника "ВариантыНоменклатуры" в разделе "Доработка справочника ВариантыНоменклатуры" на странице 269, или обработчик события "Перед записью" формы узла плана обмена "Филиалы" в разделе "Создание плана обмена Филиалы" на странице 403.
Более подробную информацию можно найти на диске ИТС в статье "Процедуры - обработчики событий".
Есть ли какой-нибудь аналог для метода ПриЗаписиПерепроводить() в версии 8.0?
Есть.
Режим перепроведения при записи проведенного документа устанавливается с помощью свойства ПриЗаписиПерепроводить, которое существует у расширения формы документа. Если это свойство установить, то при вызове стандартных команд записи в форме, запись проведенного документа будет автоматически выполняться с проведением.
Более подробно о том, что такое расширения формы, можно прочитать в разделе "Данные и элементы управления" на странице 502. [627]
Как сохранить документ без проведения (в 7.7 можно было написать в кнопке #Записать Закрыть)?
В версии 8.0 следует использовать обработчик события нажатия кнопки. Назначение процедур модуля обработчиками события нажатия возможно как для новых кнопок, размещаемых в форме, так и для стандартных кнопок, расположенных в командной панели "ОсновныеДействияФормы".
В обработчике события нажатия следует вызвать метод объекта документ Записать(), с первым параметром, равным РежимЗаписиДокумента.Запись. После этого нужно закрыть форму:
Записать(РежимЗаписиДокумента.Запись);
Закрыть();
КонецПроцедуры
Табличная часть документа (так же, как и любого другого объекта конфигурации, обладающего табличными частями) представляет собой коллекцию значений, элементами которой являются строки табличной части. Поэтому перебор строк табличной части (так же, как и любой другой коллекции значений) проще всего реализовать с помощью цикла Для Каждого ... Из ... Цикл ... КонецЦикла:
ОчереднаяСтрока = ТекСтрокаМатериалы;
...
КонецЦикла;
Для обхода табличной части можно использовать и обычный цикл Для ... По ... Цикл ... КонецЦикла, но необходимо помнить, что индекс первого элемента коллекции всегда равен нулю:
ОчереднаяСтрока = Материалы[СчетчикЦикла];
...
КонецЦикла;
Есть ли в версии 8.0 подчиненные документы?
Нет, специального понятия "Подчиненные документы" в версии 8.0 не существует.
В версии 8.0 одни объекты (документы, элементы справочников, задачи и т.д.) могут являться основанием, для создания других объектов. Таким образом, документ может быть создан не только на основании другого документа, но и на основании, например, элемента справочника или бизнес-процесса.
Поэтому теперь, для получения документов, имеющих ссылки на некоторый документ, рекомендуется использовать объект Критерий отбора. Использование критерия отбора предоставляет больше возможностей, чем механизм подчиненных документов. Критерий отбора позволяет отбирать не только документы, но и другие объекты базы данных. Кроме того, он позволяет непосредственно указать перечень реквизитов, по значению которых необходимо выполнять отбор.
В форме критерия отбора можно использовать стандартный список для отображения найденных значений и также в форме вставить список документов с отбором по указанному критерию.
Однако следует учитывать, что критерий отбора не позволяет выполнять динамический просмотр найденных данных. В список будут включаться все найденные объекты. Соответственно, нецелесообразно использовать этот механизм, если количество [629] найденных объектов по значениям критерия отбора будет достаточно велико.
Примеры работы с зависимыми объектами можно посмотреть в разделах "Ввод на основании" на странице 493 и "Объекты, введенные на основании" на странице 497.
Как добавить строку в табличную часть документа?
Табличная часть документа представляет собой коллекцию значений, элементами которой являются строки табличной части.
В версии 8.0 существуют общие принципы работы с коллекциями значений. Чтобы добавить элемент в коллекцию (в данном случае строку в табличную часть документа), нужно вызвать у коллекции метод Добавить(). Метод возвращает объект - добавленный элемент коллекции. В случае с табличной частью это будет строка табличной части:
СтрокаСостава.Количество = 10;
В версии 8.0 у документа нет метода Провести().
Это связано с тем, что проведение документа не выделяется теперь в отдельное действие. В версии 8.0 проведение рассматривается как один из режимов записи документа.
Таким образом, теперь документ может быть либо просто записан, либо записан с проведением, либо с отменой проведения. Режим записи документа задается параметром его метода Записать():
В версии 8.0 при вызове стандартной команды ввода на основании выполняется создание нового объекта и вызов в модуле этого объекта обработчика события "Обработка заполнения". [630]
В этом обработчике и должен быть реализован алгоритм заполнения данных объекта исходя из данных объекта-основания. Если вы воспользуетесь конструктором ввода на основании, то он сгенерирует обработчик именно этого события.
Надо помнить, что событие "Обработка заполнения" возникает не только при вводе на основании. Это событие будет возникать и при вызове метода объекта Заполнить().
Таким образом, обработчик события "Обработка заполнения" является стандартным местом, в котором реализуется заполнение данных объекта из данных объекта основания без учета того, откуда и зачем вызывается это заполнение.
Поэтому обратите внимание на то, что в этом обработчике следует выполнять только заполнение данных, и не следует делать каких-либо дополнительных действий связанных с интерфейсом системы.
Аналогичным образом выполняется копирование. При копировании вызывается обработчик события объекта "При копировании", в котором можно дополнить стандартное заполнение данных выполняемое системой при копировании объекта. Этот обработчик вызывается, как при интерактивном копировании, так и при вызове метода Скопировать().
Кроме того, расширения форм объектов (форма документа, форма элемента справочника и т.д.) предоставляют свойства ПараметрОснование и ПараметрОбъектКопирования, которые заполняются системой при выполнении стандартных команд ввода на основании и копирования. Значения этих свойств можно использовать в обработчиках событий формы для определения того, что при открытии формы выполнялся ввод на основании или копирование.
Примеры обработки ввода одних объектов на основании других можно посмотреть в разделах "Ввод на основании" на странице 493 и "Объекты, введенные на основании" на странице 497.
Как прочитать движения документа по определенному регистру?
Существует два способа, которыми можно это сделать.
Во-первых, можно "пойти от документа". Для этого следует воспользоваться свойством объекта ДокументОбъект.<имя> - Движения. Это свойство содержит коллекцию пустых наборов записей документа по каждому из регистров, которые указаны для [631] этого документа в конфигураторе. Чтобы получить движения документа по конкретному регистру, нужно обратиться к набору записей этого конкретного регистра (указав имя регистра в качестве свойства через точку), и затем прочитать этот набор записей:
Движения = ДокументОбъект.Движения.ОстаткиМатериалов;
Движения.Прочитать();
Движения.Отбор.Регистратор.Значение = Документы.ПриходнаяНакладная.НайтиПоНомеру(1);
Движения.Прочитать();
Да. Было принято решение в версии 8.0 отказаться от общих реквизитов документов. Вместе с этим в версии 8.0 нет и общего журнала документов.
Теперь, если у всех документов нужно иметь аналогичные реквизиты, например, "Автор" и "Редактор", эти реквизиты следует создать вручную у каждого документа.
При необходимости использовать аналог общего журнала версии 7.7, следует просто создать журнал документов, в котором будут регистрироваться все существующие документы.
Однако в этом случае следует иметь в виду, что при интенсивной работе пользователей в файловом варианте информационной базы, высока вероятность возникновения коллизий. Добиться ее уменьшения можно путем исключения из состава этого журнала документов, которые проводятся наиболее часто. [632]
Глобальный контекст
Сериализация объектов 1С:Предприятия - процедуры "ЗаписатьСообщениеСИзменениями" и "ПрочитатьСообщениеСИзменениями" в модуле узла плана обмена "ОбменСФилиалами" в разделе "Создание процедуры записи данных" на странице 407.
Глобальный модуль
Как "отловить" интерактивную пометку на удаление?
В версии 8.0 изменена реакция на снятие и установку пометки на удаление объекта.
В отличие от версии 7.7, где пометка на удаление обрабатывалась соответствующим событием удаления ("ПриУдаленииЭлемента", "ПриУдаленииДокумента" и т.д.), в версии 8.0 реакция на снятие и установку пометки на удаление приведена в соответствие физическому смыслу выполняемых действий.
При установке пометки удаления не происходит непосредственного удаления элемента из базы, а выполняется всего лишь сохранение его измененного свойства ПометкаУдаления. Поэтому реакцией на это действие в версии 8.0 являются события "Перед записью" и "При записи" (это справедливо и в случае снятия пометки на удаление).
Событие "Перед удалением" возникает теперь только при непосредственном удалении объекта из базы данных.
Таким образом, для того, чтобы отследить интерактивную или программную пометку объекта на удаление, необходимо в обработчике события "ПередЗаписью" проанализировать свойство объекта ПометкаУдаления: значение Истина будет говорить о том, что пометка на удаление устанавливается, Ложь - снимается.
Если в обработчике события "Перед записью" есть необходимость анализировать то состояние объекта, которое было до наступления этого события, нужно считывать данные из базы данных при помощи запроса. [618]
Интерфейсные объекты
Чем в 1С:Предприятии 8.0 отличаются формы справочников, документов и других объектов?
Механизм форм в 1С:Предприятии 8.0 позволяет в любой форме отображать и редактировать любые данные. Принадлежность форм в конфигурации к конкретным объектам метаданных необходима для удобства организации структуры прикладного решения. To есть форма в конфигурации только "принадлежит" объекту метаданных и может использоваться в качестве основной формы для просмотра списка, редактирования или выбора. Содержимое формы никак не определяется тем, к какому объекту метаданных относится форма и выбрана ли форма в качестве основной.
Функциональность формы определяется исключительно реквизитами формы и связанными с ними элементами управления. В большинстве случаев функциональность формы обеспечивается за счет выбора основного реквизита формы. Он определяет наличие расширения формы и обеспечивает специфическое поведение формы для конкретного прикладного объекта. [640]
Например, форма документа будет поддерживать функциональность, ориентированную на редактирование документа, если в качестве ее основного реквизита выбрано значение типа ДокументОбъект.<имя>.
Таким образом, при выборе соответствующих типов реквизитов любая форма может использоваться для редактирования и просмотра любых данных.
При создании форм с помощью конструкторов в форме размещаются реквизиты и элементы управления, в зависимости от ее назначения, выбранного в конструкторе, однако при необходимости разработчик может реализовать в форме любую функциональность.
Более подробную информацию можно найти в разделах "Данные и элементы управления" на странице 502 и "Механизм основных форм" на странице 542.
Выполняется ли автоматическое обновление списков в формах?
Да, выполняется, но не всегда.
В 1С:Предприятии 8.0 автоматическое обновление списков в формах по умолчанию выполняется, только в том случае, когда данные изменяются в текущем сеансе в клиентском приложении.
Если пользователь хочет видеть в списках изменения, вносимые другими пользователями, то ему необходимо нажимать кнопку обновления в командной панели списка или установить режим автоматического обновления списка с определенной периодичностью. Этот режим устанавливается в окне настройки списка.
Вычисляемое значение в поле ввода строки табличного поля - процедура "МатериалыКоличествоПриИзменении" в модуле формы документа "ПриходнаяНакладная" в разделе "Создание процедуры обработки события в модуле формы" на странице 74.
Создание обработчиков событий элементов управления - процедура "МатериалыКоличествоПриИзменении" в модуле формы документа "ПриходнаяНакладная" в разделе "Создание процедуры обработки события в модуле формы" на странице 74.
Обработка нескольких событий одной процедурой - модуль формы документа "ПриходнаяНакладная" в разделе "Создание процедуры обработки события в общем модуле" на странице 77.
Использование макета для вывода в табличный документ - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166.
Управление группировками при выводе в табличный документ - процедура "ВыручкаМастеров" в модуле формы отчета "ВыручкаМастеров" в разделе "Отчет ВыручкаМастеров" на странице 183.
Работа с элементом управления Список выбора - модуль формы отчета "РейтингКлиентов" в разделе "Создание отчета РейтингКлиентов" на странице 198.
Заполнение диаграммы данными - процедура "Сформировать" в модуле формы отчета "РейтингКлиентов" в разделе "Создание отчета РейтингКлиентов" на странице 198. [649]
Использование сводной таблицы - модуль отчета "Универсальный" в разделе "Создание универсального отчета" на странице 211.
Вывод данных в сводную диаграмму - отчет "ВыручкаМастеров2" в разделе "Отчет ВыручкаМастеров2" на странице 227.
Заполнение диаграммы Ганта данными - процедура "КнопкаСформироватьНажатие" в модуле отчета "ДиаграммаНачислений" в разделе "Создание отчета ДиаграммаНачислений" на странице 366.
Наличие параметра "Элемент" позволяет реализовывать один обработчик для событий нескольких элементов управления и анализировать, какой элемент вызвал событие. В частности, это необходимо, если элементы управления создаются средствами встроенного языка. [642]
Рекомендуется создавать обработчики в модуле нажатием кнопки с изображением лупы в соответствующем событии в палитре свойств. В этом случае будет создан обработчик с необходимым составом параметров.
Почему при активизации элемента управления не вызывается автоматически выбор из списка, как это было в 7.7?
В версии 8.0 появился новый режим ввода ссылочных значений путем набора на клавиатуре первых символов кода, наименования или номера требуемого объекта.
Такой режим позволяет существенно ускорить ввод информации. Чтобы этот режим мог эффективно использоваться, изменено типовое поведение автоматического открытия списка выбора.
Оно выполняется теперь не при активизации элемента управления, а при нажатии клавиши "Enter", если значение не заполнено. Таким образом, после активизации элемента управления пользователь может либо ввести несколько первых символов и нажать "Enter" для выполнения поиска по символам, либо сразу нажать "Enter" чтобы инициировать выбор из списка. Такое решение позволяет эффективно сочетать обе возможности.
Для включения режима выбора незаполненного значения нужно установить свойство АвтоВыборНезаполненного. Кроме того, с помощью свойства РежимВыбораНезаполненного можно установить вариант открытия списка при активизации элемента управления.
Однако это рекомендуется делать только в отдельных случаях, так как открытие списка при активизации поля ввода не позволит использовать режим ввода значения по первым буквам.
Почему поиск по первым символам в списке справочника работает только по колонке Наименование?
Это не так.
В динамических списках 1С:Предприятия 8.0 поиск по первым символам выполняется по той колонке, по которой в данный момент упорядочен список (установлена сортировка), независимо от того какая колонка является текущей. [643]
Чтобы выполнять поиск по другой колонке, нужно сменить текущее упорядочивание списка.
Следует сказать, что поиск в динамическом списке выполняется среди десятков и сотен тысяч записей базы данных. Он выполняется не сразу, а с некоторой задержкой, таким образом, чтобы не выполнять поиск при каждом нажатии символа.
Так как поиск ведется по той же колонке, по которой установлена сортировка, то после выполнения поиска пользователь видит не только одну строку с указанными символами в начале, но и соседние строки, имеющие такое же начало. Это позволяет эффективно использовать поиск даже при больших объемах информации отображаемой в списке.
Не отображается новое содержимое табличного поля при программном изменении источника данных.
Элемент управления табличное поле имеет особенное от других поведение при смене источника данных.
Если источник данных меняется интерактивно, в конфигураторе, платформа автоматически создает в табличном поле колонки, соответствующие новому источнику данных. Этот процесс разработчик может наблюдать своими глазами.
Однако если происходит программное изменение источника данных табличного поля, платформа не создает колонки самостоятельно. Создание колонок перекладывается на плечи разработчика, поскольку подразумевается, что разработчик может желать создать собственный набор колонок табличного поля.
Поэтому, для того, чтобы после смены источника данных новые данные были отражены в табличном поле, нужно создать колонки табличного поля. Сделать это можно, например, вызвав метод СоздатьКолонки(), который удаляет все текущие колонки и создает новые в соответствии с новым источником данных.
Пример смены источника данных у табличного поля можно посмотреть в процедуре "ОстаткиМатериаловПриИзменении" в модуле формы документа "ПриходнаяНакладная" в разделе "Изменение источника данных табличного поля" на странице 516.
Более подробную информацию можно найти на диске ИТС в статье "Программное изменение источника данных, отображаемых в табличном поле". [644]
Контекст формы
Куда вписать выражение, чтобы его результат отображался в текстовой колонке табличного поля?
В версии 8.0 нет возможности задавать для колонок текстового поля выражения, которые будут автоматически рассчитываться при отображении этого табличного поля.
Такая возможность не реализована, поскольку весь текст программы в версии 8.0 располагается только в программных модулях.
Поэтому теперь, для вывода вычисляемого значения в колонку табличного поля следует использовать обработчик события "При выводе строки" табличного поля. Это событие возникает каждый раз при формировании очередной строки табличного поля, которая будет отображена на экране.
В качестве примера можно посмотреть процедуру "СправочникСписокПриВыводеСтроки" в модуле формы списка справочника "Номенклатура" в разделе "Вычисляемые колонки в списках" на странице 524.
Более подробную информацию можно найти на диске ИТС в статье "Вывод связанной информации по текущему объекту из списка".
В 8.0 в формах нет слоев. А как теперь создавать закладки в форме?
В версии 8.0 вместо механизма слоев в формах используются панели.
Одна панель может содержать несколько страниц. Поддерживается большое количество вариантов отображения закладок, режим прокручиваемых страниц, использование закладок без распределения по страницам.
Следует заметить, что один элемент управления может располагаться только на одной странице. Поэтому если вы хотите, чтобы в форме присутствовали элементы управления, доступные с любой страницы формы, следует размещать их вне той панели, в которой находятся страницы формы.
Пример использования страниц формы можно посмотреть в форме элемента справочника "Номенклатура" в разделе "Доработка справочника Номенклатура" на странице 261, а также в форме [619] документа "ОказаниеУслуги" в разделе "Отбор объектов, введенных на основании" на странице 497.
Как в формах 1С:Предприятия 8.0 сохранить настройки пользователя (по аналогии с сохранением настроек форм отчетов и обработок в 1С:Предприятии 7.7)?
Чтобы задействовать сохранение настроек в версии 8.0, необходимо в палитре свойств формы установить значения свойств "Сохранять значения" и "Сохраняемые значения". В командной панели формы можно использовать стандартные кнопки сохранения и восстановления настроек.
Следует иметь в виду, что сохранение настроек возможно, только если в качестве основного объекта формы выбраны значения типа ОтчетОбъект.<имя> или ОбработкаОбъект.<имя>, поскольку эту функциональность обеспечивают соответствующие расширения формы.
Более подробно о том, что такое расширения формы, можно прочитать в разделе "Данные и элементы управления" на странице 502.
Есть ли в 1С:Предприятии 8.0 аналог метода АктивизироватьОбъект(), чтобы активизировать нужную строку табличного поля?
В версии 8.0 активизация строки табличного поля выполняется установкой свойства ТекущаяСтрока соответствующего элемента управления. Этому свойству нужно присвоить значение, которое будет идентифицировать нужную строку. Тип этого значения зависит от типа данных, с которыми связано табличное поле.
К примеру, если речь идет о списке справочника, то это будет ссылка на элемент справочника.
Кроме механизма, описанного выше, существует более общий механизм, позволяющий организовывать взаимодействие между различными формами.
Как правило, для установки текущей строки в некоторой форме списка из другой формы, нужно использовать свойство формы НачальноеЗначениеВыбора, а также свойства ПараметрТекущаяСтрока соответствующих расширений форм списков. [620]
Более подробно о том, что такое расширения формы, можно прочитать в разделе "Данные и элементы управления" на странице 502.
Никак не могу заставить работать элемент управления Переключатель! В чем дело?
В версии 8.0 работа с переключателем ведется таким же образом, как и в версии 7.7, за исключением одного отличия.
Теперь для каждого переключателя в группе можно задать значение, которое будет помещаться в данные при выборе этого переключателя. Это значение задается в свойстве ВыбираемоеЗначение. По умолчанию выбираемое значение имеет тип Число и значение равное нулю. Таким образом, если при создании переключателя не определить его выбираемое значение, то в данные всегда будет помещаться нулевое значение.
Возможность задания значения, которое будет выбираться конкретным переключателем, позволяет сделать алгоритм обработки работы переключателя независимым от порядка следования элементов управления, расположенных в форме.
Примеры использования переключателя можно посмотреть в разделах "Изменение источника данных табличного поля" на странице 516, и "Изменение данных табличного поля путем установки типа значения" на странице 520.
Как настроить порядок обхода в форме?
По умолчанию, у панелей форм в 1С:Предприятии 8.0 установлен режим автоматического определения порядка обхода. В этом режиме настроить порядок обхода вручную нельзя.
Для того чтобы стала доступна ручная настройка порядка обхода, нужно в палитре свойств панели формы сбросить флаг "Автопорядок обхода".
Также нужно помнить, что порядок обхода задается не для всей формы целиком, а для каждой панели, расположенной в форме, поэтому и свойство "Автопорядок обхода" нужно регулировать для каждой панели отдельно. [621]
Как в иерархическом списке программно установить отбор по конкретному родителю?
Так как табличное поле поддерживает стандартную механику работы с иерархическими списками, то поле "Родитель" не используется в стандартной механике отборов, а управляется специальным способом. Свойство ТекущийРодитель табличного поля позволяет получить и установить текущего родителя, а свойство ИзменятьТекущегоРодителя позволяет запретить пользователю переход по родителям.
Как работать с элементом управления ПолеВыбора?
В 1С:Предприятии 8.0 значением поля выбора является собственно само выбираемое значение, а не список выбора.
Список выбора, соответствующий полю выбора, задается в свойстве СписокВыбора элемента управления.
Заполнять список выбора рекомендуется в теле модуля, а не в обработчиках событий "Перед открытием" и "При открытии".
Это связано с тем, что значение, устанавливаемое для поля выбора, сохраняется, если оно найдено в списке выбора этого поля. Если же устанавливаемое значение не найдено в списке выбора - сохраняется значение Неопределено.
Таким образом, поскольку установка значения поля выбора в открываемой форме производится в процессе создания формы (до вызова событий "Перед открытием" и "При открытии") - список выбора поля выбора должен быть заполнен в теле модуля формы.
В противном случае, при создании формы значение, устанавливаемое для поля ввода, не будет найдено в его списке выбора (потому что список выбора еще пустой), и в поле выбора будет сохранено значение Неопределено (несмотря на то, что реквизит, с которым связано поле выбора, имеет другое значение). Последующие попытки заполнить список выбора в обработчиках событий "Перед открытием" или "При открытии" не дадут ожидаемого результата, поскольку в поле ввода ранее уже сохранено значение Неопределено.
Например:
ЭлементыФормы.ПолеВыбора1.СписокВыбора.Добавить( 2,"Два");
ЭлементыФормы.ПолеВыбора1.СписокВыбора.Добавить( 3,"Три"); [622]
Пример работы с полем выбора можно посмотреть в модуле формы отчета "РейтингКлиентов" в разделе "Создание отчета РейтингКлиентов" настранице 198.
Не могу найти аналог "семерочного" Активизировать(<имя реквизита>). Нужно периодически программно активизировать элемент формы.
Для указания текущего активного элемента управления, расположенного в форме, следует использовать свойство объекта Форма - ТекущийЭлемент.
Общие объекты
Использование объекта ПостроительОтчета - модуль отчета "Универсальный" в разделе "Создание универсального отчета" на странице 211.
Чтение и запись XML документов - процедура "ЗаписатьСообщениеСИзменениями" в модуле узла плана обмена "ОбменСФилиалами" в разделе "Создание процедуры записи данных" на странице 407.
Работа с объектом Файл - процедуры "ЗаписатьСообщениеСИзменениями" и "ПрочитатьСообщениеСИзменениями" в модуле узла плана обмена "ОбменСФилиалами" в разделе "Создание процедуры записи данных" на странице 407.
Работа с объектом ДиалогВыбораФайла - процедуры модуля формы обработки "ОбменСОтделениями" в разделе "Программный обмен в распределенной информационной базе" на странице 433.
Использование объекта ОписаниеТипов - список документа "ОказаниеУслуги" в разделе "Изменение данных табличного поля путем установки типа значения" на странице 520. [648]
Общие вопросы
Я указываю период (дату начала, дату окончания), но последний день в него не попадает. Почему?
Дело в том, что в версии 8.0 значения типа Дата включают в себя время с точностью до секунд. По умолчанию, если время в явном виде не задается, оно устанавливается равным 00:00:00. Поэтому, если нужно указать период по какую-то дату включительно, следует указывать конец суток, т.е. определенную дату со временем 23:59:59, либо использовать функцию КонецДня(), если время в явном виде не задается.
В качестве примера можно посмотреть процедуру "ДействияФормыРейтингУслугСформировать" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Преобразую число из 4 цифр в строку и получаю количество символов в строке - 5. Это почему так?
Дело в том, что в версии 8.0 получение строкового представления числа выполняется на основе региональных настроек, установленных на компьютере.
В случае, когда установлены стандартные региональные настройки для России, при приведении числа к строке между группами разрядов чисел вставляется неразрывный пробел (Символы.НПП), например:
СтроковоеПредставление = Строка(Год);
// СтроковоеПредставление = "2 004"
// длина строки - 5 символов, включая неразрывный пробел [635]
СтроковоеПредставление = Формат(Год,"ЧГ = 0");
// СтроковоеПредставление = "2004"
// длина строки - 4 символа

Если стоит задача получения строкового представления текущего года, можно воспользоваться встроенной функцией формат, указав в ее параметре соответствующую форматную строку:
Допускает ли версия 8.0 два сеанса работы для одного пользователя одновременно?
Да, в версии 8.0 одновременно может быть запущено два и более сеансов работы с одним пользователем системы. Наличие такой возможности весьма полезно. Например, пользователь, может запустить выполнение длительной операции в одном сеансе и, запустив второй сеанс, продолжать работать с системой.
Что будет результатом вычитания двух значений типа Дата?
В версии 8.0 значение типа Дата содержит как дату, так и время с точностью до секунды. Поэтому результатом вычитания двух значений типа Дата будет число - разница в секундах.
Для получения следующей даты нужно прибавить к дате количество секунд в дате. [636]
У меня есть реквизит составного типа, включающий ссылки на два справочника. Когда я пытаюсь получить через точку наименование справочника, система выдает ошибку. Почему?
В 1С:Предприятии 8.0 для реквизитов имеющих составной тип (боле одного типа) независимо от того какие типы в него включены, значением по умолчанию является значение Неопределено.
Поэтому выражение Реквизит.Наименование будет выдавать ошибку, если реквизиту "Реквизит" не присвоено значение ссылки на один из двух справочников, выбранных в типе этого реквизита.
Какие особенности имеют общие модули в 8.0?
В общих модулях конфигурации могут использоваться только процедуры и функции общих модулей.
В них не могут использоваться процедуры, функции и переменные модуля приложения и модуля внешнего соединения. Кроме того, в общих модулях допускается определение только процедур и функций и не допускается определение переменных.
Таким образом, общие модули представляют собой набор доступных в конфигурации процедур и функций и не имеют хранимого состояния. Это позволяет использовать их не только в клиентском приложении и внешнем соединении, но и на сервере 1С:Предприятия.
Чем отличается значение типа Неопределено и значение типа Null?
Значение типа Неопределено используется, прежде всего, как значение по умолчанию (незаданное значение) для полей с составным типом. Например, если есть реквизит, который имеет составной тип, включающий СправочникСсылка.Сотрудники и СправочникСсылка.Клиенты, то значением этого реквизита по умолчанию будет Неопределено. Также это значение используется и в других случаях для обозначения неуказанного значения.
Значение типа Null используется при работе с таблицами прикладных объектов. Оно обозначает отсутствие значения поля в выборке. Прежде всего, оно используется в результатах запросов выполняющих левое или правое соединение. Поля невыбранных записей таблиц участвующих в таких соединениях будут иметь значение Null. Кроме того, значение типа Null будет иметь, например, [637] реквизит иерархического справочника для элементов-групп, если в метаданных указано, что этот реквизит используется только для элементов, не являющихся группами.
Почему дата отображается со временем?
В 1С:Предприятии 8.0 значение типа Дата всегда включает в себя время с точностью до секунды. Если в конкретных полях прикладных объектов или форм задается хранение даты без времени, то это описывает только область допустимых значений поля. To есть при присвоении устанавливается значение со временем 00:00:00. Само значение не содержит информации о том, может ли поле, где оно хранится, содержать время или нет.
Также как и число не хранит информации о том, может ли поле, где оно хранится, содержать дробные числа. Оно может быть только фактически целым или дробным. Точно так же и дата может фактически содержать время отличное от 00:00:00 или содержать время равное 00:00:00.
При отображении реквизита объекта в табличном поле и в поле ввода система использует имеющуюся информацию о допустимом типе значений и отображает дату без времени. Однако если отображение значения происходит без непосредственной связи с объектом, то используется стандартное форматирование значения типа Дата. При этом отображается и дата и время.
Например, это происходит при заполнении табличного документа или при выводе значения в окно сообщений. Чтобы установить желаемое форматирование, можно или использовать функцию Формат() или установить форматную строку, если эта возможность предусмотрена там, где отображается значение. Свойство Формат может быть, задано, например, для ячейки табличного документа, для элемента управления Надпись и т.д. [638]
Можно ли обращаться к переменным, процедурам и функциям модуля объекта "снаружи" объекта?
В версии 8.0 любая переменная, процедура и функция модуля объекта (документа, справочника, обработки, формы и т.д.) может быть объявлена как экспортируемая. Для этого достаточно в ее объявлении указать слово Экспорт:
...
КонецПроцедуры
ДокументОбъект.Печать(ТабличныйДокумент); //Сформировать печатную форму
ДокументСсылка.Печать(ТабличныйДокумент); //ошибка!
Почему журнал регистрации пустой?
По умолчанию журнал регистрации в системе 1С:Предприятия 8.0 отключен. Для его включения нужно выполнить следующее:
| · | запустить конфигуратор |
| · | открыть меню Администрирование![]() |
| · | настроить параметры регистрируемых событий [639] |
| · | нажать "ОК". |
При использовании конструкции Для Каждого ... Из ... Цикл ... КонецЦикла элементы соответствия обходятся в произвольном порядке.
Можно ли программно "выгонять" пользователей из 1С:Предприятия 8.0?
Да, можно.
Для этого следует использовать процедуру глобального контекста ПрекратитьРаботуСистемы(). Ее выполнение приведет к тому, что работа системы будет завершена независимо от наличия модальных диалогов, открытых редактируемых форм документов, справочников и т.д. При этом не будут вызваны процедуры-обработчики событий завершения работы системы.
Общие вопросы
Я изменил конфигурацию, но когда запускаю 1С:Предприятие - там нет моих изменений. Почему мои изменения не видны?
В информационной базе версии 8.0 хранится несколько конфигураций одного и того же прикладного решения.
Конфигурация, редактируемая разработчиком, - основная конфигурация, - сохраняется без выполнения реструктуризации базы данных. Другими словами, ее сохранение не оказывает влияние на работающих пользователей.
Для работы пользователей в режиме "1С:Предприятие" используется другая конфигурация - конфигурация базы данных, также хранящаяся в информационной базе.
Чтобы привести конфигурацию базы данных в соответствие с основной конфигурацией, нужно выполнить обновление конфигурации базы данных (меню Конфигурация

В меню Конфигурация

Использование команды Конфигурация

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

Для сохранения редактируемой конфигурации без обновления конфигурации базы данных следует использовать команду Сохранить конфигурацию или Сохранить (клавиша Ctrl+S).
Более подробную информацию можно прочитать в разделе "Основная конфигурация и конфигурация базы данных" на странице 52, и в главе "Немного о конфигурациях" на странице 535.
Как прервать работу модуля? Esc не работает...
В версии 8.0 прерывание длительных действий выполняется клавишей Ctrl+Break.
Пользователь может прервать работу модуля, только если в процессе выполнения модуля выполняется вызов процедуры глобального контекста "ОбработкаПрерыванияПользователя". Эта процедура проверяет, была ли нажата пользователем клавиша Ctrl+Break и прерывает работу модуля.
Следует отметить, что работа модуля будет прервана не всегда, а только в тех случаях, когда работа модуля была инициирована следующими действиями пользователя:
| · | нажатие кнопки в форме; |
| · | выбор пункта меню или кнопки панели инструментов в форме; |
| · | выбор пункта меню или кнопки панели инструментов интерфейса; |
| · | действия, инициируемые обработчиками событий "Выбор" элементов управления. |
Почему в типовой конфигурации я не могу отредактировать полученную печатную форму документа?
Печатные формы первичных документов в типовых конфигурациях защищены от изменений пользователем. Режим "Защита" установлен [613] средствами встроенного языка, и типовые конфигурации содержат настройку, позволяющую регулировать установку этого режима.
Следует заметить, что при включенной защите невозможно не только внесение изменений, но и копирование ячеек данного табличного документа.
Аналогичный подход использовался и в типовых конфигурациях версии 7.7 (например, в девятой редакции "Торговля и склад").
В программных модулях у меня не выделяется цветом все, что относится к глобальному контексту (свойства, методы...)?
Да, в версии 8.0 выделяются цветом только конструкции встроенного языка:
Процедура ... КонецПроцедуры,
Функция ... КонецФункции,
Возврат,
Попытка ... Исключение ... КонецПопытки,
Для ... По ... Цикл ... КонецЦикла,
Для Каждого ... Из ... Цикл ... КонецЦикла,
Пока ... Цикл ... КонецЦикла,
Если ... Тогда ... ИначеЕсли ... Иначе ... КонецЕсли,
Перейти,
Прервать,
Продолжить,
Новый,
Перем,
Выполнить,
конструкция "?".
Встроенные функции языка, свойства и методы глобального контекста не являются конструкциями встроенного языка и поэтому не выделяются цветом. [614]
Я не могу внести никаких изменений в типовую конфигурацию. Почему?
В версии 8.0 существует механизм поддержки и обновления конфигураций, позволяющий пользователям обновлять конфигурации в автоматическом или полуавтоматическом режиме при выходе новых версий.
Естественно, что для всех типовых конфигураций, выпускаемых фирмой "1С" по умолчанию включен режим, позволяющий производить обновления автоматически. Поэтому вся конфигурация защищена от изменений, и вы не имеете возможности что-либо редактировать.
Можно изменить режим поддержки конфигурации так, чтобы иметь возможность вносить в нее изменения. Для этого следует воспользоваться командой меню Конфигурация



В этом же окне существует возможность вообще снять конфигурацию с поддержки, но тогда обновление не будет производиться, о чем необходимо заранее предупредить пользователей.
О том, какие существуют конфигурации, можно прочитать в главе "Немного о конфигурациях" на странице 535.
Более подробную информацию можно найти на диске ИТС в статье "Обновление прикладных решений".
Перечисление
Как получить имя значения перечисления, которое задано в метаданных?
Чтобы определить имя значения перечисления, которое задано в метаданных, можно поступить следующим образом.
Допустим, у нас есть значение типа ПеречислениеСсылка.<имя>. Сначала нужно получить имя объекта метаданных, описывающего само перечисление (при помощи метода Метаданные() и свойства Имя).
Затем, зная имя перечисления и конкретное значение перечисления, нужно получить индекс этого значения.
В заключение, по имени перечисления и индексу нужного значения перечисления можно получить объект метаданных, описывающий интересующее нас значение перечисления, и в свойстве Имя получить имя значения перечисления, как оно задано в метаданных.
Следующий пример иллюстрирует описанную методику:
ЗначениеПеречисления = Перечисления.ВидыКонтрагентов.Организация;
ИмяПеречисления = ЗначениеПеречисления.Метаданные().Имя;
ИндексЗначенияПеречисления = Перечисления[ИмяПеречисления].Индекс(ЗначениеПеречисления);
ИмяЗначенияПеречисления = Метаданные.Перечисления[ИмяПеречисления].ЗначенияПеречисления[ИндексЗначенияПеречисления].Имя; [626]
Права
Я добавил новую роль, но не могу назначить ее ни одному пользователю, она не появляется в списке выбора.
В версии 8.0 в информационной базе хранится несколько конфигураций, в том числе основная конфигурация (которую редактирует разработчик), и конфигурация базы данных (которая соответствует структуре базы данных, и с которой работают пользователи в режиме 1С:Предприятие). [615]
При редактировании пользователей доступны только те объекты конфигурации (роли, интерфейсы и языки), которые содержатся в конфигурации базы данных.
Поэтому, чтобы созданную роль можно было назначить пользователю, нужно сначала выполнить обновление конфигурации базы данных (меню Конфигурация

О том, какие существуют конфигурации, можно прочитать в главе "Немного о конфигурациях" на странице 535.
Прикладные объекты
Обращение к табличной части и данным строки табличной части в форме документа - процедура "МатериалыКоличествоПриИзменении" в модуле формы документа "ПриходнаяНакладная" в разделе "Создание процедуры обработки события в модуле формы" на странице 74.
Обход табличной части документа - процедура "ОбработкаПроведения" в модуле документа "Приходная накладная" в разделе "Создание движений документа ПриходнаяНакладная" на странице 89.
Формирование и запись движений документа в модуле документа - процедура "ОбработкаПроведения" в модуле документа "Приходная накладная" в разделе "Создание движений документа ПриходнаяНакладная" на странице 89.
Формирование движений по регистру накопления остатков - процедура "ОбработкаПроведения" в модуле документа "Приходная накладная" в разделе "Создание движений документа ПриходнаяНакладная" на странице 89. [655]
Формирование движений по оборотному регистру накопления - процедура "ОбработкаПроведения" в модуле документа "ОказаниеУслуги" в разделе "Изменение процедуры проведения документа ОказаниеУслуги" на странице 157.
Формирование движений документа по регистру бухгалтерии - процедура "ОбработкаПроведения" в модуле документа "ПриходнаяНакладная" в разделе "Создание движений документа ПриходнаяНакладная" на странице 303.
Формирование движений документа по регистру расчета - смотри процедуру "ОбработкаПроведения" документа "НачисленияСотрудникам" в разделе "Создание документа НачисленияСотрудникам" на странице 341.
Ручное редактирование набора записей регистра в документе - смотри документ "ВводНачальныхОстатковНоменклатуры" в главе "Создание документа ввода начальных остатков" на странице 477.
Получение последних значений ресурсов периодического регистра сведений на указанную дату - процедура "РозничнаяЦена" в общем модуле "РаботаСоСправочниками" в разделе "Создание функции РозничнаяЦена()" на странице 124.
Обращение к значению перечисления - процедура "ОбработкаПроведения" в модуле документа "ОказаниеУслуги" в разделе " Изменение процедуры проведения документа ОказаниеУслуги" на странице 134.
Расчет записей регистра расчета - раздел "Создание процедуры расчета записей регистра Начисления" на странице 349.
Перерасчет записей регистра расчета - процедура "ПерерасчитатьНачисления" в общем модуле "ПроведениеРасчетов" в разделе "Выполнение перерасчета записей регистра" на странице 359.
Организация обмена данными на основе механизма универсального обмена данными - раздел "Универсальный механизм обмена данными" на странице 400.
Организация обмена данными на основе механизма распределенных информационных баз - раздел "Механизм распределенных информационных баз" на странице 426.
Ввод на основании - документ "ОказаниеУслуги" в разделе "Ввод на основании" на странице 493.
Использование объекта КритерийОтбора - в разделе "Отбор объектов, введенных на основании" на странице 497. [656]


Прикладные объекты
Как узнать (проверить) тип значения документа, справочника?
В версии 8.0 для работы с типами прикладных объектов используются не их строковые наименования, а специальный тип "Тип". Значение типа Тип может быть получено функцией Тип(), у которой в качестве параметра указано имя требуемого типа.
Чтобы узнать тип значения переменной нужно определить ее тип функцией ТипЗнч() сравнить с результатом функции Тип():
Если ТипЗнч(Основание) = Тип("ДокументСсылка.ПриходнаяНакладная") Тогда
//Переменная Основание имеет тип значения ДокументСсылка.ПриходнаяНакладная
...
КонецЕсли;
О типах, описывающих прикладные объекты, можно прочитать в главе "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551.
Как в форме списка справочника получить ссылку на текущий элемент?
Для получения ссылки на текущий элемент справочника можно обратиться к свойству ТекущаяСтрока элемента управления ТабличноеПоле. Например:
Сообщить("Текущий элемент:" + ЭлементыФормы.СправочникСписок.ТекущаяСтрока);
Другой способ - обратиться к полю Ссылка текущих данных табличного поля:
Сообщить("Текущий элемент:" + ЭлементыФормы.СправочникСписок.ТекущиеДанные.Ссылка);
Для списков объектных данных (Справочников, Документов,...) эти способы равнозначны, так как поле Ссылка является идентификатором записи. [645]
При обращении к спискам регистров свойство ТекущаяСтрока будет выдавать уже ключ записи регистра, который состоит из нескольких полей.
Таким образом, свойство ТекущаяСтрока для всех типов данных выдает значение, идентифицирующее текущую строку.
Для чего служит флажок "Автопорядок по коду" у плана счетов?
Свойство "Автопорядок по коду" используется для того, чтобы указать системе, что упорядочивание по полю "Порядок" должно всегда подставляться в тех случаях, когда пользователь или разработчик выбирает упорядочивание по коду. Его нужно использовать, прежде всего, тогда, когда с точки зрения пользователя нужно упорядочивать план счетов по коду с учетом разделителей кода счета. Например, если упорядочивать по коду счета, то счета будут располагаться так:
"10.11"
"10.2"
Это правильно с точки зрения сортировки строк, но не соответствует логическому смыслу кодов.
Но если заданы значения поля "Порядок": "10.11" и "10. 2" и установлено свойство "Автопорядок по коду", то при выборе упорядочивания по коду пользователь будет, фактически, получать порядок, учитывающий разделители:
"10.2"
"10.11".
Если свойство не установить, то нужно будет в явном виде выбирать упорядочивание по полю "Порядок".
После записи в регистр сведений набора записей в нем пропадают все данные, которые были до этого, остается только тот набор, который я записываю. В чем дело?
Так происходит потому, что у вашего набора записей не был установлен отбор. Если отбор не установлен, то такой набор записей распространяется на весь регистр и, конечно, это приведет к перезаписи всего регистра сведений новым набором. [646]
Для получения более подробной информации можно посмотреть главу "Объект конфигурации регистр сведений" на странице 120, а также статьи на диске ИТС: "Периодические регистры сведений" и "Проектирование структуры периодических регистров сведений".
Почему в 8.0 нет возможности интерактивно открыть форму элемента справочника только для просмотра?
В версии 8.0 при открытии формы объекта (документа, элемента справочника и т.д.) не выполняется (как раньше) блокировка объекта от изменения другими пользователями. Поэтому два пользователя могут, например, открыть один и тот же документ одновременно. Блокировка устанавливается при начале редактирования данных объекта в форме. Если объект уже заблокирован другим пользователем, то при попытке начала редактирования будет выдано соответствующее сообщение.
Таким образом, нет необходимости в специальном режиме открытия форм объектов для просмотра. Форма объекта может быть открыта из любого режима программы (из списка, из отчета в качестве расшифровки и т.д.) без указания того, предполагается ли выполнять редактирование или нет. [647]


Работа с запросами
Использование ключевого слова ВЫБРАТЬ - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166. [651]
Использование ключевого слова ИЗ - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166.
Использование ключевого слова КАК - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166.
Использование ключевого предложения УПОРЯДОЧИТЬПО - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166.
Использование ключевого предложения ЛЕВОЕ СОЕДИНЕНИЕ ПО - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Использование ключевого слова ГДЕ - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Использование ключевого слова ИТОГИ - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Использование ключевого слова ИЕРАРХИЯ - процедура "ПереченьУслуг" в модуле формы отчета "ПереченьУслуг" в разделе "Отчет ПереченьУслуг" на странице 191.
Использование ключевого предложения ДЛЯ ИЗМЕНЕНИЯ - процедура "ОбработкаПроведения" документа "ОказаниеУслуги" в разделе "Оптимизация документа ОказаниеУслуги" на странице 238.
Получение данных документов запросом - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166.
Получение данных справочника запросом - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе " Отчет Рейтинг услуг" на странице 173. [652]
Получение данных регистра накопления запросом - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Получение данных регистра сведений запросом - процедура "ПереченьУслуг" в модуле формы отчета "ПереченьУслуг" в разделе "Отчет ПереченьУслуг" на странице 191.
Получение данных регистра бухгалтерии запросом - отчет "ОборотноСальдоваяВедомость" в разделе "Создание отчета ОборотноСальдоваяВедомость" на странице 312.
Получение данных плана счетов запросом - отчет "ОборотноСальдоваяВедомость" в разделе "Создание отчета ОборотноСальдоваяВедомость" на странице 312.
Получение данных перерасчета запросом - отчет "Перерасчет" в разделе "Иллюстрация механизмов вытеснения и зависимости от базы" на странице 345, и процедура "ПерерасчитатьНачисления" в общем модуле "ПроведениеРасчетов" в разделе "Выполнение перерасчета записей регистра" на странице 359.
Получение данных графика регистра расчета запросом - процедура "РасчитатьНачисления" в общем модуле "ПроведениеРасчетов" в разделе "Создание процедуры расчета записей регистра Начисления" на странице 349.
Получение данных базы регистра расчета запросом - процедура "РасчитатьНачисления" в общем модуле "ПроведениеРасчетов" в разделе "Создание процедуры расчета записей регистра Начисления" на странице 349.
Получение данных регистра расчета запросом - отчет "НачисленияСотрудникам" в разделе "Создание отчета НачисленияСотрудникам" на странице 357.
Получение данных фактического периода действия записей регистра расчета запросом - процедура "КнопкаСформироватьНажатие" в модуле отчета "ДиаграммаНачислений" в разделе "Создание отчета ДиаграммаНачислений" на странице 366.
Задание параметров виртуальной таблицы источника - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173. [653]
Как выбрать данные из нескольких таблиц - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Как выбрать данные, входящие в указанный период - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Получение данных регистра накопления периодами - процедура "ВыручкаМастеров" в модуле формы отчета "ВыручкаМастеров" в разделе "Отчет ВыручкаМастеров" на странице 183.
Вычисляемое поле в источнике запроса - процедура "Сформировать" в модуле формы отчета "РейтингКлиентов" в разделе "Создание отчета РейтингКлиентов" на странице 198.
Передача списка значений в параметры виртуальной таблицы - процедура "ОбработкаПроведения" документа "ОказаниеУслуги" в разделе "Оптимизация документа ОказаниеУслуги" на странице 238, и процедура "ОстаткиМатериаловПоСвойствам" в форме отчета "ОстаткиМатериаловПоСвойствам" в разделе "Отчет ОстаткиМатериаловПоСвойствам" на странице 277.
Передача результата запроса в параметры виртуальной таблицы - процедура "ОбработкаПроведения" документа "ОказаниеУслуги" в разделе "Оптимизация документа ОказаниеУслуги" на странице 238.
Динамическое формирование текста запроса - процедура "ОстаткиМатериаловПоСвойствам" в форме отчета "ОстаткиМатериаловПоСвойствам" в разделе "Отчет ОстаткиМатериаловПоСвойствам" на странице 277.
Вывод результата запроса в табличный документ - процедура "РеестрДокументовОказаниеУслуги" в модуле формы отчета "РеестрДокументовОказаниеУслуги" в разделе "Отчет РеестрДокументовОказаниеУслуги" на странице 166.
Получение промежуточных итогов - процедура "ВыручкаМастеров" в модуле формы отчета "ВыручкаМастеров" в разделе "Отчет ВыручкаМастеров" на странице 183.
Управление порядком вывода итогов в результате запроса - процедура "ВыручкаМастеров" в модуле формы отчета "ВыручкаМастеров" в разделе " Отчет ВыручкаМастеров" на странице 183. [654]
Обход многоуровневых группировок в результате запроса - процедура "ВыручкаМастеров" в модуле формы отчета "ВыручкаМастеров" в разделе "Отчет ВыручкаМастеров" на странице 183.
Получение итогов по всем датам в выбранном периоде - процедура "ВыручкаМастеров" в модуле формы отчета "ВыручкаМастеров" в разделе "Отчет ВыручкаМастеров" на странице 183.
Вычисляемое поле в результате запроса - смотри процедуру "Сформировать" в модуле формы отчета "РейтингКлиентов" в разделе "Создание отчета РейтингКлиентов" на странице 198.
Выгрузка результата запроса в таблицу значений - смотри модуль формы отчета "РейтингКлиентов" в разделе "Создание отчета РейтингКлиентов" на странице198.
Выгрузка результата запроса в список значений - смотри обработчик события "ОбработкаПроведения" документа "НачисленияСотрудникам" в разделе "Создание процедуры расчета записей регистра Начисления" на странице 349.
Системные константы, процедуры и функции
В версии 7.7 была функция КаталогИБ, а как теперь определить каталог информационной базы, чтобы хранить в нем свои файлы?
Системная функция 1С:Предприятия 7.7 КаталогИБ() не реализована в версии 8.0.
Это связано с тем, что в версии 8.0 вся информационная база физически является одним файлом, независимо от используемого файлового или клиент-серверного варианта работы. Таким образом подразумевается, что понятие каталога, как некоей совокупности файлов, относящихся к данной информационной базе, отсутствует. Теперь все нужные файлы должны размещаться внутри информационной базы. Для этого в 1С:Предприятии 8.0 введен новый тип реквизитов и ресурсов - ХранилищеЗначения.
Функция СтатусВозврата(). Есть аналог в 8.0?
Нет, в версии 8.0 метод СтатусВозврата() не используется.
Чтобы в обработчике события указать на необходимость отмены стандартных действий, выполняемых системой для данного события, нужно использовать специальный параметр обработчика события. Этот параметр имеет тип Булево, а его название зависит от вида события, и может быть различным ("Отказ" или "СтандартнаяОбработка").
Есть ли аналог процедуры ОбработкаОжидания()?
Есть. [616]
В версии 8.0 обработка ожидания может быть установлена методом ПодключитьОбработчикОжидания() (для отключения обработчика ожидания используется метод ОтключитьОбработчикОжидания()). Обработка ожидания может выполняться как в модуле приложения, так и в модуле формы. Для каждой формы, как и для приложения в целом, может быть установлено несколько обработчиков ожидания с разными интервалами.
Более подробно о событиях, связанных с формой, можно прочитать в главе "События, связанные с формой" на странице 547.
Что использовать вместо разделителя строк, который был в 7.7?
Вместо системной константы РазделительСтрок версии 7.7, в версии 8.0 следует использовать системный набор значений Символы. В частности, для указания символа перевода строки следует использовать значение этого набора - "ПС":
Да, в версии 8. 0 есть аналог системной функции ПериодСтр().
Для формирования текстового представления периода следует использовать функцию глобального контекста ПредставлениеПериода(). В качестве параметров в эту функцию передаются даты начала и окончания периода, а также строка, определяющая способ форматирования периода.
Свойство глобального контекста РабочаяДата служит для отображения или установки рабочей даты, используемой в текущем сеансе конфигурации. Поэтому оно содержит дату в виде 44:MM:CC 00:00:00, указывающую на начало дня. [617] Для получения текущего времени следует использовать встроенную функцию ТекущаяДата(), которая возвращает системную дату и время, установленные на компьютере:
Сообщить("Текущее время = " + Формат(ТекущаяДата(),"ДФ='дд.мм.гг чч:мм:сс'"));
Список значений
Раньше (в 7.7) можно было сделать выбор из списка значений в виде маленького списка или меню, которое подстраивалось по элементу управления формы... А как то же самое сделать в 8.0?
В версии 8.0 для реализации такой возможности следует использовать методы формы (а не списка значений, как это было в 7.7): ВыбратьИзСписка() и ВыбратьИзМеню().
В параметрах этих методов указывается элемент управления, рядом с которым должен выполняться выбор. При этом для некоторых элементов управления (табличного поля, поля табличного документа) система располагает список выбора и меню с учетом текущей позиции в этом элементе управления.
Пример вызова:
Выбор = ВыбратьИзСписка(СписокЗначений, ЭлементФормы, НачальноеЗначение);
Справочник
Есть ли в версии 8.0 аналог методу формы справочника ИспользоватьСписокЭлементов()?
Нет.
Для того чтобы отобразить в списке специально отобранный перечень объектов, следует использовать выборку данных запросом и отображение их в форме в таблице значений или табличном документе. При этом система 1С:Предприятие 8.0 будет обеспечивать полноценное взаимодействие других системных механизмов с такими формами.
При использовании динамических списков документов, справочников и т.д., также можно программно установить отбор по полю Ссылка, и указать, что в качестве вида сравнения будет использовано вхождение в список значений. Такой прием тоже позволяет отображать в списке только определенные объекты. Однако такой способ может иметь только ограниченное применение, потому что динамический список обладает большим количеством универсальных возможностей (установка отбора пользователем, переходы по уровням в иерархических списках и т.д.), и сложно совместить в прикладных решениях эти механизмы с отбором по конкретным значениям ссылок. [623]
Говорят, что в версии 8.0 нет периодических реквизитов справочников. А как же теперь хранить историю изменения их значений?
Действительно, в версии 8.0 нет возможности создавать периодические реквизиты объектов. На смену им пришел новый, более универсальный механизм, представленный регистрами сведений. Регистры сведений позволяют хранить информацию любого типа на пересечении комбинации значений измерений.
Регистр сведений можно сделать периодическим, и тогда он будет хранить историю изменения этих значений, с заданной точностью (имеется возможность задать различную периодичность регистра сведений - месяц, день, позиция документа и пр.).
В качестве примера можно посмотреть периодический регистр сведений "Цены", хранящий историю изменения цен номенклатуры, в главе "Периодический регистр сведений" на странице 118.
Более подробную информацию можно найти на диске ИТС в статье "Периодические регистры сведений".
Написал процедуру ПриОткрытии() в модуле формы, но она не вызывается, когда я открываю форму. В чем дело?
Дело в том, что в версии 8.0 любому событию формы может быть назначена процедура, которая будет обрабатывать это событие. Имя такой процедуры может не совпадать (а в большинстве случаев и не совпадает) с именем события, поэтому для того, чтобы ваша процедура "ПриОткрытии" стала обрабатывать событие формы "При открытии" необходимо в конфигураторе, в палитре свойств формы, явным образом назначить ее обработчиком этого события.
Для упрощения работы, в версии 8.0 можно создавать шаблоны обработчиков событий формы. Для этого следует выбрать нужное событие в палитре свойств и нажать на символ лупы в конце поля ввода. Система создаст объявление процедуры в модуле формы и свяжет ее с выбранным событием.
Подробнее можно прочитать об этом в главе "Обработчики событий" на странице 546, и на диске ИТС в статье "Процедуры - обработчики событий". [624]
У меня не получается программно изменить элемент справочника. Почему?
По всей видимости, вы пытаетесь изменять элемент справочника, используя объект СправочникСсылка.<имя>. Объекты этого типа позволяют обращаться к реквизитам и табличным частям справочника в режиме "только чтение".
Для того чтобы изменить данные элемента справочника следует получить объект СправочникОбъект.<имя>, который позволяет как читать, так и записывать данные. Это возможно с помощью метода ПолучитьОбъект().
Более подробную информацию можно найти в главах "Виды объектов встроенного языка, предназначенные для работы с данными прикладных объектов конфигурации" на странице 551, "Манипулирование данными объектов" на странице 561, а также в статьях на диске ИТС: "Работа с прикладными объектами средствами встроенного языка" и "Типы значений, связанные с прикладными объектами".
У прикладных объектов нет методов ПолучитьАтрибут() и УстановитьАтрибут(). Как теперь обращаться к атрибутам объектов, если имя атрибута формируется в процессе вычислений?
Встроенный язык версии 8. 0 поддерживает универсальную возможность обращения к свойствам объектов, используя конструкцию [<имя свойства>], где <имя свойства> - строка или строковая переменная, содержащая имя требуемого свойства:
Объект[ИмяСвойства] = Объект[ИмяСвойства] + " Новый";
В версии 8.0 была введена унифицированная объектная структура данных. Теперь значение ссылки на объект базы данных хранится в поле Ссылка, и во всех случаях (при использовании объекта, выборки, [625] запроса и т.д.) значение ссылки на объект можно получить по имени этого поля:
Пока Выборка.Следующий() Цикл
Склад = Выборка.Ссылка;
...
КонецЦикла;
Таблица (табличный документ)
В 7.7 была процедура НоваяСтраница(). А что в 8.0?
Для того, чтобы в версии 8.0 вставить в табличный документ разделитель страниц, следует использовать метод объекта ТабличныйДокумент - ВывестиГоризонтальныйРазделительСтраниц().
Следует заметить, что также появилась возможность вставлять в табличный документ и вертикальные разделители страниц (метод ВывестиВертикальныйРазделительСтраниц()).
Как сохранить табличный документ в формате Excel? У меня ничего не получается...
В версии 8.0 для сохранения табличного документа в формате, отличающемся от его исходного формата, следует использовать пункт меню Файл

Команда меню Файл

Универсальные коллекции значений
Использование объекта Структура - процедура "РозничнаяЦена" в общем модуле "РаботаСоСправочниками" в разделе "Создание функции РозничнаяЦена()" на странице 124.
Использование объекта Массив - список документа "ОказаниеУслуги" в разделе "Изменение данных табличного поля путем установки типа значения" на странице 520.
Встроенный язык
Использование функции КонецДня() - процедура "РейтингУслуг" в модуле формы отчета "РейтингУслуг" в разделе "Отчет Рейтинг услуг" на странице 173.
Запрос
В запросах версии 7.7 была опция "все вошедшие в запрос". Как сделать то же самое в 8.0?
В версии 7.7 опция "все вошедшие в запрос" использовалась для вывода в отчет всех значений одной из группировок запроса. Такая необходимость могла возникнуть при создании, например, отчета об остатках на складах, в котором обязательно должны быть указаны все склады, независимо от того, есть на них остатки товаров, или нет.
В версии 8.0 для решения такой задачи следует использовать параметр "Группировки для значений группировок" методов Выбрать() результата запроса и выборки из результата запроса. Если в качестве этого параметра указать "Все", то будут выбраны все значения этой группировки в запросе. Если же указать конкретную вышестоящую группировку, то будут выбраны все значения группировки для текущих значений указанных вышестоящих группировок.
В качестве примера можно привести отчет по складским остаткам, сгруппированным по фирмам. В таком отчете данные по фирме будут выводиться с новой страницы, причем для каждой фирмы будет сформирован свой состав колонок-складов в зависимости от того, на каких складах есть остатки по этой фирме.
Наряду с описанным выше параметром, для группировок типа Дата существует возможность указать в тексте запроса способ дополнения результата запроса значениями группировки в указанном интервале с заданной периодичностью. Для этого в описании формирования итогов используется ключевое слово ПЕРИОДАМИ.
С помощью такой конструкции можно, например, сформировать отчет о продажах по неделям, в котором будет отражена каждая неделя, независимо от того, были ли продажи в эту неделю, или нет. Вывод в отчет всех периодов может понадобиться также при построении диаграмм, в которых необходимо обеспечить непрерывность отображения периодов.
В качестве примера можно посмотреть отчет "Выручка мастеров" в разделе "Отчет ВыручкаМастеров" на странице 183. [634]


Бухгалтерия: Автоматизация - Система 1С
- Бухгалтерия
- Бухгалтерская отчетность
- Автоматизация бухгалтерии
- Расчет налогов
- Бухгалтерские расчеты
- Бухгалтерский учет
- Бухгалтерия в 1С
- 1С - конфигурации
- 1С версия 7.7
- 1С версия 8.0
- 1С 8.0 программирование