Создание и проведение документа
Новый документ
в системе 1С можно ввести различными методами:
Интерактивно - этот способ можно реализовать по-разному.
1. Вариант первый. Пользователь выбирает Пункт меню Документы и в подменю щелкает по названию необходимого документа. Что происходит дальше. Документу присваивается номер, устанавливаются дата, начинается обработка операторов предопределеннной процедуры модуля формы документа ВводНового(), после чего открывается экранная форма с вызовом процедуры ПриОткрытии(). Новый документ создается в памяти, а для того, чтобы он был записан в базу, необходимо нажать кнопку Записать.
2. Разновидностью этого варианта является создание документа из открытой формы журнала документов. Второй вариант предполагает создание нового документа путем копирования такого же. При копировании документу присваивается новый номер, а все реквизиты заполняются данными из скопированного документа. Вот почему, если в процедуре ВводНового() вы заполняете некоторые реквизиты при создании нового документа, то необходимо в начале этой процедуры задать проверку факта копирования, для того, чтобы не сбить значения реквизитов.
3. При третьем варианте новый документ создается на основании существующего документа другого вида. В такой ситуации вместо процедуры ВводНового() будет вызвана процедура ВводНаОсновании(). В ней нужно описать, какие реквизиты нового документа будут заполнены значениями из документа-основания. Естественно, что заполняемые реквизиты нового документа должны иметь тот же тип, что и соответствующие реквизиты-источники. Пример заполнения расходной накладной на основании счета:
Процедура ВводНаОсновании(ДокОсн)
РасчетныйСчет = ДокОсн.РасчетныйСчет;
МестоХранения = глЗначениеПоУмолчанию("ОсновнойСклад");
Контрагент = ДокОсн.Контрагент;
Договор = ДокОсн.Договор;
ВариантРасчетаНалогов = ДокОсн.ВариантРасчетаНалогов;ДокОсн.ВыбратьСтроки();
Пока ДокОсн.ПолучитьСтроку() = 1 ЦиклНоваяСтрока();
Товар = ДокОсн.Товар;
Количество = ДокОсн.Количество;
Цена = ДокОсн.Цена;
Сумма = ДокОсн.Сумма;
НДС = ДокОсн.НДС;
Всего = ДокОсн.Всего;КонецЦикла;
КонецПроцедуры
При вызове процедуры
происходит установка значений некоторых полей и флажков накладной
значениями из счета. Сначала мы заполнили реквизиты шапки, а затем
организовали цикл считывания строк табличной части счета операторами
ВыбратьСтроки() и ПолучитьСтроку(). В этом же цикле на каждую строку
основания вводится и заполняется новая строка накладной (команда
НоваяСтрока()).
Доступ к реквизитам счета осуществляется через переменную ДокОсн,
которая является параметром процедуры. Как мы помним (см. описание
предопределенных процедур модуля формы документа), в неё передается
контекст документа-основания.
4. Программный
способ - для него в языке 1С предусмотрены специальные команды.
Можно при записи расходной накладной сформировать документ СчетФактура:
СФ = СоздатьОбъект("Документ.СчетФактура");
СФ.Новый();
СФ.ВариантОтправки = 1;
СФ.НомерДок = НомерДок; // Счет-фактура будет с тем же номером и
датой, что и
СФ.ДатаДок = ДатаДок; // накладная. Но так можно и не делать, есть
же автонумерация
СФ.Контрагент=Контрагент;
СФ.Грузополучатель=Контрагент;
ВыбратьСтроки();
Пока ПолучитьСтроку()=1 Цикл
СФ.НоваяСтрока();
// Реквизит "Товар" док-та СчетФактура имеет неопределенный тип
СФ.НазначитьТип("Товар", "Справочник.Номенклатура");
СФ.Товар=Товар;
Если ПустоеЗначение(Товар.СтранаПроисхождения) = 0 Тогда// а это обращение к реквизитам справочника "Номенклатура"
СФ.СтранаПроисхождения = Товар.СтранаПроисхождения;Иначе
СФ.СтранаПроисхождения = "Россия";
КонецЕсли;
СФ.Количество=Количество;
СФ.Цена=Цена;
СФ.Сумма=Сумма;
СФ.НДС=НДС;
СФ.Всего=Сумма+НДС;
// Здесь накладная становится основанием счета-фактуры через специальный реквизит
СФ.ДокументОснование = ТекущийДокумент();
КонецЦикла;
СФ.Записать();
СФ.Провести(0, "Программно");
Обратите внимание,
что сначала создается документ как объект, а затем вводится новый
документ. Последующие действия похожи на действия при вводе на основании.
Не забудьте, если вы создаете или изменяете документ программно,
его необходимо записывать. И пожалуйста, не пытайтесь использовать
метод Провести() в теле предопределенной процедуры ОбработкаПроведения()
модуля документа!
Оператор Провести() в приведенном выше примере выполнит проведение документа. При проведении будет вызвана предопределенная процедура ОбработкаПроведения(). Вторым реквизитом передается в обработку проведения значение ("Программно"), по которому процедура ОбработкаПроведения() узнает о программном выполнении проведения. Это может быть простая строка или число, её задача - только обозначить факт программного проведения.
Если вы работаете с уже существующим документом, то метод Провести() перепроведет документ. А с помощью метода Проведен() можно узнать, проведен ли какой-либо документ:
Если Док.Проведен() > 0 Тогда
Сообщить( "Документ № " + Док.НомерДок + " проведен");
…………… // Какие-то действия, которые нужно сделать с проведенным документом
КонецЕсли;
О создании операций и проводок при проведении документов читай раздел Операции и проводки главы Бухгалтерия.
Транзакции
При создании множества документов или для ускорения работы можно заключить цикл в транзакцию. При этом реальная запись документов произойдет только по команде ЗафиксироватьТранзакцию(). На время транзакции блокируется для других пользователей запись и проведение документов.
СписаниеМатериалов
= СоздатьОбъект("Документ.ТребованиеНакладаная");
НачатьТранзакцию();
Для Ном = 1 По 100 Цикл
СписаниеМатериалов.Новый();
…………………
// Заполнение реквизитов
СписаниеМатериалов.Записать();
СписаниеМатериалов.Провести();
КонецЦикла;
ЗафиксироватьТранзакцию();
Напомню, что
предопределенная процедура ОбработкаПроведения() самостоятельно
открывает транзакцию для проведения, однако есть маленькая особенность
документа, созданного функцией СоздатьОбъект(). Дело в том, что
про программном проведении созданных документов не выполняется автоматическая
предварительная запись, и для того, чтобы при любых сбоях и ошибках
сохранялась согласованность данных документа и его движений (операций)
следует объединять запись и проведение документа в одну транзакцию.
Установка периодического реквизита справочника при проведении документа
Простым примером такого действия является установка нового оклада сотруднику в справочнике Сотрудники при проведении, например, штатного расписания.
Процедура ОбработкаПроведения()
УстановитьРеквизитСправочника (Сотрудник, "Оклад", НовыйОклад, ДатаДок);
КонецПроцедуры
Здесь Сотрудник
- значение реквизита документа типа "Справочник", через
него в справочнике позиционируется нужный элемент, а "Оклад"
- периодический реквизит соответствующего элемента. Этот оператор
можно использовать только в предопределенной процедуре ОбработкаПроведения().
Теперь при просмотре истории периодического реквизита вы увидите
кроме самого значения, ещё и дату установки (соответствует дате
документа), и документ, который установил данное значение.
Номер документа
При интерактивном или программном создании нового документа ему автоматически присваивается новый уникальный номер. Его можно получить или установить какой-нибудь другой с помощью атрибута НомерДок:
Док = СоздатьОбъект("Документ.Счет");
Док.Новый();
Сообщить("Документу был автоматически присвоен № " + Док.НомерДок);
Док.НомерДок = "000013";
Сообщить("Установлен новый № " + "000013");
Если вы используете распределенную базу или желаете, чтобы документы обозначали пользователя, который их создал, полезно пользоваться префиксами - одним или двумя символами, которые подставляются перед собственно номером документа, но при этом "входят" в номер. Не забывайте, что префикс должен быть строковым ("Сч-" или "01", или "1-"), а в свойствах документа должен быть установлен строковый тип номера.
Док = СоздатьОбъект("Документ.Счет");
ПрефДок = Лев(ИмяПользователя(),2);
Док.ПрефиксНомера(ПрефДок + "-");
Док.Новый();
Этот метод изменяет префикс по умолчанию, или возвращает текущее значение префикса, если использовать метод без параметра. А вот другая возможность:
Док = СоздатьОбъект("Документ.Счет");
ПрефДок = Лев(ИмяПользователя(),2);
Док.Новый();
Док.УстановитьНовыйНомер(ПрефДок + "-"); // такая
нумерация работает очень корректно
В отличие от
предыдущего этот метод устанавливает (а точнее переустанавливает
введенный по умолчанию при исполнении метода Новый()) новый номер
с указанным префиксом.
Нумератор представляет собой объект метаданных, описывающий правила нумерации документов: тип и длина номера документа, его периодичность, необходимость контроля уникальности. Основное назначение нумератора - обеспечить возможность сквозной нумерации документов разного вида, для чего таким документам назначается одинаковый нумератор.
Периодичность. Этот реквизит устанавливает 2 важные характеристики нумератора: пределы контроля уникальности номеров документов и период повторяемости номеров. Если включен признак контроля уникальности номеров (см. ниже), "Периодичность" устанавливает, в каких пределах осуществлять этот контроль. Например, если установлено "В пределах дня", то уникальность номеров документов будет контролироваться в пределах суток: на следующие сутки номера документов могут повторяться. При включенной автоматической нумерации система будет присваивать очередной порядковый номер каждому новому документу. После завершения периода, установленного в реквизите "Периодичность", нумерация документов начнется с 1.
Длина. Устанавливает максимальную длину номера документа. Не размахивайтесь без нужды, "длинный" номер снижает производительность работы.
Тип. Группа "Тип" позволяет выбрать тип значения для номера документа - числовой или текстовый. Выбор текстового типа номера бывает полезен, когда используется сложная система нумерации документов, и номер документа может включать, помимо цифр, также буквы и символы-разделители.
Контроль
уникальности. Если эта опция включена, то при вводе нового документа
его номер проверяется на уникальность в пределах, установленных
в реквизите "Периодичность".
Дата, время и позиция документа
Дата создания (или записи) - обязательный атрибут любого документа. Через него можно получить или назначить дату, с которой будет записан документ:
Док = СоздатьОбъект("Документ.РасходнаяНакладная");
Док.Новый();
Если Док.ДатаДок = '01.01.02' Тогда
..........Сообщить("С Новым Годом!");
КонецЕсли;
Кроме даты, позиция документа обозначается временем. С ним можно поступать так:
Часы = 0;
Минуты = 0;
Секунды = 0;
Док.ПолучитьВремя(Часы, Минуты, Секунды); // Прочтем время
Если Часы > 21 Тогда
Предупреждение("Хватит работать по ночам!
|Документ будет помещен в конец дня");
Док.АвтоВремяКонецДня(); // документ запишется на 10 сек позже последнего
ИначеЕсли Часы < 8 Тогда
Предупреждение("Никто не оценит!
|Документ будет записан в начало дня");
Док.АвтоВремяНачалоДня();// документ запишется на 10 сек раньше первого
ИначеЕсли Вопрос("Записать документ с текущим временем?", 4) = 7 Тогда // ответ "Нет"
ВвестиЧисло(ЧасУст, "Укажите час, с которым будет записан данный документ",2,0);
Док.УстановитьВремя(ЧасУст, Минуты, Секунды); // запишется с этим временем
Иначе
Док.АвтоВремяТекущее(); // документ запишется с текущим временем
КонецЕсли;
В крупных многопользовательских системах часто возникает ситуации, когда новые документы записываются почти одновременно, внутри одной секунды. Но все равно не возникает никаких накладок, т.к. документы разделяются внутри секунды с помощью позиции документа. Она представляет собой специальное 32-х символьное выражение, которое можно прочитать с помощью специального метода:
ПозДокумента = Док.ПолучитьПозицию(); // только чтение !
Позиция имеется только у записанного документа.
Точка актуальности (ТА)
Этот страшный зверь - точка актуальности
Точка актуальности (ТА) - это "текущий" момент времени в хронологии документов, на который регистры оперативного учета содержат текущие значения своих ресурсов. Это значит, что когда вы обращаетесь к регистрам, информация из них выдается именно на момент, куда установлена точка актуальности. Если вам нужны итоги на другой момент, должен запускаться временный расчет. ТА помогает системе определить текущее наличие средств, соответствующее, например, реальному количеству товаров на складе. Все документа, проведенные до ТА, считаются уже произошедшими хозяйственными операциями, если документ проведен после ТА, он не будет учтен при определении остатков регистра. Такая ситуация редка, т.к. документы оперативного учета после проведении автоматически устанавливают ТА на время своего проведения (режим управления ТА при проведении документов настраивается на закладке Оперативный учет окна Параметры меню Сервис режима 1С: Предприятие).
Предопределенная
процедура |
Описание |
ПолучитьТА() | Возвращает строку, содержащую дату и время ТА. Примерный вид результата этой функции: 09.04.02 08:30:12 Отдельно дату или время ТА можно с помощью функций ПолучитьДатуТА() и ПолучитьВремяТА() |
ПолучитьПозициюТА() | Позиция ТА имеет такое же представление, как и позиция документа (см. выше). Посмотреть ее можно с помощью данной функции. |
ПолучитьДокументТА() | Можно получить документ, который стоит на точке актуальности. Функция возвратит ссылку на этот документ:ПослДок = ПолучитьДокументТА();Сообщить("Последний документ имеет номер " + ПослДок.НомерДок); |
УстановитьТАна(Полож) | Устанавливает ТА на начало даты или перед документом. Полож - переменная типа "Дата" или ссылка на документ. Метод можно использовать только в монопольном режиме. |
УстановитьТАпо(Полож) | Метод похож на предыдущий, только устанавливает ТА на конец даты или после документа. |
АвтоВремяПослеТА() | Метод документа изменяет предыдущую (в том числе и пользовательскую) установку автоматического времени нового документа так, чтобы он записывался со временем после ТА. |
ПроводитьПослеТА(ФлагНеПров, ФлагПров) | Метод модуля формы документа изменяет предыдущую (в том числе и пользовательскую) установку проведения и перепроведения документа относительно ТА. Если флаги имеют значение "-1", документ будет проводиться (или перепроводиться) всегда задним числом (до ТА). Флаг с единицей установит режим проведения (перепроведения) в реальном потоке времени (т.е. после ТА). Для флага ФлагНеПров имеется дополнительное нулевое значение. В этом случае при проведении режима будет выбирать пользователь. |
ИтогиАктуальны() | Метод предопределенной процедуры ОбработкаПроведения() модуля документа определяет актуальность итогов на момент проведения документа. Если метод возвратил значение "1", можно обращаться к текущим итогам с помощью методов объекта "Регистр" или с помощью запроса без указания конечной границы. Если метод возвратил "0", то необходимо запускать временный расчет регистра. |
Последовательности
Последовательности документов - специальный механизм системы 1С, который позволяет поддерживать правильность итогов и данных проводок документов. Если документы при проведении использует данные бухгалтерских итогов или итогов регистров, то в случае, если задним числом каким-то образом меняются итоги, необходимо автоматически перепроводить все документы, которые использовали измененные итоги. Вот надзором за этим делом и занимаются Последовательности. При описании последовательности в конфигураторе, описывается, какие изменения регистров или бухгалтерских итогов по счетам будут влиять на последовательность, и какие документы входят в эту последовательность (это могут быть документы разного вида). Граница последовательности (ГП) - позиция последнего проведенного с "правильными" итогами документа. Если какие-то итоги изменяются задним числом, граница последовательности отодвигается назад на последний документ, при проведении которого использовались последние "нетронутые" итоги, а все документы, проведенные на основе изменившихся данных итогов, окажутся после границы последовательности. Восстановление последовательности - значит перепроведение всех документов, начиная от границы последовательности, заканчивая точкой актуальности или рабочей датой. Для восстановления последовательности в пользовательском режиме необходимо вызвать пункт Проведение документов… меню Операции.
Методы последовательностей записываются через точку после полного имени последовательности:
Последовательность.УчетТоваров.ПринадлежитПоследовательности(ТекДокумент);
Здесь "УчетТоваров" - имя последовательности, заданной
в конфигурации.
Программные методы последовательностей
Метод |
Описание |
ПринадлежитПоследовательности(Докум) | Определяет, принадлежит ли документ (или вид документа) данной последовательности. Возвращает "1", если принадлежит, "0" - если нет. |
ПолучитьАтрибут(Имя) | Получить значение последовательности по строке с именем последовательности. Обычно применяется для передачи контекста данной последовательности в переменную. |
ПолучитьПозицию(),
ПолучитьДокумент() |
Схожие между собой методы, первый возвращает строковую позицию границы последовательности (ГП), а второй - ссылку на документ, на котором стоит граница последовательности. |
ПолучитьДату(),
ПолучитьВремя(Ч,М,С) |
Тоже подобные методы, первый возвращает дату, а второй - время границы последовательности (ГП), причем часы, минуты, секунды записываются в разные переменные. |
Сравнить(Докум) | Очень удобный метод для определения положения документа (или даты) относительно ГП. В параметр Докум можно записать дату, документ или позицию документа. Возвращает "-1", если ГП раньше, "0" - если равны, и "1", если ГП позже. |
Установить(Положение) | Принудительно устанавливает ГП в позицию, указанную переменной Положение. В эту переменную можно передавать документ, дату или позицию документа. Осторожнее со сдвигом "вперед", документы до новой точки автоматически не перепроводятся. |
ВыбратьПоПоследовательности(ДатаНач, ДатаКон, Имя) | Открывает выборку документов с ДатаНач по ДатаКон, принадлежащих указанной Последовательности. В качестве дат так же можно использовать документы или их позиции. |
Пример автоматической процедуры восстановления последовательности
// получим
границу последовательности
ПозицияНач = СформироватьПозициюДокумента (Последовательность.ОсновнаяПоследовательность.ПолучитьПозицию(),
1);
Док = СоздатьОбъект("Документ");
// отберем док-ты посл-ти "ОсновнаяПоследовательность"
Док.ВыбратьПоПоследовательности(ПозицияНач, ПолучитьПозициюТА(),
"ОсновнаяПоследовательность");
Пока Док.ПолучитьДокумент() = 1 Цикл
Док.Провести(); // перепроводим документы
Сообщить("Восстановление последовательности "+Док);
КонецЦикла;