Последнее время натыкался на несколько различных статей об интеграции сайта и 1С. В комментариях часто начинались споры о различных подходах, и я решил поделится способом который однажды довелось реализовать мне. Разумеется, описанный ниже способ не претендует на универсальность и единственность, но, думаю, будет полезен тем, кто только собирается писать свой вариант.
Тяпки, грабли и лопаты
Не очень большой магазин (номенклатура порядка 5000 товаров).
Обыкновенная, файловая 1С 8 УТ. Конфигурация стоит на полной поддержке, и снимать с поддержки нельзя.
База лежит на одной из десктопных машин, которая в свою очередь используется для работы одним из сотрудников.
Достаточно выгружать минимум информации: название, описание, фото, несколько видов цен.
Ломать уже устоявшуюся экосистему было так же крайне не желательно.
Под сайт выделен обыкновенный
Выгрузка может происходить не часто, достаточно 1 раза в 3 часа.
Впоследствии, стало необходимо добавить выгрузку прайс-листа в xls.
Скромный бюджет для реализации проекта.
Машина, выполняющая роль «сервера» была и без того не быстрой, а наличие постоянных подключений к базе 1С, только усугубляло ситуацию. Но, заказчика это устраивало, а значит, кучи денег на покупку отдельного сервера и перевооружение остального парка не было.
В связи с ограничениями бюджета, вариант с Битриксом и его типовой интеграцией отпал сразу. Да и интерес был скорее спортивный, реализовать всё самостоятельно. Было решено использовать уже использовавшийся ранее каркас для каталога товаров. Каркас был сделан на CodeIgniter, поэтому добавить небольшой модуль труда не составляло. Решено.
Лет'с старт
Первым делом стал вопрос о периодичности выгрузки информации, а руки так и потянулись к регламентным заданиям… но, стоп. Во-первых, конфигурацию с поддержки снимать нельзя, а значит, и вносить правки в саму конфигурацию мы не можем, а во-вторых, все копии 1С запускаются только при необходимости, а значит, будет ли в нужный момент запущена 1С или нет — неизвестно. Да, можно было бы обязать заказчика, при запуске «сервера» всегда запускать 1С и всегда держать её запущенной, но ведь это создаст лишние неудобства заказчику, а значит решение не самое удобное. Увы, регламентные задания сегодня нам не смогут помочь. Очевидно, что нам понадобится помощь стороннего приложения, для запуска процедуры выгрузки в определённый момент. Тут мы вспоминаем про то, что 1С позволяет запускать себя из командной строки, более того, мы можем сразу же выполнить нужную нам внешнюю обработку и при необходимости, есть даже возможность передать ей какой-нибудь параметр.
Вот основные ключи, которые будут использоваться:
"Путь к 1С" enterprise /F"Путь к базе" /N"Логин" /P"Пароль" /Execute"Внешняя обработка" /C"Параметр" /DisableStartupMessages
Теперь осталось настроить запуск этой конструкции по расписанию. Планировщик Windows? Настраиваем, проверяем… работает!
Но есть один серьёзный недочёт. Когда планировщик запускает по расписанию 1С, то, разумеется, она открывается сверху над всеми приложениями и если в это время работает кто-то за компьютером, то это, во-первых, будет его отвлекать, а во-вторых, он может и закрыть это новое окно. Не порядок… Что же делать? Начинаем копать в сторону запуска под другой учётной записью. Спасибо гуглу, достаточно быстро находим возможность пакетного запуска под другим пользователем. Создаём нового пользователя Windows, разрешаем в политиках безопасности пакетный запуск, перенастраиваем планировщик, проверяем… вуаля! Всё сработало, при этом мы не увидели никаких раздражающих окон! Отлично, значит, такой вариант нам подходит… теперь переходим к собственно выгрузке самих данных.
Выгрузка
Первым делом, конечно, я стал смотреть в сторону CommerceML, но ознакомившись с документацией, стало ясно, что для нашей, достаточно элементарной выгрузки городить весь этот огород — слишком долго, а бюджет не резиновый. Значит, будем искать альтернативный способ. Почему бы просто не выгружать текстовую информацию в xml, а картинки выгружать в отдельную директорию? Решено, так и делаем. Получаем достаточно простую структуру xml-файла: внутри сначала идут записи для групп, а потом сами номенклатурные единицы.
Так выглядят группы:
<group> <Code>код</Code> /*Код-элемента из 1С*/ <Name>наименование</Name> /* Собственно, наименование группы*/ <ParentCode>код родителя</ParentCode> /* Если не пусто, значит группа является вложенной*/ </group>
А так товары:
<item> <Code>код</Code> /* Код-элемента из 1С */ <ParentCode>код родителя</ParentCode> /* Код группы, к которой принадлежит товар */ <Name>наименование</Name> <Descr>Описание</Descr> <Article>Артикул</Article> <TypePrice>Тип цены</TypePrice> <Price>Цена</Price> <Сurrency>валюта</Сurrency> <Remains>Остатки</Remains> <Unit>шт/кг/литры</Unit> <Img>img_dae5eacd-7d88-11de-8856-0024213f1c89.jpg</Img> /* Все изображения содержат в названии уникальный идентификатор элемента в базе 1С */ </item>
Не хитрым запросом получаем информацию по всем товарным группам и товарам, далее формируем xml-ку. Также делаем отдельную выборку и вытаскиваем информацию для прайс-листа, а затем сохраняем полученную информацию в xls.
После этого переходим к выгрузке изображений. В связи с ограничениями хостинг-площадки, обрабатывать изображения на стороне
cd c: set thePATH= Здесь указываем путь к изображениям FOR /R "%thePATH%" %%a IN (*.jpg) DO ImageMagick-6.7.0-10convert.exe %%a -resize ШИРИНАxВЫСОТА^> -quality 70 %%a FOR /R "%thePATH%" %%a IN (*.jpg) DO ImageMagick-6.7.0-10convert.exe %%a -resize ШИРИНАxВЫСОТА^> -gravity center -extent ШИРИНАxВЫСОТА -quality 70 %thePATH%mini%%~nxa
Запускаем из нашей обработки этот bat'ник и получаем результат.
Вся информация выгружена, осталось всё аккуратно упаковать в zip и загрузить по фтп на сервер, с чем отлично справляется 1С штатными средствами.
На первый взгляд всё, но… Неужели мы каждый раз будем вытаскивать всю номенклатуру, со всеми картинками и всю эту махину грузить на сервер? Нет уж, это картина не для слабонервных… И что же делать? Делать флаги и отмечать, какая номенклатурная единица изменилась? Нет, мы же не можем править конфигурацию… Но ведь есть же планы обмена? Кто нам запрещал использовать их? Никто! Создаём план обмена, настраиваем. Дальше модифицируем нашу выгрузку, теперь во время выгрузки создаём новое сообщение в плане обмена, выгружаем только изменённые с момента последнего сообщения единицы… Отлично!
Серверная часть
Тут всё ещё прозрачнее. Вешаем запуск скрипта по крону. В скрипте смотрим в нужную директорию, ищем по маске нужный архив. Если таковой имеется, то распаковываем, парсим xml, пишем информацию в БД. Картинки у нас внутри ещё одним архивом, его тоже распаковываем, прямо поверх директории с уже имеющимися картинками. Если такая картинка уже есть, переписываем её новой. xls-файл копируем с заменой в нужную директорию. Пишем в базу информацию, о том, что произвели такое-то обновление, тогда-то, с таким-то номером, а затем чистим за собой временные файлы. Всё.
Соломка от сбоев
Если в процессе выгрузки информации, обработке изображений, архивировании, загрузке на удалённый фтп произойдут ошибки, то мы можем потерять часть обновлений, и в итоге информация на сайте и в базе 1С будет рассинхронизирована. Ниже я описал основные острые углы, для которых понадобилось подстелить соломки:
1. Итак, что же будет, если например, в момент загрузки по фтп, оборвётся связь?
Если мы уже записали сообщение в план обмена, то получается, что 1С, считает, что успешно выгрузила эти изменения и теперь уже собирает новые, но на сайт-то они не попали! Правильно, поэтому заканчиваем запись в план обмена только после успешного завершения всех этапов выгрузки, включая загрузку файлов по фтп! А если же в процессе выгрузки происходит исключительная ситуация, то мы прерываем запись сообщения в плане обмена и пишем ошибку в error-log.
2. А что, если наш скрипт на сервере начнёт обрабатывать ещё не догруженный архив?
Мы сначала даём ему одно имя (например, export.zip_), а лишь по завершении переименовываем его и даём имя, которое будет искать скрипт на сервере.
3. А что если на сервере будет сбой и скрипт не успеет обработать наш архив, 1С затрёт его новым?
Нет, для этого каждый архив содержит в названии номер сообщения из плана обмена (например, export_1.zip). Скрипт на сервере в свою очередь при обнаружении нескольких архивов обрабатывает их в порядке возрастания номеров.
4. А логи не переполнятся?
Т.к. при выгрузке в лог пишется подробно информация о результатах каждого действия, то логи достаточно быстро растут, поэтому не забываем при каждой выгрузке контролировать их размер и при необходимости удалять старые.
5. А что если 1С не успеет произвести выгрузку, а в это время стартует процесс для новой выгрузки?
В настройках планировщика настраиваем так, чтобы новое задание не выполнялось, если предыдущее не завершено.
P.S.
Итак, таким вот нехитрым способом за достаточно короткий срок была реализована выгрузка номенклатуры/цен/остатков на сайт. Разумеется, данный вариант имеет ряд недостатков и не претендует на лавры единственно-верного, но при этом нам удалось полностью вписаться в ограничения установленные экосистемой заказчика. Вся эта конструкция работает на слабых машинах, не требует постоянно запущенной копии 1С, работает на самом обыкновенном виртуальном-хостинге, абсолютно не отвлекает сотрудников на себя и главное, позволяет беспрепятственно обслуживать 1С. Подстеленной соломки оказалось достаточно, и за уже почти год, к счастью, ни одного нашего вмешательства в работу системы не потребовалось.
Автор: galichmark