Введение
После создания новой версии каркасной конфигурации, для разработки web-приложений на основе http-сервисов OneScript, необходимо было на практике пощупать новые функции и оценить ее применимость для создания бизнес-ориентированых web-приложений. В качестве web-приложения, был выбран сайт небольшого ресторана или кафе. Как показал анализ выдачи гугла, этот вид приложений достаточно распространен в мире и как правило, представляет собой одностраничный сайт, позволяющий рассказать о ресторане, просмотреть меню и забронировать столик. Поскольку в 90% случаев при создании сайтов используются готовые шаблоны, я решил поступить таким-же образом. В готовых решениях Битрикс, был найден подходящий шаблон сайта (RestoPesto). Я обратился в компанию Novastar, которая является автором вышеуказанного решения, с просьбой предоставить мне этот шаблон для миграции на OneScript. Антон Яшин любезно предоставил мне ссылку на исходный шаблон, за что ему огромное спасибо. Как оказалось - это html шаблон на основе библиотеки bootstrap, который не содержит кода php.
О том, что получилось - вы можете прочитать ниже или посмотреть, нажав кнопку "Показать демо".
Системные требования
Компьютер под управлением Windows 7 или более поздней версии.
Установленный .NET Framework версии 4.5.2 или более поздней.
Платформа 1С:Предприятие версии не ниже 8.3.6.1977.
Первый тест
Файловая структура шаблона, после скачивания и распаковки имеет следующий вид:
Для начала экспериментов, создадим новую информационную базу, на основе каркасной конфигурации, как описано в этой статье. В отличие от предыдущей версии, при настройке пула приложений выберем интегрированный пул.
Создадим общий макет, типа ТекстовыйДокумент, и поместим в него содержимое файла index.html.
Также создадим http-сервис, с корневым url – index.os, добавив функцию-обработчик GET-запроса нижеследующего содержания:
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
Тело = ПолучитьОбщийМакет("ГлавнаяСтраница").ПолучитьТекст();
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(Тело);
Возврат Ответ;
КонецФункции
Добавим созданные объекты в подсистему ОбъектыКонфигурацииWebПриложения.
Выгрузим конфигурацию, затем в режиме предприятие создадим и обновим web-приложение.
Скопируем папки изображений, js-скриптов etc. В папку web-приложения, таким образом, что файловая структура web-приложения будет иметь нижеследующий вид:
Для доступа к локальным файловым ресурсам из 1С:Предприятие, для web-публикации 1С:Предприятие создадим правила url rewrite.
Протестируем наше web-приложение и убедимся, что его поведение не отличается от поведения демонстрацинного сайта-источника.
Внешний вид сайта
Рассмотрим более подробно визуальную часть нашего сайта. Как можно увидеть, страница состоит из шапки, которая включает в себя логотип и меню, шесть функциональных разделов, по количеству пунктов меню, а также подвала, содержащего контактную информацию и информацию о рабочих часах.
Шапка
Содержит логотип компании и главное меню для навигации по разделам страницы. Обычно, эта информация остается неизменной.
Приветствие (Welcome)
Фактически - это начальный экран, на который попадает пользователь при открытии сайта. В верхней части находится слайдер изображений, с поясняющим текстом для каждого изображения (Заголовок, Заголовок1, Текст ). В нижней части - текст с кратким описанием заведения, фотография, а также заголовки к данному функциональному разделу. Обычно данная информация постоянна, либо меняется достаточно редко.
Специальные блюда (Specialties)
Данная секция содержит фоновое изображение, заголовки, соответствующие названию секции, а также список специальных блюд. Каждое блюдо содержит изображение, наименование, описание и цену. Обычно, изображение и заголовки меняются нечасто, однако список специальных блюд может меняться до нескольких раз в день. В дальнейшем мы более подробно остановимся на динамическом формировании этого списка.
Меню (Menu)
Данная секция, как и предыдущая, содержит фоновое изображение, заголовки секции, а также список блюд, составляющих меню ресторана. Каждое блюдо имеет изображение, наименование, ингридиенты и цену. Как и в случае со списком специальных блюд, мы полагаем, что фоновое изображение и заголовки меняются редко, в то время как меню может формироваться каждый день. В дальнейшем мы более подробно остановимся на динамическом формировании меню.
Резервирование столика (Reservation)
Данная секция содержит фоновое изображение, заголовки секции, а также форму заказа столика. Информация в этой секции может считаться условно-постоянной.
События ресторана (Events)
Данная секция содержит информацию о предстоящих событиях, которые будут происходить в заведении. Это могут быть дни каких-либо блюд, праздники etc. Также как и предыдущая, данная секция содержит фоновое изображение и заголовки секции, которые можно считать условно-постоянными, а также список событий, который может обновляться достаточно часто. В дальнейшем, мы более подробно остановимся на динамической генерации списка событий.
Контакты (Contact)
Данная секция содержит форму обратной связи. Информацию в этой секции можно считать условно постоянной, однако, необходимо регистрировать обращения клиентов в учетной системе.
Подвал
Данная секция содержит информацию об адресе заведения, а также часах работы. Данная информация может считаться условно-постоянной.
Условно-постоянная информация
Поскольку хранение условно-постоянной информации в информационной базе учетной системы нецелесообразно и в то же время необходимо обеспечить возможность ее настройки, в качестве своеобразного хранилища различных заголовков, ссылок на изображения etc. Используем макет типа ТекстовыйДокумент, где данная информация будет представлена в формате yaml.
Для работы с данными в формате yaml, добавим методом сравнения/объединения (не забывая объединить состав подсистем) в нашу конфигурацию соответствующую библиотеку. Также, заимствуем методом Ctrl+C, Ctrl+V общий модуль, с функциями для работы с шаблонами из этой демонстрационной конфигурации.
Cоздадим общий макет типа ТекстовыйДокумент с именем ОформлениеСайта и поместим его (и общий модуль Макеты) в подсистему ОбъектыКонфигурацииWebПриложения.
Импортируем прочие файлы приложения, затем добавим полученный архив в макет ПрочиеФайлы, а сам макет в подсистему ПрочиеФайлыWebПриложения.
Отредактируем исходный код страницы, разделив его на области вывода, заменим необходимый текст на параметры и внесем параметры в макет ОформлениеСайта. При этом, на данном этапе оставим области, отвечающие за вывод специальных блюд, меню и событий как есть.
Также отредактируем код нашего http-сервиса с учетом вывода областей. При этом содержимое макета ОформлениеСайта и код http-сервиса примут нижеследующий вид:
---
# Файл настроек оформления сайта
Страница:
ИмяСайта: Yep Resto
Описание: Демонстрационный сайт ресторана на OneScript
КлючевыеСлова: http-сервисы OneScript, OneScript, Yep Resto, Yep
ТекстКопирайт: 2017 <a href="/redirect.php?url=aHR0cHM6Ly91aWNvb2tpZXMuY29tLw==">uiCookies:Resto</a>. All Rights Reserved. Images by <a href="/redirect.php?url=aHR0cHM6Ly9ncmFwaGljYnVyZ2VyLmNvbS8=">GraphicBurger</a> & <a href="/redirect.php?url=aHR0cHM6Ly91bnNwbGFzaC5jb20v">Unsplash</a>
# Наименования пунктов главного меню сайта
МенюСайта:
СекцияWelcome: Welcome
СекцияSpecialties: Specialties
СекцияMenu: Menu
СекцияReservation: Reservation
СекцияEvents: Events
СекцияContact: Contact
# Слайды на начальной странице
Слайды:
- Изображение: img/hero_bg_1.jpg
Заголовок1: Welcome
Заголовок2: The Resto
Текст: A free bootstrap website template by <a href="/redirect.php?url=aHR0cHM6Ly91aWNvb2tpZXMuY29t">uicookies.com</a>
- Изображение: img/hero_bg_2.jpg
Заголовок1: Dine
Заголовок2: With Us
Текст: A free bootstrap website template by <a href="/redirect.php?url=aHR0cHM6Ly91aWNvb2tpZXMuY29t">uicookies.com</a>
- Изображение: img/hero_bg_3.jpg
Заголовок1: Enjoy
Заголовок2: With Us
Текст: A free bootstrap website template by <a href="/redirect.php?url=aHR0cHM6Ly91aWNvb2tpZXMuY29t">uicookies.com</a>
# Секция описания ресторана
ОписаниеРесторана:
Заголовок1: Discover
Заголовок2: Our Store
Текст: Voluptatibus quaerat laboriosam fugit non Ut consequatur animi est molestiae enim a voluptate totam natus modi debitis dicta impedit voluptatum quod sapiente illo saepe explicabo quisquam perferendis labore et illum suscipit
ТекстСсылки: About Us
Изображение: img/img_1.jpg
АльтернативныйТекстИзображения: Free Bootstrap Template by uicookies.com
# Шапка секции Специальные блюда
ШапкаСпециальныеБлюда:
Изображение: img/hero_bg_2.jpg
Заголовок1: Discover
Заголовок2: Our Specialties
# Шапка секции Меню ресторана
ШапкаМенюРесторана:
Изображение: img/hero_bg_4.jpg
Заголовок1: Discover
Заголовок2: Our Menu
# Секция резервирования столика
РезервированиеСтолика:
# Шапка секции
Изображение: img/hero_bg_5.jpg
Заголовок1: Booking
Заголовок2: Reserve A Table
# Форма резервирования. Наименования полей формы
КоличествоПерсон: How Many People
ДатаРезервирования: Date
ВремяРезервирования: Time
ИмяКлиента: Name
ИмяКлиентаПодсказка: Your full name
АдресЭлектроннойПочты: Email
АдресЭлектроннойПочтыПодсказка: Your email address
Телефон: Phone
ТелефонПодсказка: Your phone
КнопкаПодтвердить: Submit
# Варианты резервирования столиков
ВариантыРезервирования:
- Наименование: 1 people
- Наименование: 2 people
- Наименование: 3 people
- Наименование: 4+ people
# Шапка секции События ресторана
ШапкаСобытия:
Изображение: img/hero_bg_4.jpg
Заголовок1: Upcoming
Заголовок2: Our Events
# Секция обратная связь
ОбратнаяСвязь:
# Шапка секции
Заголовок1: Contact
Заголовок2: Let's Chat
Текст: Voluptatibus quaerat laboriosam fugit non Ut consequatur animi est molestiae enim a voluptate totam natus modi debitis dicta impedit voluptatum quod sapiente illo saepe explicabo quisquam perferendis labore et illum suscipit
# Форма обратной связи. Наименования полей формы
ИмяКлиента: Your Name
АдресЭлектроннойПочты: Your Email
Сообщение: Your Message
КнопкаОтправить: Send Message
# Секция подвал
Подвал:
ЗаголовокАдрес: Locations
Адрес1: 198 West 21th Street, Suite 721
Адрес2: New York NY 10016
Адрес3: 198 West 21th Street, Suite 721
Адрес4: New York NY 10016
ЗаголовокЧасыРаботы: Open Hours
ЧасыРаботы1: Monday - Thursday
ЧасыРаботы2: 5:30pm - 10:00pm
ЧасыРаботы3: Friday - Sunday
ЧасыРаботы4: 5:30pm - 10:00pm
Текст1: Available for Catering
Текст2: Email or Call Us
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
МакетТекст = ПолучитьОбщийМакет("ГлавнаяСтраница").ПолучитьТекст();
ОформлениеТекст = ПолучитьОбщийМакет("ОформлениеСайта").ПолучитьТекст();
ПроцессорYaml = Обработки.YamlПроцессор.Создать();
ПараметрыОформления = ПроцессорYaml.ПрочитатьYaml(ОформлениеТекст);
ПараметрыОформления["Страница"].Вставить("Слайды", ВывестиСлайды(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("МенюСайта", ВывестиМенюСайта(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("ОписаниеРесторана", ВывестиОписаниеРесторана(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("ШапкаСпециальныеБлюда", ВывестиШапкуСпециальныеБлюда(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("СпециальныеБлюда", ВывестиСписокСпециальныхБлюд(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("ШапкаМенюРесторана", ВывестиШапкуМенюРесторана(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("МенюРесторана", ВывестиМенюРесторана(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("РезервированиеСтолика", ВывестиСекциюРезервированиеСтолика(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("ШапкаСобытия", ВывестиШапкуСобытия(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("События", ВывестиСобытия(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("ОбратнаяСвязь", ВывестиОбратнаяСвязь(МакетТекст, ПараметрыОформления));
ПараметрыОформления["Страница"].Вставить("Подвал", ВывестиПодвал(МакетТекст, ПараметрыОформления));
ОбластьСтраница = Макеты.ПолучитьОбласть(МакетТекст, "<!--Страница-->", "<!--Страница-->");
ТелоСтрока = Макеты.ЗаполнитьПараметры(ОбластьСтраница.Текст, ПараметрыОформления["Страница"]);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(ТелоСтрока);
Возврат Ответ;
КонецФункции
// Формирует html код элементов главного меню сайта
//
Функция ВывестиМенюСайта(МакетТекст, ПараметрыОформления)
ОбластьМеню = Макеты.ПолучитьОбласть(МакетТекст, "<!--МенюСайта-->", "<!--МенюСайта-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьМеню.Текст, ПараметрыОформления["МенюСайта"]);
КонецФункции
// Формирует html-код слайдов для слайдера
//
Функция ВывестиСлайды(МакетТекст, ПараметрыОформления)
ОбластьСлайд = Макеты.ПолучитьОбласть(МакетТекст, "<!--Слайд-->", "<!--Слайд-->");
ТекстСлайды = "";
Для каждого ПараметрыСлайд Из ПараметрыОформления["Слайды"] Цикл
ТекстСлайды = ТекстСлайды + Макеты.ЗаполнитьПараметры(ОбластьСлайд.Текст, ПараметрыСлайд);
КонецЦикла;
Возврат ТекстСлайды;
КонецФункции
// Формирует html-код секции описания ресторана
//
Функция ВывестиОписаниеРесторана(МакетТекст, ПараметрыОформления)
ОбластьОписаниеРесторана = Макеты.ПолучитьОбласть(МакетТекст, "<!--ОписаниеРесторана-->", "<!--ОписаниеРесторана-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьОписаниеРесторана.Текст, ПараметрыОформления["ОписаниеРесторана"]);
КонецФункции
// Формирует html-код шапки секции специальные блюда
//
Функция ВывестиШапкуСпециальныеБлюда(МакетТекст, ПараметрыОформления)
ОбластьШапкаСпециальныеБлюда = Макеты.ПолучитьОбласть(МакетТекст, "<!--ШапкаСпециальныеБлюда-->", "<!--ШапкаСпециальныеБлюда-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьШапкаСпециальныеБлюда.Текст, ПараметрыОформления["ШапкаСпециальныеБлюда"]);
КонецФункции
// Формирует список специальных блюд
//
Функция ВывестиСписокСпециальныхБлюд(МакетТекст, ПараметрыОформления)
ОбластьСпециальныеБлюда = Макеты.ПолучитьОбласть(МакетТекст, "<!--СпециальныеБлюда-->", "<!--СпециальныеБлюда-->");
Возврат ОбластьСпециальныеБлюда.Текст;
КонецФункции
// Формирует html-код шапки секции специальные блюда
//
Функция ВывестиШапкуМенюРесторана(МакетТекст, ПараметрыОформления)
ОбластьШапкаМенюРесторана = Макеты.ПолучитьОбласть(МакетТекст, "<!--ШапкаМенюРесторана-->", "<!--ШапкаМенюРесторана-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьШапкаМенюРесторана.Текст, ПараметрыОформления["ШапкаМенюРесторана"]);
КонецФункции
// Формирует список специальных блюд
//
Функция ВывестиМенюРесторана(МакетТекст, ПараметрыОформления)
ОбластьМенюРесторана = Макеты.ПолучитьОбласть(МакетТекст, "<!--МенюРесторана-->", "<!--МенюРесторана-->");
Возврат ОбластьМенюРесторана.Текст;
КонецФункции
// Формирует секцию Резервирование столика
//
Функция ВывестиСекциюРезервированиеСтолика(МакетТекст, ПараметрыОформления)
ПараметрыОформления["РезервированиеСтолика"].Вставить("ВариантыРезервирования", ВывестиВариантыРезервирования(МакетТекст, ПараметрыОформления));
ОбластьРезервированиеСтолика = Макеты.ПолучитьОбласть(МакетТекст, "<!--РезервированиеСтолика-->", "<!--РезервированиеСтолика-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьРезервированиеСтолика.Текст, ПараметрыОформления["РезервированиеСтолика"]);
КонецФункции
// Формирует список вариантов резервирования
//
Функция ВывестиВариантыРезервирования(МакетТекст, ПараметрыОформления)
ОбластьВариантРезервирования = Макеты.ПолучитьОбласть(МакетТекст, "<!--ВариантРезервирования-->", "<!--ВариантРезервирования-->");
ТекстВариантыРезервирования = "";
Для каждого ПараметрыВариантРезервирования Из ПараметрыОформления["ВариантыРезервирования"] Цикл
ТекстВариантыРезервирования = ТекстВариантыРезервирования + Макеты.ЗаполнитьПараметры(ОбластьВариантРезервирования.Текст, ПараметрыВариантРезервирования);
КонецЦикла;
Возврат ТекстВариантыРезервирования;
КонецФункции
// Формирует шапку секции События
//
Функция ВывестиШапкуСобытия(МакетТекст, ПараметрыОформления)
ОбластьШапкаСобытия = Макеты.ПолучитьОбласть(МакетТекст, "<!--ШапкаСобытия-->", "<!--ШапкаСобытия-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьШапкаСобытия.Текст, ПараметрыОформления["ШапкаСобытия"]);
КонецФункции
// Формирует список событий
//
Функция ВывестиСобытия(МакетТекст, ПараметрыОформления)
ОбластьСобытия = Макеты.ПолучитьОбласть(МакетТекст, "<!--События-->", "<!--События-->");
Возврат ОбластьСобытия.Текст;
КонецФункции
// Формирует html-код секции обратная связь
//
Функция ВывестиОбратнаяСвязь(МакетТекст, ПараметрыОформления)
ОбластьОбратнаяСвязь = Макеты.ПолучитьОбласть(МакетТекст, "<!--ОбратнаяСвязь-->", "<!--ОбратнаяСвязь-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьОбратнаяСвязь.Текст, ПараметрыОформления["ОбратнаяСвязь"]);
КонецФункции
// Формирует html-код секции подвал
//
Функция ВывестиПодвал(МакетТекст, ПараметрыОформления)
ОбластьПодвал = Макеты.ПолучитьОбласть(МакетТекст, "<!--Подвал-->", "<!--Подвал-->");
Возврат Макеты.ЗаполнитьПараметры(ОбластьПодвал.Текст, ПараметрыОформления["Подвал"]);
КонецФункции
Обновим наше web-приложение и протестируем его.
Как можно увидеть, наше web-приложение аналогично оригиналу и имеет возможность изменения оформления.
Вывод списка специальных блюд
Поскольку в учетной системе уже имеется информация о блюдах, предлагаемых рестораном, а также их стоимости, вполне разумным, будет использовать эту информацию на сайте.
Объекты в учетной системе
Для эмуляции соответствующих объектов учетной системы, создадим справочники Номенклатура, ВидыНоменклатуры, а также документ УстановкаЦенНоменклатуры. Эти объекты будут содержать информацию, соответственно о блюдах (Номенклатура), категориях блюд (ВидыНоменклатуры), а также их стоимости (УстановкаЦенНоменклатуры).
Также, создадим нестандартный документ СпециальныеБлюда, который будет содержать список блюд, которые мы будем считать специальными и выводить их в соответствующем разделе сайта.
Объекты на стороне сайта
Для хранения необходимых данных на стороне сайта используем СУБД SQLite. Изображения блюд будем хранить в отдельных файлах.
Для удобства дальнейших действий, создадим некое подобие ER-диаграммы, а также http-сервис, в который впоследствии поместим скрипт создания БД.
Также, в папке web-приложения создадим папку db, где будет расположен файл БД сайта, и добавим разрешения на запись аккаунту, из под которого выполняется наше web-приложение.
Создадим параметры соединения с СУБД
Создадим запрос на создание таблицы category и выполним его.
В процессе выполнения команды возникнет исключительная ситуация, которая обусловлена ошибкой в коде и не влияет на выполнение команды.
Проверим наличие таблицы, выполнив запрос на чтение из этой таблицы.
Сформируем код запроса, скопируем его и вставим в http-сервис создания БД.
Аналогичным образом создадим другие таблицы и сформируем код создания БД, а также саму БД.
При этом код создания нашей БД (обработчик http-сервиса createdb.os) будет выглядеть примерно следующим образом
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
// Соединение
Соединение = Обработки.СоединениеСУБД.Создать();
Соединение.СтрокаСоединения = Обработки.ПараметрыСоединенияСУБД.ПолучитьСтрокуСоединения("TestConn");
Соединение.ТипСУБД = Обработки.ПараметрыСоединенияСУБД.ПолучитьТипСУБД("TestConn");
Соединение.Открыть();
// Удаление таблиц
// Удалить special_product
Попытка
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DROP TABLE special_product
|";
Запрос.ВыполнитьКоманду();
Исключение
КонецПопытки;
// Удалить special_products
Попытка
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DROP TABLE special_products
|";
Запрос.ВыполнитьКоманду();
Исключение
КонецПопытки;
// Удалить price
Попытка
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DROP TABLE product_price
|";
Запрос.ВыполнитьКоманду();
Исключение
КонецПопытки;
// Удалить product
Попытка
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DROP TABLE product
|";
Запрос.ВыполнитьКоманду();
Исключение
КонецПопытки;
// Удалить category
Попытка
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DROP TABLE category
|";
Запрос.ВыполнитьКоманду();
Исключение
КонецПопытки;
// Создание таблиц
// Создание category
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| CREATE TABLE category (
| id nvarchar(50) PRIMARY KEY,
| code nchar(9) NOT NULL,
| name nvarchar(50) NOT NULL,
| deleted boolean NOT NULL
| );
|";
Запрос.ВыполнитьКоманду();
// Создание product
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| CREATE TABLE product (
| id nvarchar(50) PRIMARY KEY,
| code nchar(9) NOT NULL,
| name nvarchar(100) NOT NULL,
| descr nvarchar(150) NOT NULL,
| category_id nvarchar(50) NOT NULL,
| fext nvarchar(4) NOT NULL,
| deleted boolean NOT NULL
| );
|";
Запрос.ВыполнитьКоманду();
// Создание product_price
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| CREATE TABLE product_price (
| id nvarchar(50) NOT NULL,
| from_date datetime NOT NULL,
| product_id nvarchar(50) NOT NULL,
| price decimal(10,2) NOT NULL
| );
|";
Запрос.ВыполнитьКоманду();
// Создание special_products
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| CREATE TABLE special_products (
| id nvarchar(50) PRIMARY KEY,
| number nchar(9) NOT NULL,
| from_date datetime NOT NULL
| );
|";
Запрос.ВыполнитьКоманду();
// Создание special_product
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| CREATE TABLE special_product (
| id nvarchar(50) REFERENCES special_products(id) ON DELETE CASCADE,
| row_index integer NOT NULL,
| product_id nvarchar(50) NOT NULL
| );
|";
Запрос.ВыполнитьКоманду();
Соединение.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Возврат Ответ;
КонецФункции
Данный код будет прекрасно работать в тестовой среде, однако будет непригоден для развертывания в производственной среде. Проблема заключается в том, что при создании строки соединения с СУБД мы указали физический путь к файлу БД. Так как мы заранее не знаем, на каком диске, в какой папке и под управлением какой операционной системы будет выполняться наше приложение, указание прямого физического пути к файлу скорее всего приведет к проблемам. В нашем случае, наиболее универсальным будет метод, использующий пути в стиле web. В нашем случае - это ~/db/, однако провайдеры СУБД не работают с такими форматами путей, поэтому разумным подходом будет хранение пути к СУБД в вышеуказанном формате, с последующим преобразованием в физический путь во время выполнения.
Для решения этой задачи, используем библиотеку HttpMeans, которая не входит в каркасную конфигурацию, поэтому подключим эту библиотеку "вручную".
Для этого, создадим подсистему БиблиотекаСредстваHTTP, общий макет типа ДвоичныеДанные с именем ИсполняемыеФайлыБиблиотекаСредстваHTTP, поместив его в вышеуказанную подсистему, а также в подсистему ИсполняемыеФайлыWebПриложения.
Скачаем последнюю версию библиотек c github'а, удалим из архива все dll, кроме HttpMeans.dll и поместим получившийся архив в макет.
Создадим общий макет типа ТекстовыйДокумент с именем appSettingsHttpMeans и добавим его в подсистемы БиблиотекаСредстваHTTP и СекцияAppSettingsФайлаWebConfig.
В соответствии с документацией, добавим в содержимое макета необходимый ключ, для регистрации библиотеки в OneScript.
Поскольку данная библиотека пока не имеет кросплатформенной реализации, создадим общий модуль ПлатформозависимыеФункции, куда мы будем помещать все платформозависимые функции (в нашем случае - это преобразование виртуального пути в физический), а также модуль СлужебныеФункции, куда мы будем помещать различные вспомогательные функции (в нашем случае - это функция создающая соединение с БД) и поместим их в подсистему ОбъектыКонфигурацииWebПриложения.
Реализуем функцию, возвращающую открытое соединение к БД, примерно следующим образом
// Создает соединение с БД
//
Функция НовыйСоединениеБД() Экспорт
Соединение = Обработки.СоединениеСУБД.Создать();
Соединение.ТипСУБД = Обработки.ПараметрыСоединенияСУБД.ПолучитьТипСУБД("DbConn");
СтрокаСоединения = Обработки.ПараметрыСоединенияСУБД.ПолучитьСтрокуСоединения("DbConn");
ФизическийПуть = ПлатформозависимыеФункции.ПолучитьФизическийПутьИзВиртуального("~/db/") + "localdb.db";
Соединение.СтрокаСоединения = СтрЗаменить(СтрокаСоединения, "{{ПутьКФайлуБД}}", ФизическийПуть);
Соединение.Открыть();
Возврат Соединение;
КонецФункции
А также функцию, преобразующую виртуальный путь в физический
// Получает физический путь файловой системы, соответствующий виртуальному
//
Функция ПолучитьФизическийПутьИзВиртуального(ВиртуальныйПуть) Экспорт
//<1C>
Если СтрНачинаетсяС(ВиртуальныйПуть, "/") Тогда
ФизическийПуть = Константы.КаталогПриложения.Получить() + ВиртуальныйПуть;
ИначеЕсли СтрНачинаетсяС(ВиртуальныйПуть, "~") Тогда
ФизическийПуть = Константы.КаталогПриложения.Получить() + Прав(ВиртуальныйПуть, СтрДлина(ВиртуальныйПуть) - 1);
ИначеЕсли ВиртуальныйПуть = "" Тогда
ФизическийПуть = Константы.КаталогПриложения.Получить();
Иначе
ФизическийПуть = Константы.КаталогПриложения.Получить() + "\" + ВиртуальныйПуть;
КонецЕсли;
Возврат СтрЗаменить(ФизическийПуть, "/", "\");
//<!1C>
//<OneScript>
//СредстваHTTP = Новый СредстваHTTP;
//Возврат СредстваHTTP.ПолучитьФизическийПутьИзВиртуального(ВиртуальныйПуть);
//<!OneScript>
КонецФункции
Создадим новые параметры соединения с СУБД с кодом DbConn, копированием параметров TestConn и заменим физический путь на строку {{ПутьКФайлуБД}}.
Сгенерируем необходимые ключи и вставим их в соответствующие макеты.
В нашем случае - это макеты connectionStringsПоУмолчанию и appSettingsПоУмолчанию.
Также изменим код обработчика http-сервиса createdb таким образом, чтобы он для создания соединения с СУБД использовал функцию ПлатформозависимыеФункции.НовыйСоединениеБД.
В дальнейшем, мы будем использовать ее во всех наших функциях, реализующих работу с БД.
Обмен данными между 1С:Предприятие и сайтом
Для обмена между учетной системой и сайтом используем механизм, аналогичный тому, что использовался в демонстрационной конфигурации интернет-магазина. Суть механизма обмена учетная система->сайт можно представить в виде последовательности нижеследующих действий:
У каждого объекта конфигурации, учавствующего в обмене (в данном случае - это справочники ВидыНоменклатуры, Номенклатура, документы - УстановкаЦенНоменклатуры, а также СпециальныеБлюда) создаются подписки на события ПриЗаписи, ПередУдалением для справочников и ОбработкаПроведения, ОбработкаОтменаПроведения для документов.
При измененении объектов, обработчики подписок формируют данные, необходимые для обмена в формате json и помещают их в очередь изменений.
Элемент очереди изменений представляет собой документ, который содержит признак вида изменений, а также данные об изменяемом объекте в формате json.
Обмен осуществляется по расписанию, с использованием регламентного задания. Обработчик регламентного задания, на основании данных, содержащихся в документах-элементах очереди осуществляет вызов соответствующих http-сервисов на стороне сайта и передает необходимую информацию. В случае успешного завершения операции обновления, соответствующий элемент очереди помечается как выполненный.
В случае неудачи, к примеру временного отсутствия связи с сайтом, попытка обновления будет предпринята при следующем запуске регламентного задания.
Для реализации данного механизма, методом Ctrl+C, Ctrl+V перенесем необходимые объекты в нашу конфигурацию и добавим их в подсистему RestoОбъекты1С.
Создадим общий модуль ОбменССайтом, куда поместим необходимые обработчики подписок на события, а также http-сервисы, которые будут обновлять данные на стороне сайта.
Пример создания обмена с сайтом
В качестве примера, рассмотрим процесс реализации обмена справочника ВидыНоменклатуры.
Создадим подписки на события с именами ОбновитьВидНоменклатурыНаСайте и УдалитьВидНоменклатурыНаСайте.
В качестве источника событий, укажем справочник ВидыНоменклатуры.
Первая подписка будет обрабатывать событие ПриЗаписи, которое возникает при записи нового элемента справочника или обновлении существующего элемента. Вторая подписка будет обрабатывать событие ПередУдалением, которое возникает перед удалением элемента справочника. Код обработчиков подписок представлен ниже:
Процедура ОбновитьВидНоменклатурыНаСайтеПриЗаписи(Источник, Отказ) Экспорт
// Вставить содержимое обработчика.
Док = Документы.ОбновленияДляСайта.СоздатьДокумент();
Док.Дата = ТекущаяДата();
// Заполняем данные
// Обновляем категорию
Док.ВидОбновления = "uc";
Данные = Новый Соответствие;
Идентификатор = Строка(Источник.Ссылка.УникальныйИдентификатор());
Данные.Вставить("id", Идентификатор);
Данные.Вставить("name", Источник.Наименование);
Данные.Вставить("code", Источник.Код);
Данные.Вставить("deleted", Источник.ПометкаУдаления);
Док.ТелоЗапроса = JSON.Записать(Данные);
// Записываем документ
Док.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры
Процедура УдалитьВидНоменклатурыНаСайтеПередУдалением(Источник, Отказ) Экспорт
// Вставить содержимое обработчика.
Док = Документы.ОбновленияДляСайта.СоздатьДокумент();
Док.Дата = ТекущаяДата();
// Заполняем данные
// Обновляем категорию
Док.ВидОбновления = "dc";
Данные = Новый Соответствие;
Идентификатор = Строка(Источник.Ссылка.УникальныйИдентификатор());
Данные.Вставить("id", Идентификатор);
Док.ТелоЗапроса = JSON.Записать(Данные);
// Записываем документ
Док.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры
Как можно увидеть, обработчики создают элементы очереди обновлений и заполняют их необходимыми данными. В дальнейшем, элементы очереди будут использоваться для отправки соответствующих изменений на сайт в обработчике регламентного задания ВыполнитьОбменССайтом. Код обработчика представлен ниже.
// Выполняет обмен с сайтом в один поток
// Обновляет цены, товары, категории на сайте
//
Процедура ВыполнитьОбменССайтом() Экспорт
// Вставить содержимое обработчика.
Запрос = Новый Запрос("ВЫБРАТЬ
| ОбновленияДляСайта.Ссылка
|ИЗ
| Документ.ОбновленияДляСайта КАК ОбновленияДляСайта
|ГДЕ
| ОбновленияДляСайта.ПометкаУдаления = &ПометкаУдаления
| И ОбновленияДляСайта.Проведен = &Проведен
|
|УПОРЯДОЧИТЬ ПО
| ОбновленияДляСайта.Номер");
Запрос.УстановитьПараметр("ПометкаУдаления", Ложь);
Запрос.УстановитьПараметр("Проведен", Ложь);
Выборка = Запрос.Выполнить().Выбрать();
СуффиксСтраниц = Константы.СуффиксСтраницОбмена.Получить();
ОтносительныйURL = Константы.ОтносительныйURLСайта.Получить();
Если СуффиксСтраниц = Неопределено Тогда
СуффиксСтраниц = "";
КонецЕсли;
Соединение = Новый HTTPСоединение(
Константы.ИмяХостаСайта.Получить(), // сервер (хост)
80, // порт, по умолчанию для http используется 80, для https 443
, // пользователь для доступа к серверу (если он есть)
, // пароль для доступа к серверу (если он есть)
, // здесь указывается прокси, если он есть
, // таймаут в секундах, 0 или пусто - не устанавливать
// защищенное соединение, если используется https
);
Пока Выборка.Следующий() Цикл
Запрос = Новый HTTPЗапрос(ОтносительныйURL + Выборка.Ссылка.ВидОбновления + СуффиксСтраниц + ".os");
Запрос.УстановитьТелоИзСтроки(Выборка.Ссылка.ТелоЗапроса);
Результат = Соединение.ОтправитьДляОбработки(Запрос);
Если Не Результат.КодСостояния = 200 Тогда
ВызватьИсключение "Error: " + Строка(Результат.КодСостояния);
КонецЕсли;
Док = Выборка.Ссылка.ПолучитьОбъект();
// Можно просто удалить документ
Док.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокуме