Эргономика рулит, или как добиться от 1С возможности редактирования объекта в списке / Попытка применения MVC паттерна в среде 1С Предприятия 8.2




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

26 Comments

  1. zaebidze

    Молодчик!Только MVC с 1С-ной как-то не айс вяжется))))Программер который будет читать код не зная данного паттерна, быстрее застрелица! Да и для ООП он более актуален!А идея супер!

    Reply
  2. kote

    (1) .. думал я один бессоницей маюсь 🙂 А на счет не айс, в общем согласен.. но давно было желание попробывать реализовать в 1С эти идеи.. как начал знакомиться с Java для самообразования.

    Обидно как то за то, что лучшие мировые наработки использовать 1С не дает.

    Reply
  3. V_V_V

    Я конечно далек от ООП, но в чем конкретно была проблема с связями списков в 1С 8.2? О каком перепрограммировании (муторном) связи с Владельцем идет речь, если эта связь настраивается парой щелчков мышки? При этом становятся видны (и доступны на редактирование) только подчиненные элементы. Что сложного в редактировании элемента в списке без вызова форм?

    Reply
  4. kote

    (3) Ну и.. в общем я такого же мнения был, пока не начал делать такую форму.. Бъюсь об заклад, штатными средствами — без написания кода — у Вас ничего не выйдет.. особенно при создании нового объекта.

    А если я не прав — пожалуйста, расскажите как сделать то же простыми настройками, буду очень благодарен Вам.

    Ну и попробую ответить, как смогу..

    «Что сложного в редактировании элемента в списке без вызова форм?»- ну хотя бы то, что на месте можно редактировать _только данные табличных частей_, но никак не поля списка, данные в котором, — элементы справочника.. ну и при этом — в списке же — нужно не только изменять поля, но и добавлять новые элементы — тоже без вызова формы объекта..

    «О каком перепрограммировании (муторном) связи с Владельцем идет речь, если эта связь настраивается парой щелчков мышки?» — .. по опыту поддержки значительно»меняных» конфигураций — особенно в части форм — при обновлении настройки, «нащелканные» мышкой как правило слетают и/или забываются.. код поддерживать проще, быстрее и дешевле.. а если изменения (или построение) форм прописать в код, в событие ПриСоздании, например, — то перенос изменений форм при обновлении ГОРАЗДО быстрее.. Единственное неудобство поначалу — в конфигураторе сразу не видишь форму в доработанном виде.. но это поначалу — когда по привычке лезешь смотреть макет формы 🙂

    Reply
  5. tsd

    (4) а при чем здесь Гагарин? 🙂

    Reply
  6. kote

    (5) Тык, это я шлем примеряю.. Видимо, придется в космосе искать 1Сников, интересующихся шаблонами проектирования 😉

    Reply
  7. tango

    так это — (0) — шаблон проектирования?

    всегда казалось, что ШП — это типовые конфигурации

    Reply
  8. kote

    (7) типовые конфигурации — все таки готовые решения.. а вообще 1С страдает тем, что заимствует термины, но понятия в них вкладывает свои, что порой приводит к путанице.. я не слышал, но может и типовые конфигурации они обозвали шаблоном проектирования.

    Reply
  9. tango

    (8) «1С страдает» — …жЖоООжЬ… 🙂

    Reply
  10. Збянтэжаны Саўка

    (5) Присмотритесь. Это не Гагарин, возможно это фото автора или еще кого-то, но никак не Гагарина.

    Reply
  11. tsd

    (10) уже присмотрелись. Как признался автор, энто он примеряет старые шмотки.

    Видать взлететь собрался 😀

    Reply
  12. kote

    (10)(11) .. Для желающих отправиться со мной — скафандры выдают на http://www.tinza.ru/flash.photofx.php 😎

    Reply
  13. Rabajaba

    Плюс за попытку реализации.

    Немного размышлений вслух:

    1. Зачем редактировать в списке, если есть форма объекта? Я переход к SDI интерфейсу вижу как попытку сделать ввод и чтение данных процессом последовательным, т.е. если что-то начал делать, то делай до конца, а не переключайся между окнами нонстопом. Эта идея 1С мне очень нравится, у пользователей теперь не по 20-25 окон а 3-4, спустя месяц работы говорят удобнее;

    2. По трафику реализация — жесть. Фильтровать список отбором динамического списка 50к элементов в 15-30 позиций это 100-500Б у меня, у вас на 2-3 элемента 5-6кБ;

    3. В реалиях 1С идея мало необходима, т.к. в конечном итоге все равно описываются реквизиты, штатными же средствами необходимо установить точные вызовы событий, ИМХО вид в профиль. 1С штука прикладная, поэтому, на мой взгляд, делать сверхуправляемыми списки, при наличии типа «Динамический список» с произвольным запросом, мало необходимо;

    4. Пример простой работы с отборами в списках (2 метода в глобальном модуле):

    Функция ПолучитьЭлементОтбораКомпоновки(Отбор, ИмяПоля) Экспорт
    // разберем по типам отбора
    Результат = «»;
    флПоиска = ЛОЖЬ;
    // сначала попробуем найти
    Для каждого Элемент из Отбор.Элементы Цикл
    Если Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоля) Тогда
    Результат = Элемент;
    флПоиска = ИСТИНА;
    Прервать;
    КонецЕсли;
    КонецЦикла;
    // не нашли — создадим
    Если НЕ флПоиска Тогда
    Результат = Отбор.Элементы.Добавить(Тип(«ЭлементОтбораКомпоновкиДанных»));
    Результат.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоля);
    КонецЕсли;
    
    Возврат Результат;
    КонецФункции
    Функция УстановитьЗначениеЭлементаОтбораКомпоновки(Отбор, ИмяПоля, Значение, ВидСравнения = «») Экспорт
    ЭлементОтбора = ПолучитьЭлементОтбораКомпоновки(Отбор, ИмяПоля);
    ЭлементОтбора.Использование = ИСТИНА;
    ЭлементОтбора.ПравоеЗначение = Значение;
    Если ВидСравнения = «» Тогда
    ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
    КонецЕсли;
    ЭлементОтбора.ВидСравнения = ВидСравнения;
    
    Возврат ЭлементОтбора;
    КонецФункции

    Показать

    Итого как у меня выглядит связь двух списков:

    &НаКлиенте
    Процедура ТаблицаСпискаПриАктивизацииСтроки(Элемент)
    УстановитьЗначениеЭлементаОтбораКомпоновки(РеквизитФормыТаблица.Отбор, «Объект», Ссылка);
    КонецПроцедуры
    Reply
  14. kote

    (13) Спасибо за интерес..

    «Зачем редактировать в списке, если есть форма объекта?»

    .. ну а зачем пользователю показывать ненужные ему поля, которые в форме объекта представлены все? Или под каждую роль делать отдельную форму с отдельным набором полей? У меня набор полей определяется запросом, являющимся источником данных для конкретного списка — проще манипулировать полями запроса, чем делать формы под каждую роль или использовать штатные средства управления доступом на уровне полей в платформе, ИМХО.

    «..SDI.. а не переключайся между окнами нонстопом. Эта идея 1С мне очень нравится..»

    .. как правило, подробно разработанная модель данных, при использовании 1С, вызывает то, что появляются множество объектов, и, соответственно, множество форм — для редактирования каждого из них.. именно от этого и хотелось уйти, т.е. получить удобный SDI интерфейс + сохранить свободу в реализации модели данных..

    «По трафику реализация — жесть.» .. не спорю, что трафика больше, но это не совсем так, как кажется.. если динамический список прокрутить от начала до конца — он сгенерирует в сумме не меньше трафика… просто там подкачка, происходит в момент перед показом элементов списка на экране, здесь же все сразу выкачивается..

    «В реалиях 1С идея мало необходима, .. делать сверхуправляемыми списки, при наличии типа «Динамический список» с произвольным запросом, мало необходимо..»

    Мне, прежде всего, было необходимо иметь возможность редактировать поля объекта непосредственно в списке — вот этого в 1С нет. Остальное — последствия.

    Reply
  15. kote

    (13) А вообще, думается, что можно на основе динамических списков сделать все это.. Как нибудь попробую попробовать сотворить это с использованием модели MVC.. Спасибо, еще раз, за общение.

    Reply
  16. Rabajaba

    (14)

    .. как правило, подробно разработанная модель данных, при использовании 1С, вызывает то, что появляются множество объектов, и, соответственно, множество форм

    попробую более подробно описать как я вижу работу с интерфейсами 8.2:

    1. Пользователю нужно что-то выбрать из списка — форма списка должна быть легкой, интуитивно понятной и не нагруженной кнопками и формами. Если в списке чего-то не хватает, то пользователь жмет добавить и открывается полная форма объекта. Как результат: окна модальны относительно родителя, т.е. он не сможет вернуться в документ, в котором выбирал номенклатуру, пока не закончит ввод номенклатуры. Из-за этого у меня было много проблем с семеркой (там при открытии модально списков нельзя было добавлять элементы). Т.е. никогда не остается открытых не понятно откуда окон.

    2. Управление видимостью элементов ИМХО проще, чем динамически генерить тексты запросов. Да и не забываем, что это управляемый интерфейс. Я уже своих научил — сначала на форму я размещаю все реквизиты все, потом пользователи снимают видимость того, что их не интересует. Т.е. проще управлять видимостью реквизитов от ролей, нежели генерить разные запросы от ролей. Можно даже унифицировать (пробовал уже) и хранить настройки видимости реквизитов в каком-нибудь справочнике, для централизованного управления;

    3. Небольшое удобство для программиста — не нужно определять все проверки и события модификации объекта как в форме списка, так и в форме объекта. Я уже сам привык (даже как-то удобнее), что справочник на два реквизита редактируется в отдельной форме.

    4. Динамический список удобнее таблицы значений, т.к. его можно настроить как угодно (отборы, сортировки и условное оформление).

    ИМХО:

    Не вижу смысла редактировать объекты в списке.

    Применение вашей реализации вижу удобным только для различных универсальных журналов, списков и т.п.

    Reply
  17. kote

    (16) спасибо за подробное изложение опыта.. буду изучать.

    PS // чую, что скоро ценность комментариев станет больше, чем самого сабжа статьи 😉

    Reply
  18. zfilin

    (6) Нашел. =)

    Reply
  19. zfilin

    Подписаться.

    Reply
  20. AlexO

    Я так понимаю, что это интерактивная связь двух динамических списков?

    Reply
  21. kote

    (20) Если смотреть чисто функционально — то можно и так сказать.. но сам подход — везде доказал свою жизнеспособность и эффективность. Только до прикладных программистов 1С не дошел — в силу специфичности платформы и продвигаемых фирмой 1С наилучших практик использования своей платформы..

    .. на практике — могу сказать, что этот, ээээ.. «скилл» 🙂 помог мне ускорить работу пользователей на большой базе местного лидера рынка по продажам 1С — в среднем в 8 раз.. а на самом «напряжном» моменте — в 22 раза, примерное. Просто переписал интерфейс CRM системы (подсистема от фирмы Рарус). А там многие «спецы» сломались — используя стандартный подход и рекомендации от 1С.

    Reply
  22. Rustig

    (0) покажите в публикации алгоритмы, чтобы не скачивать ваши файлы. сначала заинтересуйте алгоритмами, прежде чем вынуждать людей скачивать что-то. за это минус.

    в описании много лишнего (по-моему): космос, пространные мысли об ООП, каких-то Модель-Вью-Контрол…

    Только из комментарий стало ясно, по какому поводу разговор. Сталкивался с этой проблемой. Скажу так, что в 1С (дополнительно к типовым спискам документов и элементов справочника) редактирование в списке реализуется через ТаблицуЗначений, в которую вы сами заливаете нужные вам поля нужных вам объектов (справочников, документов, характеристик), далее для этой таблицы значений через командную панель сами программируете «Добавить», «Удалить», «Добавить копированием» и так далее. Объем писанного кода безусловно увеличивается в разы, если сравнить с типовыми средствами редактирования в списках элементов справочника.

    Но если вы это сделаете, вы будете в плюсе, потому что это понравится вашим клиентам. 🙂

    Потому что это реально удобно пользователям, но уже не так гибко разработчикам.

    Reply
  23. Rustig

    Пример, представленный в файлах, выбран неудачно, потому что все равно остаются непонятными преимущества перед стандартными динамическими списками. Также, особых комментариев в коде нет, что усложняет расшифровку заложенных алгоритмов и самой идеи. В коде есть отбор списка при активизации элемента в другом списке, собственное перепрограммирование создания и удаления элементов списка, то есть в целом ничего нового… Может я что не увидел? 😉

    Reply
  24. kote

    (23) Вы, видимо, сути так и не поняли — суть не в организации связанных списков. Суть — в возможности редактирования элементов справочников в списке, _без открытия формы элементов_.

    Если Вы сможете с помощью _любых штатных 1С-ских механизмов_ организовать редактирование на одной форме _в списке_ элементов документов/справочников — то я бы признал Вашу правоту.

    Reply
  25. w-divin
    .. ну а зачем пользователю показывать ненужные ему поля, которые в форме объекта представлены все? Или под каждую роль делать отдельную форму с отдельным набором полей? У меня набор полей определяется запросом, являющимся источником данных для конкретного списка — проще манипулировать полями запроса, чем делать формы под каждую роль или использовать штатные средства управления доступом на уровне полей в платформе, ИМХО.

    Специально для этого придумали ФункциональныеОпции, ВидимостьПоРолям ну и как уже говорилось произвольный запрос у динамического списка

    «По трафику реализация — жесть.» .. не спорю, что трафика больше, но это не совсем так, как кажется.. если динамический список прокрутить от начала до конца — он сгенерирует в сумме не меньше трафика… просто там подкачка, происходит в момент перед показом элементов списка на экране, здесь же все сразу выкачивается..

    Интересно было бы посмотреть на работу такого механизма в веб-клиенте при 500-800 тыщь строк…

    Reply
  26. kote

    (25)

    Интересно было бы посмотреть на работу такого механизма в веб-клиенте при 500-800 тыщь строк…

    Не, спасибо 🙂 Тут вот на примере тестов все сделано — вот для таких вот случаев оно в самый раз..

    А где это на стандартных то механизмах можно посмотреть? Мне кажется — такого на практике не бывает, чтоб пользователю нужно было показать все это разом.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *