Урок 7 из 8 · 25 мин · обновлено
Встроенный язык и запросы
Основы встроенного языка 1С: переменные, условия, циклы, процедуры и функции, виды модулей, клиент и сервер. Язык запросов — родственник SQL: ВЫБРАТЬ, ИЗ, ГДЕ, параметры и виртуальные таблицы. Запрещаем продавать товар, которого нет на складе.
Язык на русском
Встроенный язык 1С похож на другие языки программирования, только ключевые слова русские. Есть и английские синонимы — If, Then, EndIf, — но в российских компаниях почти везде пишут по-русски.
// Переменные создаются присваиванием
Цена = 1500;
Количество = 3;
Сумма = Цена * Количество;
// Условие
Если Сумма > 10000 Тогда
Скидка = 5;
ИначеЕсли Сумма > 3000 Тогда
Скидка = 3;
Иначе
Скидка = 0;
КонецЕсли;
// Цикл со счётчиком
Для Номер = 1 По 3 Цикл
Сообщить("Строка " + Номер);
КонецЦикла;
Сообщить("Сумма со скидкой: " + Сумма * (100 - Скидка) / 100);
Каждая команда заканчивается точкой с запятой. Комментарии начинаются с //. Сообщить показывает текст пользователю — удобно для первых опытов.
Код собирают в процедуры и функции. Функция возвращает значение:
Функция СуммаСоСкидкой(Сумма, Скидка)
Возврат Сумма * (100 - Скидка) / 100;
КонецФункции
Цикл Для Каждого вы уже видели в коде проведения: он перебирает строки табличной части, элементы массива или результат запроса.
Где живёт код
Код в 1С не лежит в отдельных файлах, а привязан к объектам — в модулях:
- модуль объекта — поведение конкретного документа или элемента справочника: проведение, проверки при записи;
- модуль формы — реакция на действия пользователя в окне: нажал кнопку, выбрал товар;
- модуль менеджера — действия с объектами одного вида в целом: например, печать;
- общие модули — процедуры, которые нужны в разных местах конфигурации.
Клиент и сервер
Программа на 1С работает в двух местах: клиент — окна на компьютере пользователя, сервер — где лежат данные. В модуле формы перед процедурой пишут, где она выполняется:
&НаКлиенте
Процедура ПересчитатьСумму(Команда)
ПересчитатьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПересчитатьНаСервере()
// здесь можно читать данные из базы
КонецПроцедуры
Правило: данные из базы читают на сервере, а вызовы с клиента на сервер делают пореже — каждый занимает время. Новичкам это кажется сложным, но привыкают быстро.
Язык запросов
Получать данные из базы удобнее всего запросами. Язык запросов — родственник SQL, только на русском:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Товар КАК Товар,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(, Склад = &Склад) КАК Остатки
|УПОРЯДОЧИТЬ ПО
| Товар";
Запрос.УстановитьПараметр("Склад", Склад);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("" + Выборка.Товар + ": " + Выборка.Остаток);
КонецЦикла;
Что здесь происходит:
ВЫБРАТЬ … ИЗ … УПОРЯДОЧИТЬ ПО— какSELECT … FROM … ORDER BYв SQL;ОстаткиТоваров.Остатки— виртуальная таблица остатков из прошлого урока; в скобках её параметры: дата не указана — значит, текущие остатки, и отбор по складу;&Склад— параметр: значение передаётся отдельно методомУстановитьПараметр;- текст запроса многострочный: каждая новая строка начинается с
|; Пока Выборка.Следующий() Циклперебирает строки результата.
Ещё одна особенность — обращение через точку: Остатки.Товар.Артикул достанет артикул товара без явного соединения таблиц. Удобно, но в больших запросах этим не злоупотребляют: каждая точка — скрытое соединение.
Писать запросы вручную с нуля не нужно: в Конфигураторе есть конструктор запроса, где таблицы и поля выбирают мышкой. Но читать и править текст запроса разработчик должен уверенно. Если вы проходили курс «SQL с нуля», половина языка запросов вам уже знакома.
Попробуйте сами. Сейчас документ «Расход товара» проводится, даже если товара на складе нет, и остаток уходит в минус. Допишите проведение: после записи движений проверьте запросом, нет ли отрицательных остатков на складе документа, и если есть — сообщите, какого товара не хватает, и отмените проведение.
Решение
В модуле объекта документа РасходТовара после цикла с движениями добавьте:
// записываем движения сейчас, чтобы проверить остатки с их учётом
Движения.ОстаткиТоваров.Записать();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Товар КАК Товар,
| Остатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(, Склад = &Склад) КАК Остатки
|ГДЕ
| Остатки.КоличествоОстаток < 0";
Запрос.УстановитьПараметр("Склад", Склад);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Не хватает товара «" + Выборка.Товар + "»: " + (-Выборка.Остаток) + " шт.");
Отказ = Истина;
КонецЦикла;
Проверьте: проведите расход больше остатка — документ не проведётся, а внизу окна появится сообщение. При отказе платформа отменит и уже записанные движения.
Это упрощённая проверка: она смотрит на текущие остатки, а не на остатки в момент документа. В настоящих конфигурациях учитывают и дату документа, и одновременную работу нескольких пользователей — этому учат в полноценных курсах.
Мини-тест: проверьте себя
Закрепите урок: несколько вопросов, разбор ответов — в конце.
-
Что выведет код: Сумма = 0; Для Н = 1 По 3 Цикл Сумма = Сумма + Н; КонецЦикла; Сообщить(Сумма);
Цикл проходит Н = 1, 2, 3 и прибавляет каждое к сумме: 1 + 2 + 3 = 6.
-
Зачем в запросе писать ГДЕ Остатки.Склад = &Склад, а не вставлять название склада в текст?
Параметры — правильный способ передать значения в запрос. Склеивание текста ломается на кавычках и открывает дорогу ошибкам.
-
Чем язык запросов 1С отличается от SQL?
Основа та же, что у SQL, но язык запросов знает объекты 1С: виртуальные таблицы остатков и оборотов, ссылки и их поля.
-
В каком модуле лучше писать код, который нужен в нескольких документах сразу?
Общие модули хранят процедуры, которые вызывают из разных мест конфигурации. Код пишется один раз.