Введение
После создания новой версии каркасной конфигурации, для разработки 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
ТекстКопирайт: 2025 <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: " + Строка(Результат.КодСостояния);
КонецЕсли;
Док = Выборка.Ссылка.ПолучитьОбъект();
// Можно просто удалить документ
Док.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
КонецЦикла;
КонецПроцедуры
Как можно увидеть, суть работы этого обработчика состоит в последовательной отправке POST запросов к соответствующим http-сервисам сайта. Соответственно тело запросов содержит необходимую информацию об изменениях.
Для выполнения обновлений на стороне сайта, создадим http-сервисы uc.os и dc.os, которые будут соответственно создавать новые или обновлять существующие категории, а также удалять категории, которые были удалены в учетной системе.
Для облегчения работы, в консоли работы с СУБД, создадим запрос, который создает новый элемент таблицы category, которая является представлением справочника ВидыНоменклатуры на сайте.
И выполним его.
Для просмотра результатов выполнения — создадим запрос, который получает запись из таблицы категорий, по определенному id
Как можно увидеть, запись с указанными нами параметрами была успешно добавлена в БД.
Для удаления категорий, создадим запрос, который удаляет запись в таблице с определенным Id
Установим значение параметра id таким же как при добавлении и выполним запрос.
Для проверки откроем запрос получения записи по id и выполним его.
Как можно увидеть, запись была успешно удалена.
Создадим обработчики http-сервисов uc.os и dc.os, используя автоматически-генерируемый код ранее созданных запросов.
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
// Проверяем корректность метода запроса
Если Не Запрос.HTTPМетод = "POST" Тогда
Возврат Новый HTTPСервисОтвет(404);
КонецЕсли;
// Получаем данные, необходимые для создания или обновления
СтрокаТело = Запрос.ПолучитьТелоКакСтроку();
Данные = JSON.Прочитать(СтрокаТело);
// Создаем соединение с БД
Соединение = СлужебныеФункции.НовыйСоединениеБД();
// Удаляем существующую запись, если есть
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DELETE FROM category
| WHERE id = @id
|";
Запрос.УстановитьПараметр("id", Данные["id"]);
Запрос.ВыполнитьКоманду();
// Добавляем новую запись
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| INSERT INTO category (id, code, name, deleted)
| VALUES (@id, @code, @name, @deleted)
|";
Запрос.УстановитьПараметр("id", Данные["id"]);
Запрос.УстановитьПараметр("code", Данные["code"]);
Запрос.УстановитьПараметр("name", Данные["name"]);
Запрос.УстановитьПараметр("deleted", Данные["deleted"]);
Запрос.ВыполнитьКоманду();
// Закрываем соединение
Соединение.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Возврат Ответ;
КонецФункции
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
// Проверяем корректность метода
Если Не Запрос.HTTPМетод = "POST" Тогда
Возврат Новый HTTPСервисОтвет(404);
КонецЕсли;
// Получаем данные из тела запроса
СтрокаТело = Запрос.ПолучитьТелоКакСтроку();
Данные = JSON.Прочитать(СтрокаТело);
// Создаем новое соединение
Соединение = СлужебныеФункции.НовыйСоединениеБД();
// Удаляем существующую запись, если есть
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DELETE FROM category
| WHERE id = @id
|";
Запрос.УстановитьПараметр("id", Данные["id"]);
Запрос.ВыполнитьКоманду();
// Закрываем соединение
Соединение.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Возврат Ответ;
КонецФункции
Обновим web-публикацию 1С:Предприятие, добавив созданные http-сервисы.
В режиме предприятия, заполним значения констант ИмяХостаСайта (в нашем случае — localhost), а также ОтносительныйUrlСайта (в нашем случае — /Resto2/hs/).
Создадим элемент справочника ВидыНоменклатуры и через некоторое время посмотрим на очередь обновлений.
Проверим наличие категории на сайте.
Изменим наименование, а также, пометим элемент справочника к удалению.
Вновь просмотрим очередь обновлений и состяние объекта в БД.
Как можно увидеть, изменения в учетной системе успешно реплицируются на сайт.
Удалим элемент справочника и убедимся, что он исчез из БД сайта.
Аналогичным образом запрограммируем обмен для остальных объектов учетной системы и протестируем работоспособность.
Вывод списка
Получение данных
Как вы помните, за список специальных блюд в учетной системе отвечает документ СпециальныеБлюда, а на сайте соответственно таблицы special_products и special_product. Данные объекты однозначно определяют список специальных блюд, который необходимо отображать на сайте, начиная с некоторой даты и времени, которые определяются датой и временем документа. Поскольку в реальной жизни эти списки могут меняться, к тому же мы можем составлять такие списки будующей датой (скажем через неделю у нас начинается акция, которая продлится две недели), для начала необходимо определить документ-список, который действует в настоящий момент времени.
Для тестирования нашего запроса создадим два документа, один будет прошедшей датой, а другой — будующей.
Дождемся завершения репликации данных на сайт и приступим к написанию запроса.
В справочнике запросов создадим группу Специальные блюда, куда будем помещать все запросы, относящиеся к выводу списка специальных блюд. Затем, создадим новый запрос, определяющий идентификатор документа актуального списка.
Поскольку в списке специальных блюд должны быть представлены цены, создадим запрос, который получает актуальные цены номенклатуры. Также как и в предыдущем случае, цены могут меняться со времененем, а также в системе могут быть документы, которые устанавливают цены будующей датой.
Для тестирования запроса, создадим три документа установка цен номенклатуры, один из которых будет будующим числом.
Затем, создадим и протестируем соответствующий запрос
Исходя из визуального представления списка специальных блюд, в нем присутствует информация о наименовании блюда, его описании, изображение, а также актуальная цена.
Создадим и протестируем запрос, возвращающий вышеуказанную информацию для актуального документа-списка, скомбинировав ранее созданные запросы.
Используя генератор кода запроса, создадим в модуле http-сервиса, выводящего главную страницу функцию ПолучитьСписокСпециальныхБлюд, которая будет возвращать таблицу значений, содержащую информацию, необходимую для вывода.
// Получает список специальных блюд для вывода
//
Функция ПолучитьСписокСпециальныхБлюд()
// Определение идентификатора актуального списка
// Соединение
Соединение = СлужебныеФункции.НовыйСоединениеБД();
// Имя переменной: АктуальнаяДата
// Имя параметра: current_date
//
АктуальнаяДата = ТекущаяДата();
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| SELECT t1.id
| FROM special_products AS t1
| INNER JOIN
| (
| SELECT MAX(from_date) AS from_date
| FROM special_products
| WHERE from_date <= @current_date
| ) AS t2
| ON
| t2.from_date = t1.from_date
|";
Запрос.УстановитьПараметр("current_date", АктуальнаяДата);
Результаты = Запрос.ВыполнитьЗапрос().Выгрузить();
Если Результаты.Количество() = 0 Тогда
Возврат Новый ТаблицаЗначений;
КонецЕсли;
// Имя переменной: ИдентификаторАктуальногоСписка
// Имя параметра: list_id
//
ИдентификаторАктуальногоСписка = Результаты[0].id;
// Имя переменной: ПометкаУдаленияПродукт
// Имя параметра: product_deleted
//
ПометкаУдаленияПродукт = Ложь;
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| SELECT sp.row_index AS row_index, p.id AS id, p.fext AS fext, p.name AS name, p.descr AS descr, pr.price AS price
| FROM
| product AS p
| INNER JOIN
| special_product AS sp
| ON
| p.id = sp.product_id
| INNER JOIN
| (
| SELECT t1.product_id AS product_id, t1.price AS price
| FROM
| product_price AS t1
| INNER JOIN
| (
| SELECT product_id, MAX(from_date) as from_date
| FROM
| product_price
| WHERE
| from_date <= @current_date
| GROUP BY product_id
| ) AS t2
| ON
| t1.product_id = t2.product_id
| AND
| t1.from_date = t2.from_date
| ) AS pr
| ON
| sp.product_id = pr.product_id
| WHERE
| p.deleted = @product_deleted
| AND
| sp.id = @list_id
| ORDER BY sp.row_index ASC
|";
Запрос.УстановитьПараметр("current_date", АктуальнаяДата);
Запрос.УстановитьПараметр("list_id", ИдентификаторАктуальногоСписка);
Запрос.УстановитьПараметр("product_deleted", ПометкаУдаленияПродукт);
Результаты = Запрос.ВыполнитьЗапрос().Выгрузить();
Соединение.Закрыть();
Возврат Результаты;
КонецФункции
Отображение на странице
В макете главной страницы, отредактируем область СпециальныеБлюда так, что она примет нижеследующий вид:
<!--ШапкаСпециальныеБлюда-->
<section class="probootstrap-section-bg overlay" style="background-image: url({{Изображение}});" data-stellar-background-ratio="0.5" data-section="specialties">
<div class="container">
<div class="row">
<div class="col-md-12 text-center probootstrap-animate">
<div class="probootstrap-heading">
<h2 class="primary-heading">{{Заголовок1}}</h2>
<h3 class="secondary-heading">{{Заголовок2}}</h3>
</div>
</div>
</div>
</div>
</section>
<!--ШапкаСпециальныеБлюда-->
<!--СпециальныеБлюда-->
<!-- probootstrap-bg-white -->
<section class="probootstrap-section">
<div class="container">
<div class="row">
<div class="probootstrap-cell-retro">
<div class="half">
{{СпециальныеБлюдаСлева}}
</div>
<div class="half">
{{СпециальныеБлюдаСправа}}
</div>
</div>
</div>
</div>
</section>
<!--СпециальныеБлюда-->
<!--СпециальноеБлюдоЧетнаяСтрока-->
<div class="probootstrap-cell probootstrap-animate" data-animate-effect="fadeIn">
<div class="image" style="background-image: url({{Изображение}});"></div>
<div class="text text-center">
<h3>{{Наименование}}</h3>
<p>{{Описание}}</p>
<p class="price">{{Цена}}</p>
</div>
</div>
<!--СпециальноеБлюдоЧетнаяСтрока-->
<!--СпециальноеБлюдоНечетнаяСтрока-->
<div class="probootstrap-cell reverse probootstrap-animate" data-animate-effect="fadeIn">
<div class="image" style="background-image: url({{Изображение}});"></div>
<div class="text text-center">
<h3>{{Наименование}}</h3>
<p>{{Описание}}</p>
<p class="price">{{Цена}}</p>
</div>
</div>
<!--СпециальноеБлюдоНечетнаяСтрока-->
В модуле http-сервиса, отредактируем функцию ВывестиСписокСпециальныхБлюд, в соответствии с внесенными изменениями:
// Формирует список специальных блюд
//
Функция ВывестиСписокСпециальныхБлюд(МакетТекст, ПараметрыОформления)
ОбластьСпециальныеБлюда = Макеты.ПолучитьОбласть(МакетТекст, "<!--СпециальныеБлюда-->", "<!--СпециальныеБлюда-->");
ОбластьСпециальноеБлюдоНечетнаяСтрока = Макеты.ПолучитьОбласть(МакетТекст, "<!--СпециальноеБлюдоНечетнаяСтрока-->", "<!--СпециальноеБлюдоНечетнаяСтрока-->");
ОбластьСпециальноеБлюдоЧетнаяСтрока = Макеты.ПолучитьОбласть(МакетТекст, "<!--СпециальноеБлюдоЧетнаяСтрока-->", "<!--СпециальноеБлюдоЧетнаяСтрока-->");
СписокСпециальныхБлюд = ПолучитьСписокСпециальныхБлюд();
ТекстСтрокиСпециальныеБлюда = "";
ТекстСпециальныеБлюдаСлева = "";
ТекстСпециальныеБлюдаСправа = "";
Индекс = 0;
Для каждого СпециальноеБлюдо Из СписокСпециальныхБлюд Цикл
Параметры = Новый Соответствие;
Параметры.Вставить("Изображение", "img/" + СпециальноеБлюдо.id + СпециальноеБлюдо.fext);
Параметры.Вставить("Наименование", СпециальноеБлюдо.name);
Параметры.Вставить("Описание", СпециальноеБлюдо.descr);
Параметры.Вставить("Цена", СпециальноеБлюдо.price);
Если Индекс % 2 = 0 Тогда
Если Цел(Индекс/2) % 2 = 0 Тогда
ТекстСпециальныеБлюдаСлева = ТекстСпециальныеБлюдаСлева + Макеты.ЗаполнитьПараметры(ОбластьСпециальноеБлюдоЧетнаяСтрока.Текст, Параметры);
Иначе
ТекстСпециальныеБлюдаСлева = ТекстСпециальныеБлюдаСлева + Макеты.ЗаполнитьПараметры(ОбластьСпециальноеБлюдоНечетнаяСтрока.Текст, Параметры);
КонецЕсли;
Иначе
Если Цел(Индекс/2) % 2 = 0 Тогда
ТекстСпециальныеБлюдаСправа = ТекстСпециальныеБлюдаСправа + Макеты.ЗаполнитьПараметры(ОбластьСпециальноеБлюдоЧетнаяСтрока.Текст, Параметры);
Иначе
ТекстСпециальныеБлюдаСправа = ТекстСпециальныеБлюдаСправа + Макеты.ЗаполнитьПараметры(ОбластьСпециальноеБлюдоНечетнаяСтрока.Текст, Параметры);
КонецЕсли;
КонецЕсли;
Индекс = Индекс + 1;
КонецЦикла;
Параметры = Новый Соответствие;
Параметры.Вставить("СпециальныеБлюдаСлева", ТекстСпециальныеБлюдаСлева);
Параметры.Вставить("СпециальныеБлюдаСправа", ТекстСпециальныеБлюдаСправа);
Возврат Макеты.ЗаполнитьПараметры(ОбластьСпециальныеБлюда.Текст, Параметры);
КонецФункции
Обновим конфигурацию и протестируем вывод.
Вывод меню ресторана
Фактически, меню ресторана — это список товаров (блюд), которые ресторан предлагает к продаже. Конечно, этот список может меняться со временем. Также, возможны такие ситуации, когда меню формируется на предстоящий период заранее. Как правило, меню группируется по видам (напитки, первые блюда, закуски etc.). Соответственно при выводе меню на сайте необходимо предусмотреть данную группировку.
Объекты в учетной системе
Для реализации данного функционала, создадим в учетной системе документ — МенюРесторана, содержит список блюд, предлагаемых к продаже. Поскольку функционал данного документа практически идентичен документу СпециальныеБлюда, мы создадим его простым копированием этого документа. В качестве категорий блюд будем использовать справочник ВидыНоменклатуры, созданный нами ранее.
Объекты на стороне сайта
В БД сайта, создадим таблицы product_lists и product_list аналогично тому, как это было сделано для документа СпециальныеБлюда (таблицы special_products и special_product).
Обмен данными между 1С:Предприятие и сайтом
Для организации обмена, создадим подписки обработки проведения и обработки отмены проведения аналогично тому, как это было сделано для документа СпециальныеБлюда. Также, создадим http-сервисы upl и dpl, аналогично тому, как это было сделано для других объектов.
Затем, необходимо опубликовать новые http-сервисы и обновить переопределения Url.
Вывод меню
Для простоты, порядок вывода категорий блюд, будет определяться кодом соответствующих элементов справочника ВидыНоменклатуры.
Получение данных
Получение данных из БД аналогично получению данных списка специальных блюд. Создадим и соответствующий запрос в консоли запросов, а затем перенесем его в функцию ПолучитьМенюРесторана.
// Получает список специальных блюд для вывода
//
Функция ПолучитьМенюРесторана()
// Соединение
Соединение = СлужебныеФункции.НовыйСоединениеБД();
// Имя переменной: АктуальнаяДата
// Имя параметра: current_date
//
АктуальнаяДата = ТекущаяДата();
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| SELECT t1.id
| FROM product_lists AS t1
| INNER JOIN
| (
| SELECT MAX(from_date) AS from_date
| FROM product_lists
| WHERE from_date <= @current_date
| ) AS t2
| ON
| t2.from_date = t1.from_date
|";
Запрос.УстановитьПараметр("current_date", АктуальнаяДата);
Результаты = Запрос.ВыполнитьЗапрос().Выгрузить();
Если Результаты.Количество() = 0 Тогда
Возврат Новый ТаблицаЗначений;
КонецЕсли;
// Имя переменной: ИдентификаторАктуальногоМеню
// Имя параметра: list_id
//
ИдентификаторАктуальногоМеню = Результаты[0].id;
// Имя переменной: ПометкаУдаления
// Имя параметра: is_deleted
//
ПометкаУдаления = Ложь;
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| SELECT c.code AS cat_code, c.name AS cat_name, p.id AS id, p.fext AS fext, p.name AS name, p.descr AS descr, p.ingridients AS ingridients, pr.price AS price
| FROM
| product AS p
| INNER JOIN
| product_list AS pl
| ON
| p.id = pl.product_id
| INNER JOIN
| category AS c
| ON
| c.id = p.category_id
| INNER JOIN
| (
| SELECT t1.product_id AS product_id, t1.price AS price
| FROM
| product_price AS t1
| INNER JOIN
| (
| SELECT product_id, MAX(from_date) as from_date
| FROM
| product_price
| WHERE
| from_date <= @current_date
| GROUP BY product_id
| ) AS t2
| ON
| t1.product_id = t2.product_id
| AND
| t1.from_date = t2.from_date
| ) AS pr
| ON
| pl.product_id = pr.product_id
| WHERE
| p.deleted = @is_deleted
| AND
| c.deleted = @is_deleted
| AND
| pl.id = @list_id
| ORDER BY cat_code, name ASC
|";
Запрос.УстановитьПараметр("current_date", АктуальнаяДата);
Запрос.УстановитьПараметр("list_id", ИдентификаторАктуальногоМеню);
Запрос.УстановитьПараметр("is_deleted", ПометкаУдаления);
Результаты = Запрос.ВыполнитьЗапрос().Выгрузить();
Соединение.Закрыть();
Возврат Результаты;
КонецФункции
Отображение на странице
Преобразуем область МенюРесторана в макете главной страницы таким образом, чтобы он принял нижеследующий вид:
<!--ШапкаМенюРесторана-->
<section class="probootstrap-section-bg overlay" style="background-image: url({{Изображение}});" data-stellar-background-ratio="0.5" data-section="menu">
<div class="container">
<div class="row">
<div class="col-md-12 text-center probootstrap-animate">
<div class="probootstrap-heading">
<h2 class="primary-heading">{{Заголовок1}}</h2>
<h3 class="secondary-heading">{{Заголовок2}}</h3>
</div>
</div>
</div>
</div>
</section>
<!--ШапкаМенюРесторана-->
<!--МенюРесторана-->
<section class="probootstrap-section probootstrap-bg-white">
<div class="container">
<div class="row">
{{КатегорииМеню}}
</div>
</div>
</section>
<!--МенюРесторана-->
<!--КатегорияМеню-->
<div class="col-md-12 text-center probootstrap-animate">
<div class="probootstrap-heading">
<h2 class="primary-heading">{{НаименованиеКатегории}}</h2>
</div>
</div>
<div class="col-md-6">
<ul class="menus">
{{ЭлементыМенюСлева}}
</ul>
</div>
<div class="col-md-6">
<ul class="menus">
{{ЭлементыМенюСправа}}
</ul>
</div>
<!--КатегорияМеню-->
<!--ЭлементМеню-->
<li>
<figure class="image"><img src="{{Изображение}}" alt="{{Наименование}}" style="width: 100%"></figure>
<div class="text">
<span class="price">{{Цена}}</span>
<h3>{{Наименование}}</h3>
<p>{{Ингридиенты}}</p>
</div>
</li>
<!--ЭлементМеню-->
Обновим конфигурацию, опубликуем вновь созданные http-сервисы, создадим несколько видов номенклатуры и распределим ранее созданные товары между ними. Затем, протестируем сделанные изменения. Меню ресторана будет отображаться примерно следующим образом:
Заказ столика
Секция заказ столика представляет собой форму ввода, в которую клиент вводит информацию, необходимую для заказа и нажимает кнопку подтверждения заказа. На основании этих данных в учетной системе должен быть создан предварительный заказ, на основании которого менеджер ресторана связывается с клиентом, уточняет детали и производит резервирование.
Схема обмена данными
Поскольку возможно наш сайт будет находиться на хостинге, а учетная система в офисе ресторана, возможны случаи перебоев со связью, между рестораном и сайтом. Поэтому мы будем сохранять заявки, созданные клиентами непосредственно на сайте. Также, с целью экономии лицензий и упрощения инфраструктуры мы не будем публиковать какие-либо сервисы учетной системы во внешний мир. Учетная система будет периодически (при помощи регламентного задания) обращаться к сайту и получать новые заявки. Таким образом, алгоритм обмена заявками на бронирования будет примерно следующим:
Клиент заполняет данные формы и нажимает кнопку подтверждения заявки.
Заявка сохраняется в локальной БД сайта.
Клиент получает сообщение о том, что его заявка принята.
Учетная система запрашивает информацию о заявках и формирует соответствующие документы.
После того, как документы созданы, учетная система сообщает сайту информацию о заявках, которые можно удалить из локальной БД сайта.
Соответствующий сервис сайта удаляет заявки, которые уже есть в учетной системе.
Создание заказа на основании данных web-формы
В исходном шаблоне, передача данных введенных клиентом осуществляется посредством отпраки post запроса с данными формы. Данный метод является стандартным и достаточно простым, однако при его использовании страница будет перерисована заново. Также, будут некоторые неудобства, связанные с выводом сообщения об успешном или неуспешном создании заявки. В нашем случае, при нажатии кнопки подтверждения мы будем формировать ajax запрос к http-сервису сайта, который будет создавать заявку в локальной БД сайта и возвращать результат этой операции. После выполнения запроса, пользователю будет выведено диалоговое окно с соответствующим сообщением. В серьезных проектах, данный функционал должны реализовывать разработчики frontend части, а мы должны пердоставить соответствующие http-сервисы, однако поскольку таких разработчиков под рукой не оказалось — я позаимствовал идею и основу кода у коллег из Novastar.
Отредактируем шаблон нашей страницы нижеследующим образом:
Создадим блок, соответствующий диалоговому окну
<div id="reservationModal" class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="icon-cross"></i></button>
<h4 class="modal-title">
<center></center>
</h4>
</div>
<div class="modal-body"></div>
<div class="modal-footer">
<center>
<button type="button" class="btn btn-primary" data-dismiss="modal">{{ТекстКнопкиЗакрыть}}</button>
</center>
</div>
</div>
</div>
</div>
Подключим jQuery и добавим обработчик нажатия кнопки подтверждения заказа, который будет отправлять запрос с данными формы в формате JSON и выводиить соответствующее диалоговое окно.
<script src="https://cdnjs.cloudflare.com/ajax/libs/smoothscroll/1.4.4/SmoothScroll.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.matchHeight/0.7.2/jquery.matchHeight-min.js"></script>
<script>
$(document).ready(function () {
$('.matchheight').matchHeight();
$('#reservation').submit(function (e) {
var fd = {
people: $('#people').val(),
name: $('#name').val(),
date: $('#date').val(),
time: $('#time').val(),
email: $('#email').val(),
phone: $('#phone').val()
};
var myJSON = JSON.stringify(fd);
e.preventDefault();
$.ajax({
url: 'co.os',
type: 'POST',
dataType: "json",
data: myJSON,
success: function (data) {
if (!data.errorstatus) {
$('.modal-body').html("{{ТекстЗаявкаУспешноСозданаДетали}}");
$('.modal-title center').text("{{ТекстЗаявкаУспешноСоздана}}");
} else {
$('.modal-body').html("{{ТекстЗаявкаНеСозданаДетали}}");
$('.modal-title center').text("{{ТекстЗаявкаНеСоздана}}");
}
$("#reservationModal").modal('show');
},
error: function() {
$('.modal-title center').text("{{ТекстЗаявкаНеСоздана}}");
$('.modal-body').html("{{ТекстЗаявкаНеСозданаДетали}}");
$("#reservationModal").modal('show');
}
});
});
$('#feedback').submit(function (e) {
var fd = {
name: $('#c_name').val(),
email: $('#c_email').val(),
message: $('#c_message').val()
};
var myJSON = JSON.stringify(fd);
e.preventDefault();
$.ajax({
url: 'cf.os',
type: 'POST',
dataType: "json",
data: myJSON,
success: function (data) {
if (!data.errorstatus) {
$('.modal-title center').text("{{ТекстОбращениеУспешноСоздано}}");
$('.modal-body').html("{{ТекстОбращениеУспешноСозданоДетали}}");
} else {
$('.modal-title center').text("{{ТекстОбращениеНеСоздано}}");
$('.modal-body').html("{{ТекстОбращениеНеСозданоДетали}}");
}
$("#reservationModal").modal('show');
},
error: function() {
$('.modal-title center').text("{{ТекстОбращениеНеСоздано}}");
$('.modal-body').html("{{ТекстОбращениеНеСозданоДетали}}");
$("#reservationModal").modal('show');
}
});
});
});
</script>
Объекты на сайте
При помощи консоли запросов, создадим в БД таблицу order, которая будет отвечать за хранение заявок на резервирование.
Объекты в учетной системе
Для реализации данного функционала создадим документ ЗаявкаБронирования, который будет содержать информацию, введенную клиентом на сайте, а также идентификатор заявки на сайте.
Обмен данными
Создадим http-сервис no.os, который будет принимать введенные данные и сохранять в локальной БД.
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
Текст = Запрос.ПолучитьТелоКакСтроку();
Данные = JSON.Прочитать(Текст);
// Соединение
Соединение = СлужебныеФункции.НовыйСоединениеБД();
// Имя переменной: Идентификатор
// Имя параметра: id
//
Идентификатор = Строка(Новый УникальныйИдентификатор);
// Имя переменной: ДатаСоздания
// Имя параметра: creation_date
//
ДатаСоздания = ТекущаяДата();
// Имя переменной: ДатаРезервирования
// Имя параметра: reservation_date
//
СтруктураДатаВремя = ПолучитьДатуИзСтроки(Данные["date"]);
СтруктураДатаВремя = ПолучитьВремяИзСтроки(Данные["time"], СтруктураДатаВремя);
ДатаРезервирования = Дата(
СтруктураДатаВремя.Год,
СтруктураДатаВремя.Месяц,
СтруктураДатаВремя.День,
СтруктураДатаВремя.Час,
СтруктураДатаВремя.Минута,
0
);
// Имя переменной: КоличествоМест
// Имя параметра: people
//
КоличествоМест = Число(Данные["people"]);
// Имя переменной: ИмяКлиента
// Имя параметра: name
//
ИмяКлиента = Данные["name"];
// Имя переменной: Телефон
// Имя параметра: phone
//
Телефон = Данные["phone"];
// Имя переменной: АдресЭлПочты
// Имя параметра: email
//
АдресЭлПочты = Данные["email"];
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| INSERT INTO order_request (id, creation_date, reservation_date, people, name, phone, email)
| VALUES
| (@id, @creation_date, @reservation_date, @people, @name, @phone, @email)
|";
Запрос.УстановитьПараметр("id", Идентификатор);
Запрос.УстановитьПараметр("creation_date", ДатаСоздания);
Запрос.УстановитьПараметр("reservation_date", ДатаРезервирования);
Запрос.УстановитьПараметр("people", КоличествоМест);
Запрос.УстановитьПараметр("name", ИмяКлиента);
Запрос.УстановитьПараметр("phone", Телефон);
Запрос.УстановитьПараметр("email", АдресЭлПочты);
Запрос.ВыполнитьКоманду();
Соединение.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("{}");
Возврат Ответ;
КонецФункции
// Преобразует строку вида mm/dd/yyyy в структуру, содержащую Год, Месяц, Число
//
Функция ПолучитьДатуИзСтроки(СтрокаДата, СтруктураДата = Неопределено)
Если СтруктураДата = Неопределено Тогда
СтруктураДата = Новый Структура;
КонецЕсли;
СтрокаДата = СтрЗаменить(СтрокаДата, " ", "");
Индекс = Найти(СтрокаДата, "/");
СтрокаМесяц = Лев(СтрокаДата, Индекс - 1);
СтрокаДата = Сред(СтрокаДата, Индекс + 1);
Индекс = Найти(СтрокаДата, "/");
СтрокаДень = Лев(СтрокаДата, Индекс - 1);
СтрокаГод = Сред(СтрокаДата, Индекс + 1);
СтруктураДата.Вставить("Год", Число(СтрокаГод));
СтруктураДата.Вставить("Месяц", Число(СтрокаМесяц));
СтруктураДата.Вставить("День", Число(СтрокаДень));
Возврат СтруктураДата;
КонецФункции
// Преобразует строку вида HH:MMpm(am) в части времени
Функция ПолучитьВремяИзСтроки(СтрокаВремя, СтруктураВремя = Неопределено)
Если СтруктураВремя = Неопределено Тогда
СтруктураВремя = Новый Структура;
КонецЕсли;
СтрокаВремя = СтрЗаменить(СтрокаВремя, " ", "");
Индекс = Найти(СтрокаВремя, ":");
СтрокаЧасы = Лев(СтрокаВремя, Индекс - 1);
СтрокаВремя = Сред(СтрокаВремя, Индекс + 1);
ДоПослеПолудня = НРег(Прав(СтрокаВремя, 2));
СтрокаМинуты = Лев(СтрокаВремя, СтрДлина(СтрокаВремя) - 2);
Часы = Число(СтрокаЧасы);
Минуты = Число(СтрокаМинуты);
Если ДоПослеПолудня = "am" И Часы = 12 Тогда
Часы = 0;
ИначеЕсли ДоПослеПолудня = "pm" И Часы = 12 Тогда
Часы = 12;
ИначеЕсли ДоПослеПолудня = "pm" Тогда
Часы = Часы + 12;
КонецЕсли;
СтруктураВремя.Вставить("Час", Часы);
СтруктураВремя.Вставить("Минута", Минуты);
Возврат СтруктураВремя;
КонецФункции
Создадим http-сервис go.os, который будет возвращать заказы из БД сайта в учетную систему для импорта
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
// Получить все заявки бронирования
// Соединение
Соединение = СлужебныеФункции.НовыйСоединениеБД();
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| SELECT *
| FROM
| order_request
|";
ЗаявкиБронирования = Запрос.ВыполнитьЗапрос().Выгрузить();
Соединение.Закрыть();
СписокЗаявок = Новый Массив;
Для каждого ЗаявкаБронирования Из ЗаявкиБронирования Цикл
ДанныеЗаявка = Новый Соответствие;
ДанныеЗаявка.Вставить("id", ЗаявкаБронирования.id);
ДанныеЗаявка.Вставить("creation_date", Формат(ЗаявкаБронирования.creation_date, "ДФ=""ггггММддЧЧммсс"""));
ДанныеЗаявка.Вставить("reservation_date", Формат(ЗаявкаБронирования.reservation_date, "ДФ=""ггггММддЧЧммсс"""));
ДанныеЗаявка.Вставить("people", ЗаявкаБронирования.people);
ДанныеЗаявка.Вставить("name", ЗаявкаБронирования.name);
ДанныеЗаявка.Вставить("email", ЗаявкаБронирования.email);
ДанныеЗаявка.Вставить("phone", ЗаявкаБронирования.phone);
СписокЗаявок.Добавить(ДанныеЗаявка);
КонецЦикла;
ТекстТело = JSON.Записать(СписокЗаявок);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(ТекстТело);
Возврат Ответ;
КонецФункции
Создадим http-сервис do.os, который будет удалять заказ с определенным идентификатором, после появления его в учетной системе
Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
// УдалитьЗаявкуБронирования
// Соединение
Соединение = СлужебныеФункции.НовыйСоединениеБД();
Данные = JSON.Прочитать(Запрос.ПолучитьТелоКакСтроку());
// Имя переменной: Идентификатор
// Имя параметра: id
//
Идентификатор = Данные["id"];
Запрос = Соединение.СоздатьЗапрос();
Запрос.Текст = "
| DELETE FROM order_request
| WHERE
| id = @id
|";
Запрос.УстановитьПараметр("id", Идентификатор);
Запрос.ВыполнитьКоманду();
Соединение.Закрыть();
Ответ = Новый HTTPСервисОтвет(200);
Возврат Ответ;
КонецФункции
Создадим регламентное задание ПолучитьЗаявкиССайта, с нижеследующим обработчиком:
Процедура ПолучитьЗаявкиССайта() Экспорт
// Вставить содержимое обработчика.
СуффиксСтраниц = Константы.СуффиксСтраницОбмена.Получить();
ОтносительныйURL = Константы.ОтносительныйURLСайта.Получить();
Если СуффиксСтраниц = Неопределено Тогда
СуффиксСтраниц = "";
КонецЕсли;
Соединение = Новый HTTPСоединение(
Константы.ИмяХостаСайта.Получить(), // сервер (хост)
80, // порт, по умолчанию для http используется 80, для https 443
, // пользователь для доступа к серверу (если он есть)
, // пароль для доступа к серверу (если он есть)
, // здесь указывается прокси, если он есть
, // таймаут в секундах, 0 или пусто - не устанавливать
// защищенное соединение, если используется https
);
Запрос = Новый HTTPЗапрос(ОтносительныйURL + "go" + СуффиксСтраниц + ".os");
Ответ = Соединение.Получить(Запрос);
Если Не Ответ.КодСостояния = 200 Тогда
Возврат;
КонецЕсли;
МассивЗаявок = JSON.Прочитать(Ответ.ПолучитьТелоКакСтроку());
Для каждого Заявка Из МассивЗаявок Цикл
// Проверяем наличие заказа в ИБ, если есть - пропускаем
Если Не Документы.ЗаявкаБронирования.НайтиПоРеквизиту("ИдентификаторЗаявкиНаСайте", Заявка["id"]) = Документы.ЗаявкаБронирования.ПустаяСсылка() Тогда
Продолжить;
КонецЕсли;
ДокЗаявка = Документы.ЗаявкаБронирования.СоздатьДокумент();
ДокЗаявка.Дата = ТекущаяДата();
ДокЗаявка.ДатаБронирования = Дата(Заявка["reservation_date"]);
ДокЗаявка.КоличествоМест = Заявка["people"];
ДокЗаявка.ИмяКлиента = Заявка["name"];
ДокЗаявка.Телефон = Заявка["phone"];
ДокЗаявка.АдресЭлПочты = Заявка["email"];
ДокЗаявка.ИдентификаторЗаявкиНаСайте = Заявка["id"];
ДокЗаявка.ДатаСозданияНаСайте = Дата(Заявка["creation_date"]);
ДокЗаявка.Записать(РежимЗаписиДокумента.Запись);
УдалитьЗаявкуССайта(Заявка["id"]);
КонецЦикла;
КонецПроцедуры
Обновим конфигурацию ИБ, опубликуем новые http-сервисы и протестируем функционал.
События ресторана
Создание галереи событий ресторана аналогично созданию списка специальных блюд. В учетной системе, события представлены справочником СобытиеРесторана, который аналогичен справочнику Номенклатура. Список событий на сайте формируется документом УстановкаСобытийРесторана. На стороне сайта, этим объектам соответствуют таблицы event, event_lists и event_list. Для обмена данными используются http-сервисы ue.os, de.os, uel.os, del.os.
Обратная связь
Реализация этого функционала аналогична реализации приема заявок на резервирование. На стороне учетной системы, обращения клиента представлены документом ОбращениеКлиента. На стороне сайта, данный объект представлен таблицей feedback. Для обмена данными используются http-сервисы cf.os, gf.os и df.os. Для периодического получения обращений клиентов используется регламентное задание ПолучитьОбращенияКлиентов.
Итоговая структура БД сайта представлена на рисунке ниже.
Создание web-приложения OneScript
Поскольку в процессе создания и тестирования приложения мы добавили строку соединения с СУБД, а также библиотеку СредстваHTTP, нам необходимо полностью перевыгрузить приложение. Однако, поскольку учетная система и БД сайта уже содержат некоторые данные, перед полной выгрузкой приложения сформируем архив "прочие файлы" и поместим его в одноименный макет. Обновим конфигурацию и выгрузим ее в файлы. Затем, в режиме предприятия на всякий случай создадим архив нашего приложения. Далее обновим приложение с установленным чекбоксом Обновить приложение. Также необходимо заново добавить права на запись для папок db и img пользователю IUSR.
Протестируем созданное приложение.
Развертывание web-приложения.
Для развертывания в различных средах, могут быть использованы методики, описанные в статьях:
В нашем случае — развернем приложение на web-хостинге.
Заключение
Вот таким вот нехитрым образом, почти не покидая конфигуратор, мы создали настраиваемое бизнес-ориентированное web-приложение, которое интегрировано с 1С:Предприятие. Думаю, что интеграция с какой-либо типовой конфигурацией не должно вызвать каких-либо проблем.
Теперь о впечатлениях, полученных в процессе создания данной демонстрационной конфигурации:
Код является практически полностью переносимым. Непереносимой является единственная функция, преобразующая виртуальный путь в физический :
// Получает физический путь файловой системы, соответствующий виртуальному
//
Функция ПолучитьФизическийПутьИзВиртуального(ВиртуальныйПуть) Экспорт
//<1C>
Если СтрНачинаетсяС(ВиртуальныйПуть, "/") Тогда
ФизическийПуть = Константы.КаталогПриложения.Получить() + ВиртуальныйПуть;
ИначеЕсли СтрНачинаетсяС(ВиртуальныйПуть, "~") Тогда
ФизическийПуть = Константы.КаталогПриложения.Получить() + Прав(ВиртуальныйПуть, СтрДлина(ВиртуальныйПуть) - 1);
ИначеЕсли ВиртуальныйПуть = "" Тогда
ФизическийПуть = Константы.КаталогПриложения.Получить();
Иначе
ФизическийПуть = Константы.КаталогПриложения.Получить() + "" + ВиртуальныйПуть;
КонецЕсли;
Возврат СтрЗаменить(ФизическийПуть, "/", "");
//<!1C>
//<OneScript>
//СредстваHTTP = Новый СредстваHTTP;
//Возврат СредстваHTTP.ПолучитьФизическийПутьИзВиртуального(ВиртуальныйПуть);
//<!OneScript>
КонецФункции
Инструменты для работы с БД оказались достаточно удобными и вместе с автогенерацией кода сэкономили массу времени при разработке и отладке.
Механизм сравнения/объединения оказался удобным, для включения библиотек.
Механизм макетов также оказался кстати, так как не приходилось думать о размещении файлов.
Хранение конфигурационных файлов в формате yaml также оказалось очень удобным, ввиду возможности динамического добавления элементов и читаемого вида.
Конечно для создания web-приложений необходимы хотя-бы базовые знания html, css и javascript, поскольку небольшие правки практически неизбежны. Альтернативой является наличие отдельного специалиста по frontend.
Неудобным является необходимость программировать обмен для каждого объекта информационной базы, который должен быть отображен на сайте. В результате появляется большое количество http-сервисов с похожим кодом. Хотя этот код несложен и быстро создается, особенно с использованием автогенерации, все-таки это отнимает время и его создание является достаточно нудным занятием. По всей видимости эту проблему можно решить, создав подсистему, в которой будет реализован обмен "типовых" справочников и документов, которую можно включать сравнением/объединением в новые проекты.
Отличная статья!
Единственный вопрос:
Это хобби? Или os+web используется для решения реальных бизнес задач?
Где можно пощупать результат и будет ли пример прикручивания оплаты?
(2)Результат — по кнопке «Показать демо». Конфигурация — в аттаче к публикации. Код открыт. Можете развернуть у себя etc.
Пример прикручивания оплаты — можно конечно сделать.
(3) Спасибо, не знал про эту кнопку
(1)Используется в паре небольших проектов.
Все отлично и доступно. Можно ли данный функционал залить на рабочий хостинг? Т.е. полноценно использовать это решение.
Так же есть ли вариант «прикрутить» платежные сервисы ? Допустим Сбер банк?
(6)
Да, конечно, только хостинг должен поддерживать asp.net
пример
Вот
Да. Каждая эквайринговая система предоставляет api (как правило — это POST-запросы + json), а также виджеты кнопок, для перехода на страницу оплаты (ввод номера карты etc.).
Наверное таки надо сделать демо-пример оплаты 🙂
очень интересная вещь!
А конфигурация, генерирующая сущности БД — это она?https://infostart.ru/public/817239/
(11)
Нет, это была первая версия.
https://infostart.ru/public/841785/
Вот эта
(12) Заплюсовал, спасибо
Все красиво, главное вопрос трудозатрат и масштабируемости. Судя по ним все печально.
(14)Что привело Вас к такому заключению?
(15)
1. Разработка этого, поддержка и расширение требует значительно больших(в разы) трудозатрат, чем использования готовых решений(пусть даже платных).
2. Сейчас куча требований от ya и google по сайтам, если их не выполнять, сайт будет в перде и тд. Интеграция с различными сервисами.
3. Отказоустойчивость низкая.
(16) Давайте по пунктам, если не возражаете:
Почему Вы так считаете? Что конкретно ее снижает по сравнению — ну пусть будет с битриксом (или приведите Ваш пример)?
Какие же конкретно хитрые требования, которые трудновыполнимы в данном случае предъявляют яндекс и гугл?
Опять таки непонятно, на основании чего сделан такой вывод. Пожалуйста разверните Вашу мысль, лучше с небольшим конкретным примером.
(19)
Тогда предлагаю вычеркнуть этот пункт
1.
Мне кажется, что это никак не связано именно с отказоустойчивостью и тем не менее:
Если Вы размещаете сайт на хостинге — то как правило данная функциональность уже в наличии. Если Вы размещаете сайт у себя — используйте штатные средства системы. И windows и linux позволяют производить резервное копирование файловых ресурсов без всяких проблем.
Аналогично с п. выше. Никакого отношения к отказоустойчивости не имеет. Самый простой и правильный вариант проверки работоспособности сайта, который используется и в таких системах, как System Center — это периодическая отправка тестовых http-запросов, желательно также и из сегмента сети клиентов. Соответственно создаете регламентное задание и вперед.
Если Вы размещаете сайт на хостинге, то как правило — она есть. Если у себя — и подчеркну это актуальная проблема, то наилучшим решением — будет покупка соответствующего hardware.
Я скептически отношусь к встроенным в cms средствам защиты от DDoS атак и сомневаюсь, что приведенное Вами software может защитить от атак типа icmp storm etc.
Пожалуйста расскажите подробнее, что Вы имеете ввиду, т.к. это понятие очень обширное (можно книгу написать).
(20)
https://yandex.ru/support/webmaster/recommendations/intro.xml#intro .
Если я не знаю именно(нет перед глазами списка), то это не значит что его нет. Требования есть — это факт. И у гугла и у яндекса. Например яндекс:
Если сайт не будет работать, то спрашивать будут у вас. Вы будете чинить, а не хостер. А если данные сайта потеряются — вы будете страдать, а не хостер. Хостер далеко, вы рядом.
Например самая модная штука: двухфакторная авторизация( по 2 параметрам — паролю и телефону.)
(19)
Это на мой взгляд какие-то надуманные страхи.
Если мы ведем речь о сайте из статьи, где пяток (ну пусть будет 20) таблиц и одна страница — то найти разработчика, который не разберется будет сложно, хотя и возможно. Если мы говорим об большом и сложном проекте — то Вы и так не соскочите ввиду сложности проекта либо получите, как Вы написали, огроменный счет.
Вы не поверите, но на ASP.NET сделано не меньше сайтов для не менее крупных клиентов, достаточно взглянуть на stackoverflow или microsoft с Azure 🙂
Это все болезни начального этапа. Если инструмент удобный — то появится и все то, о чем Вы написали 🙂
Кстати Вы полагаете, что функционал оплаты банковскими картами настолько сложен, что требует для своей реализации огромных трудозатрат?
А зачем его обходить? Вы полагаете, что скажем эквайринг Сбербанка, Яндекс Кассы или Робокасса не поддерживают требования этого закона?
(22)
Надуманные страхи? Вы рассматриваете все со стороны разработчика. Клиентам(заказчикам) плевать на ваши суждения. Им главное приемлемый результат, как можно дешевле и меньшими рисками. Ваш пример в принципе не имеет конкурентных преимуществ для стороннего клиента. Если бы я был безденежный студент, который захотел бы себе запилить сайт — такой вариант подошел бы. Да и то, нужно 1С покупать, а это деньги.
Более того, нахрена тут 1С? Здесь по сути нет никакого учета. Это все можно на сайте запилить. Но вместо этого, а давайте на 1С! Заплатим за него, сделаем одно узкое место(обмен)
(19)
Я правильно понимаю, что остальные вопросы отпали :)?
Неплохо-бы к этой фразе добавить три слова: по моему мнению
Абсолютно верно. И в случае, когда у вас уже есть разработчики 1С, которые владеют предметной областью, а также имеют необходимые знания о бизнес-процессах компании и учетной системе, возможно более дешевым и менее рискованным будет вариант — заказать frontend у web-студии и сделать backend своими силами.
Мы не рассматриваем сферического клиента в вакууме. Предполагается, что у клиента уже есть учетная система на платформе 1С-предприятие. Соответственно сайт является частью учетной системы предприятия.
Ну хорошо, рассмотрим не примере конфигурации из статьи 🙂
Скажем, у Вас есть ресторан, в ресторане Вы используете скажем 1С:Ресторан (подставьте название подходящей конфигурации). В учетной системе УЖЕ формируется меню. Вы предлагаете вводить его руками на сайте? Также у вас со временем могут меняться цены. Поступим аналогично? Скажем у вас появляются некие блюда со скидками, и их введем вручную?
Наверное нам придется нанять человека, который все это будет делать?
Ну и т.п. 🙂
(25)
Честно говоря — не в курсе. А подскажите пожалуйста, с какими cms есть штатный обмен в УНФ? Есть ли с woocommerce, opencart, может быть с magento?
Подскажите пожалуйста, почему периодически возникают различные публикации и статьи, использующие то прямую запись в БД , то вызовы API http-сервисов при помощи различных обработок и иных средств?
Допустим — да :).
По моему никто и не предлагал писать с нуля Али Экспресс или твиттер (к тому-же системы такого уровня пишут так, что получается как с нуля). Давайте как-то определимся с размером проектов, которые мы рассматриваем.
Чтобы не выдумывать, возьмем для начала пример из статьи, который является распространенным и реальным. Потом, если будет желание — можем проэкстраполировать на что-то более крупное :). И более того, никто не утверждал, что какая-либо другая система (битрикс, wordpress, допишите нужное) чем-то плоха, а вот то, что предлагается — это «серебряная пуля» и решение всех проблем.
Собственно суть дискуссии в Вашем первом исходном тезисе —
С остальными опасениями мы вроде как благополучно разобрались.
Так вот таки хотелось-бы увидеть от Вас аргументированный, относительно развернутый и конкретный комментарий того, на основании чего Вы сделали такое заключение.
Если Вы это утверждаете — значит у Вас есть какие-то количественные оценки ну и Вы уже произвели сравнение и выявили все минусы.
Вот и поделитесь этой информацией для начала, для данного конкретного случая.
Думаю не только мне это будет интересно.
(27)
извините что влезаю, можно пример?
Только собирался писать свой велосипед
(21)
(21)
Ну и? Какие там особенные требования, которые нельзя реализовать в сайте на простых html страницах?
Сайт без двухфакторной авторизации будет понижен в выдаче или заблокирован?
Это говорят вышеприведенные правила?
Давайте-таки ближе к теме 🙂 Хорошо, что Вы нашли ссылку на рекоммендации.
(17) По пункту 1 в части «поддержка и расширение» коллега на текущий момент прав. Вы используете набор готовых компонент и свои наработки — если Вы перестанете поддерживать свои труды, то с очередным обновлением что-то может «пойти не так» и конечный пользователь останется один на один с данной проблемой. Ванскрипт могут перестать поддерживать, asp обновится и на текущую версию будет сложно найти хостинг и т.д. Другими словами, говорить про поддержку более распространенных решений проще именно ввиду наличия комьюнити. С другой стороны, если вспомнить историю php — комьюнити «дело наживное» 🙂
(31)
Полностью с Вами согласен, относительно существования такого риска. Этот риск так или иначе существует для любого продкта/системы. Несомненно, в данном случае он на порядки выше. Вопрос о том, принимать или не принимать этот риск думаю будет зависеть от баланса того, что Вы можете в итоге потерять и какие преимущества можете приобрести.
Вот если бы коллега высказал именно эту мысль, а также мысль о том, что библиотек с прикладной функциональностью пока практически нет и их нужно создавать — никто бы не стал возражать. Однако, из аргументов вместо этого прозвучали снижение отказоустойчивости, некие правила, которые могут быть выполнены только при использовании определенных систем, и увеличенная в разы стоимость поддержки и разработки, с непонятной мне методикой оценки, непонятно для какого случая.
(33)
Так вот оно что 🙂
Почему же Вы НЕ являясь тем самым бизнесом, который платит Вам деньги говорите от его имени и пытаетесь решать, что ему нужно, а что нет? Может быть бизнес сам примет необходимые решения?
Коллега, Вы путаете мониторинг состояния службы с отказоустойчивостью. Я не собираюсь Вас в чем-либо переубеждать. Если Вы считаете, что Ваше enterprise решение более отказоустойчиво, чем другие, но не можете внятно объяснить в каком месте, то пусть так и будет 🙂
Голый woocommerce без доп плагинов?
Тема заказа столиков совсем не раскрыта. Как будем заказывать?
Какой функционал? Чатик? Наберите в google — бесплатный онлайн чат для сайта. Все, что Вам потребуется в дальнейшем — зарегистрироваться и добавить javascript виджета на свою страницу.
Какой еще enterprise функционал Вы бы порекомендовали добавить?
То есть, я должен заплатить 30К, возможно еще купить шаблон, разобраться в платформе, чтобы написать сайт, аналогичный демонстрационной конфигурации, только с чатом :)?
(33)
Ну понятно 🙂 Сами себе продаете свою систему.
Зачем пытались ввести людей в заблуждение?
Коллега, скажу прямо, Ваши посты по данному вопросу, равно как и по вопросу неких правил поисковых систем показывают Вашу некомпетентность.
Поскольку и Вы и я изложили свои мнения — предлагаю завершить дискуссию, ввиду ее бессодержательности.
(37)
Если я буду говорить, сколько и что — то будет ясно где я работаю и кто я. Я этого не хочу.
(37)
В данном случае вводите заблуждения вы. Я вам сказал, что есть типовой обмен от 1С, работающий по стандартизируемому протоколу обмена. Есть поддержка разных платформ. Сказал вам, что можно поставить бесплатные плагины на woocommerce , которые работают по этому же протоколу обмена. Более того, из 1С можно создавать интернет магазины, с автоматически настроенным обменом. Ничего внятного в ответ вы так и не сказали.
(37)
Перед тем как написать про поисковики — я лично проверил запросы, что они выдают верную информацию. Я так понял аргументировать вы не смогли. На том и решим.
Мы люди работающие с разных позиций, с разным опытом и разным мышлением.
(25)
(25)
Вы путаете причины и потребности, я думаю у «крупняка» потребности как у всех остальных субъектов бизнес сферы, но у них другие приоритеты.
Тут скорей важно гарантированное покрытие задач за гарантированное время, и ГЛАВНОЕ, это благодаря тому, что эти решения тиражные, если все не взлетит, есть объяснение у принявшего решение, что это «интерпрайз решения за миллионы»,
НО если получится заинтересовать ответственных менеджеров нестандартными решениями, вполне возможно в их среде и использование разработок «с нуля».
Повторюсь, проблема даже не в том, что в разработках под заказчика дороже или дешевле, дольше или быстрее, а в том, что используя решения известные, принимающие решения менеджеры снимают с себя ответственность, типа «как все, так и мы» но «не взлетело»…
(38)
Коллега, давайте посмотрим:
Вы:
У них универсальный протокол обмена с сайтом. Подходит для платформы Битрикса, UMI, CS-Cart и других. Причем, как у Битрикса и у многих других, есть отдельные бесплатные модули интеграции, который еще больше расширяют функционал. Причем работающие не только по commerce ML. 1С сейчас очень сильно продвигает enterprise data и многие используют эту технологию.
Я:
Я правильно понимаю, что я в wordpress выбираю тему, устанавливаю плагин woocommerce, в 1С:Унф указываю url сайта м.б. логин, пароль и все? У меня появятся цены, товары, характеристики скидки и продажи автоматически попадут в 1С:Предприятие? А если у меня нет продаж, а нужно резервировать столики?
Без доработок, по commerce ML, в 1С придет заказ в УНФ. А этот заказ можно интерпретировать по разному уже на уровне 1С.
Собственно как изволите это трактовать?
Заказ без плагина, т.е. без доработки как Вы понимаете никуда не придет. И товары не появятся. И если Вы посмотрите требования к настройке — там вплоть до правки php (возможно сейчас его уже вылизали).
Какие запросы и куда Вы проверили? Изначально, Вы писали:
Вы:
2. Сейчас куча требований от ya и google по сайтам, если их не выполнять, сайт будет в перде
Я:
Какие же конкретно хитрые требования, которые трудновыполнимы в данном случае предъявляют яндекс и гугл?
Что я должен аргументировать? Вы прочли рекоммендации, которые Вы нашли? Теперь можете ответить на мой вполне конкретный вопрос, который находится выше по тексту?
Ну вот при всем моем к Вам уважении 🙂
(41)
Коллега, Вам был задан конкретный вопрос, на который был получен конкретный ответ (см диалог), который не совпадает с действительностью.
Пожалуйста прекратите флуд. Вам был задан конкретный вопрос, на который Вы внятно не смогли ответить.
(42) Ясно, по существу сказать ничего не можете.
По функционалу ответил, что точно есть. Что спросили — то и ответил.
Я ведь скинул вам выдержуку из доки. Там четно написаны рекомендации.
Я выше писал уже, у нас разный взгляд и разный опыт. Что то вам доказывать бессмысленно. Живите с своем мире.
(39)
Тут скорей важно гарантированное покрытие задач за гарантированное время, и ГЛАВНОЕ, это благодаря тому, что эти решения тиражные, если все не взлетит, есть объяснение у принявшего решение, что это «интерпрайз решения за миллионы»,
НО если получится заинтересовать ответственных менеджеров нестандартными решениями, вполне возможно в их среде и использование разработок «с нуля».
Там много причин. У них главный приоритет(технический) это масштабируемость и его поддержка(инструментальная, техническая). Нужна уверенность, что при реальных(и пиковых) нагрузках время отклика будет в требуемых значениях. Другой функционал тоже нужен, но это не так критично, можно допилить,, т.к. там такие бюджеты..
(31) ерунду говорите… точнее, очевидные вещи… майкрософт прекратила поддержку многих своих продуктов… все переучивались и переходили на другие продукты… 1С заставила семерочников переучиваться на восьмерочников, а бизнес менять работающие решения… с другими производителями ПО та же история… комьюнити ни на что не годится, если производитель закрыл тему… вообще, ничего нового не могло бы возникнуть, если бы все так рассуждали как вы… каждая технология и каждый продукт вначале ходит в детских штанишках, но некоторые из них как-то вырастают…
если вы программист и вам лично на первый взгляд нравится новый язык или новая технология, пробуйте… и только попробовав решайте…
(45) сложно ответить на Ваш комментарий, потому что он больше похож на поток сознания (сплошные многоточия). По порядку:
— попробуйте таки определиться;
— закрытие проприетарных проектов не относится к моему комменту и к теме обсуждения;
— очень спорно, отвечать смысла не вижу;
— если сравнивать с dot net (java) и т.д. — здесь скорее «освоить новую версию», а не «переучиваться» (вендор тот же, предметка та же, материалы для перехода и т.п.);
— если исходники открыты, коммьюнити жива и нет правовых споров — то никаких проблем ;
— автор понял мою мысль и согласился с ней. Его ответ меня очень порадовал — мы оба осознаем риски и обсудили их. В общем, эта фраза явно мимо кассы.
— да, этот рост связан как раз с интересом людей (пользователей, разработчиков, инвесторов и т.д.). К чему эта фраза?
— на мой взгляд это спорный подход, если Вам он нравится — пользуйтесь.
Крутяк
(46) если у Вас возникли проблемы с приемом моего потока сознания, то могли бы и не тратить время на ответ… 🙂 извините, если что… так бывает в жизни, я ему про Фому, а он мне про Ерему… последняя фраза относится к нам обоим… поговорили каждый о своем…
Автору огромное человеческое спасибо за титанический труд. Озадачился подобным веб-движком и нашел это чудо. Очуметь! Круто!
Знаю на ты php, html, javascript, css, 1c. Писал сайта, одностраничники, конфигурации на 1с.
МНОГО ЛЕТ ждал подобного решения на 1с, которое позволит в родном, РУССКОЯЗЫЧНОМ синтаксисе описать языком высокого уровня логику веб-приложения. Это чудо расчудесное.
Я считаю, для рядового программиста, который по НЕОБХОДИМОСТИ осваивает чужеземные веб-технологии, русскоязычный синтаксис экономит время, мозг, нервы, память.
— Не нужно в процессе работы переключаться между раскладками клавиатуры
— Обмен данными на http-сервисах позволяет встроить обмен и отладку на стороне 1с, с трансляцией объектов запросов во встроенные объекты 1с.
— Логику веб-приложения пишем на родном русскоязычном языке.
— Есть поддержка, есть документация, есть библиотеки, есть плагины.
Я считаю, данную технологию нужно развивать и добавлять функционала.
В защиту технологии должен заметить:
— WordPress, Bitrix и другие CMS на заре развития, несколько лет назад — были голыми системами с малой толикой сегодняшнего функционала
— Доп функционал можно добавлять постепенно, плагинами, библиотеками и др.
— Русскоязычный синтаксис с лихвой компенсирует все перечисленные противниками малые недостатки.
Как программист, освоивший множество смежных веб-технологий, заявляю — моя любовь к платформе 1с горит в сердце незатухающим огнем. Готов тратить время, ресурсы на развитие подобного проекта.
1с это интерпретируемый язык высокого уровня абстракции. Разработка такового языка делается для:
— быстроты и удобства использования ПРИКЛАДНЫМ программистом (тот, который реализует бизнес-логику в рамках языка)
— Основная черта высокоуровневых языков — это абстракция
— разработаны для платформенной независимости сути алгоритмов
— Зависимость от платформы перекладывается на инструментальные программы — трансляторы
В данном решении выбран язык высокого уровня абстракции — 1с, известный прикладным программистам
1с:
— обладаем русскоязычным синтаксисом
— структура языка похожа на осмысленные предложения русского языка.
— при беглом прочтении прикладным разработчиком, суть программы становится ИНТУИТИВНО ПОНЯТНОЙ
это обеспечивает:
— экономию времени на прочтение и улавливание СУТИ кода на языке
— быструю разработку, не вдаваясь в подробности реализации конкретных механизмов взаимодействия.
Что дает данная разработка:
— экономятся денежные ресурсы предприятия
— вместо программиста php, веб-программиста, используется квалифицированный 1с-программист с начальными знаниями функционирования веб-сайтов
— используется встроенные механизмы 1с-платформы для реализации обмена данными и отладкой на стороне 1с
— для создания сайта используется русскоязычный синтаксис высокой степени абстракции. Это позволяет абстрагироваться от заучивания низкоязыковых ИНОСТРАННЫХ конструкций, использовать ИНТУИТИВНО ПОНЯТНЫЙ СИНТАКСИС при разработке веб-приложения.
Многие противники, которые выступают против данной технологии приводят кучу аргументов, которые легко опровергаются.
НО ОНИ НЕ ПОНИМАЮТ СУТИ:
— 1script сделан для УДОБСТВА ПРОГРАММИСТА.
— РУССКОЯЗЫЧНЫЙ СИНТАКСИС языка высокого уровня ИНТУИТИВНО ПОНЯТЕН РУССКОМУ разработчику.
— Абстракция позволяет АБСТРАГИРОВАТЬСЯ от конкретной реализации метода/функции с помощью технологии MVC (Модель, Представление, Контроллер).
Знаете такое МНОГОЛЕТНЕЕ явление — священные войны между программистами ?
Выходит новый язык программирования и начинается Священная война между адептами старых языков и нового.
Суть войн заключается в следующем:
— Какой язык лучше
— Какой язык круче
— Какой язык быстрее
— Какой язык ПОНЯТНЕЕ
И по мере развития НОВОГО языка, он все больше обрастает фишками, последователями, библиотеками.
Все просто — новый язык НРАВИТСЯ программистам по тем или иным причинам.
и дело вовсе не в ПРИБЫЛИ, ЗАРАБОТКЕ, ПОДДЕРЖКЕ. Все это — ничего не значит в СВЯЩЕННЫХ ВОЙНАХ языков.
Точно такую же Священную войну в миниатюре разыграли противники данной технологии.
От себя скажу, что мне НЕ НРАВИТСЯ php, c javascript имею дело по принуждению (выбора нет).
Если появится возможность ЗАМЕНИТЬ их на язык высокого уровня абстракции, то с удовольствием это сделаю, несмотря ни на что.
Что касается ДЕНЕЖНОЙ реализации.
Можно написать ПРостой сайт с интеграцией с 1с.
При наличии времени и команды можно реализовать веб-морду к любой типовой конфигурации 1с и продавать это дело отдельно!
(49)
Ну дык при соединяйтесь :), код, в том числе и движка — открыт.
Очень не хватает мануала, позволяющего за полчаса запустить ваше решение и оценить его возможности.
Нет ли где информации, как имея конфигурацию cf, платформу с настроенным вебсервером — запустить ваш сайт?
Здесь подробно описана настройка web-сервера
https://infostart.ru/public/789679/
https://infostart.ru/public/841785/
https://infostart.ru/public/794882/
Это описание базовой конфигурации. Здесь же описано как выгружать приложение
Здесь описана установка на linux
Правильно ли я понял, что, чтобы достать данные из базы данных, не получится пользоваться удобной консолью запросов 1С? Нужно писать руками запросы к используемой базе данных?
(55)
Если Вы имеете ввиду конструктор запросов — его нет, нужно писать руками selecy from ….
(24)
У меня те же самые вопросы и они никуда не отпали. Я смотрю в эту статью и вижу велосипед, который, конечно же, ездит, возможно, даже хорошо ездит, но непонятно, для чего его было изобретать, если велосипедов много. Т.е. как хобби и просто так — конечно, интересно покрутить это всё. Но как коммереское решение? Серьёзно? Свой битрикс-вордпресс-джумла на 1С с преферансом и поэтессами?
Даже посмотреть на размер текста этой статьи — я быстрее сайт на вордпрессе примерно похожего содержания разверну, чем это всё прочту. А это не худлит, это ещё и осмыслить надо и повторить! Сколько на это уйдёт? Неделя? Какова себестоимость такой разработки?
Следующий момент, вы пишете, что у вас там 20 таблиц и можно легко найти того, кто в этом разберётся. Это отлично, только я как клиент не хочу искать кого-то, кому надо будет разбираться в этом всём. Я хочу чтобы человек сразу сел и принялся за доработку, уже зная систему. Единственный человек на рынке, кто знает эту вашу разработку — это вы, программист 1С, который возьмёт с меня от 1500 в час. А тех, кто знает вордпресс-битрикс — тысячи, на любом фрилансе по три копейки продаются.
Дальше — мне вот это всё хозяйство чтобы завести, нужно ещё и сервер 1С купить, коробку, СУБД, с лицензиями и прочим весельем, развернуть свой сервер или покупать спецхостинг и т.п. Во сколько это выльется? Обычных ПХП-хостинг для битрикса-вордпресса стоит от 1200 в год — купил, включил, загрузил, забыл. И даже не знаешь таких страшных слов, как ИТС, лицензии, анкеты и проч.
Даже если у меня уже есть база 1С, из которой надо грузить сайт, всё равно готовые решения будут стоить в разы дешевле — для битрикса уже куча готовых коннекторов, для вордпресса-джумлы можно накидать на коленке за пару часов просто на структуре их БД (это из личного опыта).
И что на выходе? Огромное нечто значимой стоимости, созданное на стыке технологий, очень дорогое в поддержке и доработке с привлечением дорогих спецов, знающих этот стык, и с кучей сопутствующего головняка. И для чего? Чтобы в конце тоннеля получить сайт ресторана, который можно было получить за пару часов на битриксе-вордпрессе-джумле?
Как разбор этого самого стыка технологий — очень интересно. Но раз уж вы так увлечённо доказываете, что это — отличная альтернатива существующим велосипедам, то я так и не понял, в чём экономическая выгода для среднестатистического клиента всего этого как коробочного решения.
(57)Вот Вам примеры:
https://infostart.ru/project/1088172/
https://infostart.ru/project/1087417/
Готовы сделать два проекта за 4 часа ;)?
А вообще кто нибудь получал оплату за проекты в тендере?
А то тут курсы есть по выстраиванию отношений с клиентами в том числе.Может сначала надо купить курсы, а только потом участвовать в конкуренции за проекты?
(59)
У меня есть типовой обмен 1С и битрикс, который не допиливается и работает. Что я делаю не так? 🙂
(62)Ну а у других надо допиливать 🙂 Так Вы сделаете два проекта за четыре часа :)? Или внедрите типовой обмен так, чтобы было как у Вас?
(63)
Понятно)) Т.е. это не просто эксперимент из чистого любопытства. Вы во что бы то ни стало решили всем доказать, что ваше решение — экономически выгоднее всех других и ради этого будете передёргивать, менять и скрывать информацию. Ваше право. Удачи в продажах))
(64)
Нет, Вы не правильно поняли (как и предыдущий коллега). Речь идет о том, что когда Вы что-то утверждаете — будьте готовы к тому, что Вас попросят обосновать Ваше утверждение. Не более того 🙂
Я же не тянул Вас за язык, делать различные утверждения, а при попытке выяснить, на чем они основаны, Вы начинаете злиться 🙂 и путать простой эксперимент с какими-то продажами, передергиваниями и сокрытием какой-то информации.
P.S.
Спасибо, за пожелание удачи (да хоть и в продажах :), почему бы и нет), Вам также всех благ.
(65)
Злиться?))) На что мне злиться?))) Это вы после простых вопросов о вашем детище начали злиться, на одни вопросы не отвечаете, на другие даёте какие-то выдернутые из контекста данные. Я ведь как раз об этом и говорю — если вы пишете статью, то будьте готовы, что вам зададут вопросы. Вопросы вам задали, а вы говорите — «Нет, не буду отвечать, просто моё решение экономически выгоднее всех на свете!» И пытаетесь теперь перевернуть всё с ног на голову, будто это кто-то делает утверждение и это он обязан доказывать. Хотя утверждение делали вы («моё решение как минимум такое же выгодное, как существующие»), но доказать его даже не пытаетесь, сразу перейдя к манипуляциям.
Вы тогда уж определитесь — это «простой эксперимент, не путайте с продажами» и тогда вам больше спасибо, эксперимент действительно хороший и подробный. Или же это невиданное доселе суперкоммерческое решение, которое разорит битрикс и всех остальных — тогда вы мне, как потенциальному клиенту, ни на один вопрос не ответили по существу))
(66)
Вы вроде как откланялись уже 🙂
Вы аннотацию к статье читали :)?
Там написано:
Есть какие-то двусмысленности :)?
Не согласны с моим мнением о том, что это можно использовать для создания простых сайтов и это сопоставимо по трудозатратам с адаптацией темы под wordpress?- Конструктивно аргументируйте.
Коллега, какие конструктивные вопросы Вы задали и получили ответ, про экономическую выгоду?
Ну, …., даже не знаю :).