Условные условия и запросы




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2025-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='\

59 Comments

  1. alexk-is

    Может так?

    ПостроительОтчета.Текст =

    «ВЫБРАТЬ

    | Учет.Товар,

    | Учет.Количество

    |ИЗ

    | Документ.Учет КАК Учет

    |{ГДЕ

    | Учет.Склад.*}»
    ;

    ПостроительОтчета.ПолучитьЗапрос()).Выполнить();

    Посмотреть как это работает, ну, и другие варианты оптимизации запросов можно здесь http://www.infostart.ru/public/69707/

    И еще «Учет.Склад.Ссылка = » плохое условие, правильнее будет «Учет.Склад = «

    Reply
  2. Serj1C

    (1) +1 за использование построителя

    (0) Прошлый век. На СКД также предлагаете мучаться?

    Reply
  3. vlengin

    Что значит «моструозных», может имелось ввиду «монстроозных»?

    Reply
  4. vlengin

    Точнее «монструозных».

    Reply
  5. zfilin

    (4) Ага. Точно!

    (1) Насчет «Учет.Склад.Ссылка = » согласен, это я «очепятался». И спасибо, что предложили еще более совершенный способ достигнуть требуемого результата. Правда, я не совсем понял при чем тут ваш замечательны журнал, но видимо какая-то связь есть…

    Reply
  6. Yashazz

    Я в таких случаях пишу комментарии в тексте запроса.

    Например

    |ГДЕ

    |Склад = &УсловныйСклад

    |//УсловиеНаТовар//»;

    и потом просто СтрЗаменить(ТекстЗапроса,»//УсловиеНаТовар//»,»И Товар = &УсловныйТовар»)

    Конечно, конструктор режет комментарии, но хоть прочитать запрос при этом может.

    Reply
  7. 4ish

    Еще как вариант:

    |ГДЕ

    |ВЫБОР

    |КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

    |ТОГДА ПоступлениеТоваровУслугТовары.Ссылка.Склад = &Склад

    |ИНАЧЕ ИСТИНА

    |КОНЕЦ

    Reply
  8. zfilin

    (7) Точно! =)

    (6) Да, жаль что режет, так тоже способ ничего.

    (1) А! Спасибо, уже оценил!

    Reply
  9. alexk-is

    (8) По ссылке в (1) используется много разных запросов. Мой любимый по структуре подчиненности документов.

    Reply
  10. zfilin

    (9) Ага, вот смотрю как раз. Круто, че сказать.

    Reply
  11. artbear

    По опыту скажу:

    1. Построитель не всегда удобен 🙁

    2. использование как (0), так и (7) не всегда удобно.

    Лично я чаще юзаю сравнение не с ПустаяСсылка, а с NULL.

    Reply
  12. artbear

    (0) ОФФ Увидел в твоем блоге заметки про тестирование.

    По опыту скажу: Сценарное тестирование долго, неудобно, негибко 🙁

    Посмотри

    Юниттестирование на восьмерке (готовый набор для тестирования, у меня постоянно в работе) http://www.1cpp.ru/forum/YaBB.pl?num=1267016427/94#94

    Тестирование разработок на платформе 1С. Управление данными http://www.1cpp.ru/forum/YaBB.pl?num=1273213867/35#35 (это схемы работы с тестовыми данными и обсуждение разных схем)

    .

    Также можешь посмотреть мою разработку

    Повышение удобства разработки в среде 1С http://infostart.ru/public/65526/

    есть спец.раздел Тестирование

    Reply
  13. zfilin

    (12) О! Спасибо, тестирование меня очень интересует, обязательно посмотрю.

    Reply
  14. Vit aka proger

    а я обычно пишу так:

    Запрос.Текст =

    «ВЫБРАТЬ

    | Учет.Товар,

    | Учет.Количество

    |ИЗ

    | Документ.Учет КАК Учет

    |ГДЕ

    | Учет.Склад в иерархии( &Склад))»;

    Если склад пустой, выбирается по всем имеющимся складам

    Хотя я обычно делаю запрос по регистрам

    |ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&КонПериода, Склад в иерархии(&Склад))

    Reply
  15. Alias

    (6) А я пишу так. Конструктор отрабатывает без проблем, ничего не теряется… и сама строка «&УсловиеСклада» выглядит понятнее чем какие-то сложные условия. И выполнение запроса (это важно!) при этом не тормозит. И конструктор ничего не режет. Короче, сплошные плюсы 🙂

    Запрос.Текст =

    «ВЫБРАТЬ

    | Учет.Товар,

    | Учет.Количество

    |ИЗ

    | Документ.Учет КАК Учет

    |ГДЕ

    | &УсловиеСклада»;

    Запрос.Текст = СтрЗаменить(Запрос.Текст, «&УсловиеСклада»,?(ЗначениеЗаполнено(ВыбСклад),»Учет.Склад.Ссылка = &Склад»,»»));

    Reply
  16. Minotavrik

    Есть хороший способ отлаживать большие и страшные, текст которых изменен в конфигураторе различными операторами.

    Я делаю так:

    Нахожу строчку Запрос.выполнить(). Ставлю точку останова и перехожу в отладку. Когда точка срабатывает, делаю следующее:

    Нажимаю на кнопку «Вычислить выражение»;

    в поле пишу Запрос.Текст (если через построитель то ПостроительОтчета.ПолучитьЗапрос().Текст);

    Копирую текст запроса и отлаживаю его в консоли.

    Reply
  17. zfilin

    О! Спасибо всем, сколько способов!

    Нужно обязательно будет включить их в текст самой статьи.

    Reply
  18. gaglo

    (15) Тут не понял: если «&УсловиеСклада» заменить на «», то получится запрос

    «ВЫБРАТЬ



    |ГДЕ «;

    — но ведь он синтаксически неверен?

    Я пишу почти так же, только вместо «ГДЕ &УсловиеСклада» ставлю «ГДЕ Истина».

    Выглядит не так уж понятно, и наводит на не те мысли (сравни с «Где справедливость?»)

    Зато можно выполнять и без всяких СтрЗаменить…

    Reply
  19. zfilin

    (16) Спасибо за подсказку, я тоже использую такой способ для отладки. =)

    Reply
  20. mst

    а я в 7ке пишу не «=» а «в» и работает независимо выбран элемент или нет… никогда не писал =, потому что при «в» в запрос попадают еще и элементы из подгрупп выбранной группы справочника.

    Reply
  21. I_G_O_R

    (16) Вы наверное большие запросы не видели, в ЗУПе они почему-то не помещаются 😥

    Reply
  22. artbear

    (21) Все помещается, нужно только включить выражение с текстом в табло просмотра, далее щелкнуть на тексте, и нажать лупу. откроется окошко для просмотра текста, откуда и можно скопировать текст.

    (16) (19) Копирование текста запроса вручную неудобно, т.к. параметры придется самому ставить 🙁

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

    В итоге в отладчике вычисляешь код Отладить(Запрос) и в режиме Предприятия открывается консоль с полным запросом (текст, параметры, временные таблицы и т.д.)

    Посмотрите мою разработку http://infostart.ru/public/65526/

    В ней я описал различные фичи, в т.ч. и мощнейшие консоли.

    Reply
  23. Alias

    (18) Ой, конечно, Вы абсолютно правы! Поспешил с написанием комментария. У меня просто обычно этот приём используется как часть сложного условия (то есть, например, условие на Организацию есть всегда). Тогда пустой строки никак не бывает.

    В простом же случае можно писать либо «ИСТИНА ИЛИ &УсловиеСклада», либо в СтрЗаменить() включать строку с указанием ГДЕ («ГДЕ Учет.Склад.Ссылка = &Склад»)

    А в комментарии смешал оба этих случая. 🙂 спасибо что указали на неточность.

    Выбор варианта зависит от удобства в конкретном случае.

    Reply
  24. Lapitskiy

    с выводами по скорости не согласен, если выполнять запросы в цикле, выборка идет из кэша! Надо не запрос в цикле делать, а 1 запрос по большой базе.

    Reply
  25. zfilin

    (24) Согласен, я для этого и приложил конфу, чтобы можно было по-разному попробовать.

    Reply
  26. rasswet

    в если из ГДЕ Учет.Склад.Ссылка убрать ссылку?

    Reply
  27. zfilin

    (26) Про ссылку еще в самом начале говорили, она там случайно оказалась.

    Наверное, надо подредаткировать…

    Reply
  28. I_G_O_R

    (22) я именно так и смотрю, просто в ЗУПе есть такие большие запросы что в этом окне только часть текста (например текст запроса расчета НДФЛ, в нем около 5000 строк, а помещается где-то 3000 с лишним).

    Reply
  29. Yashazz

    Способ Alias’a опасен тем, что при достаточно сложной логике условия есть риск запутаться и налажать. Простыми «истина» и «ложь» тоже можно напутать — поставить, например, «Истина» в условие «И», а потом поменять где-то что-то на «Или», условие-то большое, и получить ошибку.

    Reply
  30. Serj1C

    (14) «в иерархии» работает медленно!

    мне больше нравится (1) и (15)

    Reply
  31. Alias

    (29) Не согласен. Разбивание большого и сложного условия на несколько маленьких наоборот, упростит понимание условия! Сравните, например, один из предложенных вариантов:

    |ВЫБОР

    | КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)

    | ТОГДА Учет.Склад = &Склад

    | ИНАЧЕ ИСТИНА

    |КОНЕЦ И

    |ВЫБОР

    | КОГДА &Организация <> ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)

    | ТОГДА Учет.Организация = &Организация

    | ИНАЧЕ ИСТИНА

    |КОНЕЦ

    и то что предлагаю я:

    |&СкладПодходит И &ОрганизацияПодходит

    Что из этого проще? 🙂

    Ваш довод работает против Вас — так как в сложном условии как раз-таки проще запутаться, чем в условии, разбитом на простые блоки.

    Reply
  32. Serj1C

    Вместо (31) я использую иногда:

    |ГДЕ

    | &Склад В (Выборка.Склад, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка))

    Reply
  33. romansun

    (0) добавлю свои пять копеек. Похоже на уже описанные тут варианты..

    довольно стандартная реализация чекбокса в запросе:

    |ГДЕ (&флПДК = ложь ИЛИ (&флПДК = истина И ДокументРасчетов.ПризнакДополнительногоКонтроля = истина))

    вместо динамических запросов использую часто также СтрЗаменить() через примерно такие конструкции:

    |ГДЕ Истина

    |//секцияКонтрагент И Контрагент = &Контрагент

    |//секцияДоговор И Договор = &Договор

    |//секцияДокументРасчетов И ДокументРасчетов = &ДокументРасчетов

    Конструктор, конечно, срубит ремарку, но я им практически не пользуюсь. Только при первоначальном написании в консоле запросов, чтоб имена реквизитов он мне все вытащил :).

    Reply
  34. max082

    Мне лично еще нравится следующая конструкция:

    |

    |Где &ВсеСклады ИЛИ Документ.Склад = &Склад

    |

    Reply
  35. zfilin

    (34) max082, Тоже неплохо, а &ВсеСклады это что?

    Reply
  36. Altair777
    Reply
  37. zfilin

    Да, я тоже пользуюсь модификацией текста запроса.

    Но я все же применил бы параметр &УсловиеПоДатеДоговора, который бы в зависимости от ситуации менял бы на строку «ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода» или на «Истина».

    Так в конструкторе запроса, я увижу что у меня есть какое-то условие, которое в последствии будет определяться в коде модуля. А если просто убирать строчку «И ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода», то про то, что она в последствии может исчезнуть во время отладки запроса очень просто забыть. И думать потом — вот у меня же четко стоит отбор по датам. Почему ж оно не отбирает-то?

    Reply
  38. Altair777

    (38) а текст кода нормально виден? У меня что-то нет 🙂

    P.S. Вопрос снят. Разобрался.

    Reply
  39. AlexO

    Непонятны восторги.

    Ну да, хорошо, собрал в одном месте варианты проверок (да и то не все), — но не систематизированные, без описания применимости и раскрытия смысла.

    Есть масса способов сделать условие в запросе.

    Их уже множество тут накидали.

    1С наделала столько всего, что оно и не нужно так много. Достаточно было сделать одно — но путное и быстрое.

    Можно и ВЫБОР…КОГДА, можно и через параметр &Параметр, можно и заменой текста запроса перед выполнением.

    ПостроительОтчета для выполнения запроса используют только тру-1сники.

    А все же посыл статьи не раскрыт: без динамического формирования запросов во многих случаях не обойтись никак, ничем это не заменишь, и никаких инструментов в 1С для отладки нет.

    Reply
  40. Altair777

    (38)

    > И думать потом — вот у меня же четко стоит отбор по датам. Почему ж оно не отбирает-то?

    Если это сделать системой, то думать не придется.

    Логика простая — если есть параметр запроса, значит он должен заполняться.

    А раз он заполняется, то есть код его заполнения.

    И в том же самом месте происходит и модификация текста запроса.

    Плюс немного экономии — раз параметр не используется, то зачем его вставлять?

    ОФФ: А вообще, при отладке очень сложных запросов, текст которых может модифицироваться несколько раз и в нескольких разных местах, лучше в отладчике отловить окончательный текст прямо на стоке Запрос.Выполнить()

    Reply
  41. zfilin

    (42) Altair777, Ага. Ну, с этой позиции да, полностью согласен.

    Но я-то исходил из того, что код могут смотреть и другие люди, которые могут не знать о такой системе и воспринимать выражение «ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода» однозначно — есть такое условие, полагая, что заполнение параметров это… Просто заполнение параметров! =) И там только обычное заполнение дат!

    А одиночным параметром мы однозначно заставляем того, кто читает код, проверить что за условие скрывается за параметром. Естественно, к имени параметра тот кто будет писать запрос, должен выставлять требования сходные с требованиям к именованию функций. Имя этого параметра должно отражать суть условия.

    Собственно, это на самом деле уже детали, и дело вкуса. Кому-то кажется понятнее одно, кому-то другое. Суть одна — модификация текста запроса.

    Reply
  42. Altair777

    (43)

    > Ну, с этой позиции да, полностью согласен.

    Спасибо 🙂

    Такой подход дает 2 неоспоримых преимущества — возможность использовать конструктор и ускорение выполнения запроса.

    P.S. Видел я и второй подход — по условию добавлять строки в текст запроса. Но это гораздо затратнее.

    Reply
  43. zfilin
    Reply
  44. AlexO

    (42) Altair777,

    лучше в отладчике отловить окончательный текст ….

    оо, выдал все профессиональные тайны … 🙁

    Reply
  45. Altair777
    Reply
  46. Altair777

    (46) AlexO, да?!!! 🙂

    Я бы мог отредактировать свой коммент чтобы не раскрывать тайну, но… все равно останется в цитате.

    Reply
  47. Altair777

    (45)

    понял! А если этот текст перекинуть в консоль запросов, то как его отлаживать?

    Два понятных параметра НачалоПериода И КонецПериода заменяется на нечто… совсем не понятное 🙂

    Reply
  48. zfilin

    (47) Да, добавлением не очень удобно.

    (49) Свои минусы есть. В консоли отлаживать не очень удобно, но как вы справедливо заметили для отладки лучше использовать итоговый текст из строки «Выполнить()». =) Раз уж мы тут все замешаны в выдаче страшных секретов. =)))

    Reply
  49. AlexO

    (50)

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

    Это проблема проблем 🙂

    Я решаю совсем уж оригинальным способом, здесь не указанным.

    (48) Altair777,

    я отредактировал цитату, теперь ваша очередь 🙂

    но вдруг уже попала в поисковую базу яндекса?!

    Reply
  50. ArtemiFD

    (6) Yashazz, так же пользуюсь заменой условия, но предпочитаю использовать сравнения одинаковых цифр или символов.

    Запрос = Новый Запрос;
    Запрос.Текст =
    «ВЫБРАТЬ
    |   Учет.Товар,
    |   Учет.Количество
    |ИЗ
    |   Документ.Учет КАК Учет
    |ГДЕ
    | 1=1
    | И 2=2″;
    СтрЗаменить(Запрос.Текст,»1=1″,»Товар = &УсловныйТовар»);
    

    Показать

    Reply
  51. Yashazz

    (52) Красиво! Спасибо за идею. В случае 666=666 вероятность совпадения практически нулевая, и читаться конструктором будет в большем количестве случаев. 🙂

    Reply
  52. ta44ik

    Еще необходима статья как заменить &ПустаяСсылка на ЗНАЧЕНИЕ(Документ.ПустаяСсылка) И &ПустаяДата например на Год(&Дата)=1(есть варианты.)

    Reply
  53. ekaruk

    Могу предложить еще вариант

    СхемаЗапроса = Новый СхемаЗапроса;

    СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст);

    СхемаЗапроса.ПакетЗапросов[0].Операторы[0].Отбор.Добавить(«Учет.Склад = &Склад»);

    Запрос.Текст = СхемаЗапроса.ПолучитьТекстЗапроса();

    Подробнее тут http://infostart.ru/public/307045/

    Reply
  54. zfilin

    (55) ekaruk, Тоже хорошо. Жаль, что только для новых версий.

    Reply
  55. SemenovaMarinaV

    Очень любопытно

    Reply
  56. _Sasha_
    Reply
  57. zfilin

    (58) _Sasha_, Циферки чем не удобно. Тем, что сидя в конструкторе запроса не понятно что за 1=1, что за 2=2. Надо идти смотреть в код.

    Заменяемый параметр типа &УсловиеСклада более «говорящее» название. Можно писать что угодно, хоть &ТутСложноеУсловиеГдеПроверяетсяВходящиеНаВхождениеАИсходящи­еНаИсхождение. Синтаксису не противоречит, перед выполнением все-равно будет заменено и иллюстрирует о чем же условие.

    Но и циферками, конечно тоже можно.

    Reply
  58. okulus

    Подскажите, как в СКД сделать условное условие «МЕЖДУ &НачалоПериода И &КонецПериода»?

    Reply
  59. ToJIuK

    Это все работает когда запрос пишется в модуле . А как быть если мне нужно данное условие засунуть в «ДинамическийСписок» через параметры формы

    Пробовал

    ЗНАЧЕНИЕ(Справочник.

    Пишет ошибку . «Не понимает «?Справочник» «.

    Пробовал передать пустое значение «Контрагента» (я по Контрагенту фильтрую) выходит пустой отбор . Подскажите как быть ? как сделать так чтобы условие работало только когда передан Контрагент

    Reply

Leave a Comment

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