<?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='\
Может так?
ПостроительОтчета.Текст =
«ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|{ГДЕ
| Учет.Склад.*}»;
ПостроительОтчета.ПолучитьЗапрос()).Выполнить();
Посмотреть как это работает, ну, и другие варианты оптимизации запросов можно здесьhttp://www.infostart.ru/public/69707/
И еще «Учет.Склад.Ссылка = » плохое условие, правильнее будет «Учет.Склад = «
(1) +1 за использование построителя
(0) Прошлый век. На СКД также предлагаете мучаться?
Что значит «моструозных», может имелось ввиду «монстроозных»?
Точнее «монструозных».
(4) Ага. Точно!
(1) Насчет «Учет.Склад.Ссылка = » согласен, это я «очепятался». И спасибо, что предложили еще более совершенный способ достигнуть требуемого результата. Правда, я не совсем понял при чем тут ваш замечательны журнал, но видимо какая-то связь есть…
Я в таких случаях пишу комментарии в тексте запроса.
Например
|ГДЕ
|Склад = &УсловныйСклад
|//УсловиеНаТовар//»;
и потом просто СтрЗаменить(ТекстЗапроса,»//УсловиеНаТовар//»,»И Товар = &УсловныйТовар»)
Конечно, конструктор режет комментарии, но хоть прочитать запрос при этом может.
Еще как вариант:
|ГДЕ
|ВЫБОР
|КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
|ТОГДА ПоступлениеТоваровУслугТовары.Ссылка.Склад = &Склад
|ИНАЧЕ ИСТИНА
|КОНЕЦ
(7) Точно! =)
(6) Да, жаль что режет, так тоже способ ничего.
(1) А! Спасибо, уже оценил!
(8) По ссылке в (1) используется много разных запросов. Мой любимый по структуре подчиненности документов.
(9) Ага, вот смотрю как раз. Круто, че сказать.
По опыту скажу:
1. Построитель не всегда удобен 🙁
2. использование как (0), так и (7) не всегда удобно.
Лично я чаще юзаю сравнение не с ПустаяСсылка, а с NULL.
(0) ОФФ Увидел в твоем блоге заметки про тестирование.
http://www.1cpp.ru/forum/YaBB.pl?num=1267016427/94#94
http://www.1cpp.ru/forum/YaBB.pl?num=1273213867/35#35 (это схемы работы с тестовыми данными и обсуждение разных схем)
http://infostart.ru/public/65526/
По опыту скажу: Сценарное тестирование долго, неудобно, негибко 🙁
Посмотри
Юниттестирование на восьмерке (готовый набор для тестирования, у меня постоянно в работе)
Тестирование разработок на платформе 1С. Управление данными
.
Также можешь посмотреть мою разработку
Повышение удобства разработки в среде 1С
есть спец.раздел Тестирование
(12) О! Спасибо, тестирование меня очень интересует, обязательно посмотрю.
а я обычно пишу так:
Запрос.Текст =
«ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| Учет.Склад в иерархии( &Склад))»;
Если склад пустой, выбирается по всем имеющимся складам
Хотя я обычно делаю запрос по регистрам
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&КонПериода, Склад в иерархии(&Склад))
(6) А я пишу так. Конструктор отрабатывает без проблем, ничего не теряется… и сама строка «&УсловиеСклада» выглядит понятнее чем какие-то сложные условия. И выполнение запроса (это важно!) при этом не тормозит. И конструктор ничего не режет. Короче, сплошные плюсы 🙂
Запрос.Текст =
«ВЫБРАТЬ
| Учет.Товар,
| Учет.Количество
|ИЗ
| Документ.Учет КАК Учет
|ГДЕ
| &УсловиеСклада»;
Запрос.Текст = СтрЗаменить(Запрос.Текст, «&УсловиеСклада»,?(ЗначениеЗаполнено(ВыбСклад),»Учет.Склад.Ссылка = &Склад»,»»));
Есть хороший способ отлаживать большие и страшные, текст которых изменен в конфигураторе различными операторами.
Я делаю так:
Нахожу строчку Запрос.выполнить(). Ставлю точку останова и перехожу в отладку. Когда точка срабатывает, делаю следующее:
Нажимаю на кнопку «Вычислить выражение»;
в поле пишу Запрос.Текст (если через построитель то ПостроительОтчета.ПолучитьЗапрос().Текст);
Копирую текст запроса и отлаживаю его в консоли.
О! Спасибо всем, сколько способов!
Нужно обязательно будет включить их в текст самой статьи.
(15) Тут не понял: если «&УсловиеСклада» заменить на «», то получится запрос
«ВЫБРАТЬ
…
|ГДЕ «;
— но ведь он синтаксически неверен?
Я пишу почти так же, только вместо «ГДЕ &УсловиеСклада» ставлю «ГДЕ Истина».
Выглядит не так уж понятно, и наводит на не те мысли (сравни с «Где справедливость?»)
Зато можно выполнять и без всяких СтрЗаменить…
(16) Спасибо за подсказку, я тоже использую такой способ для отладки. =)
а я в 7ке пишу не «=» а «в» и работает независимо выбран элемент или нет… никогда не писал =, потому что при «в» в запрос попадают еще и элементы из подгрупп выбранной группы справочника.
(16) Вы наверное большие запросы не видели, в ЗУПе они почему-то не помещаются 😥
(21) Все помещается, нужно только включить выражение с текстом в табло просмотра, далее щелкнуть на тексте, и нажать лупу. откроется окошко для просмотра текста, откуда и можно скопировать текст.
(16) (19) Копирование текста запроса вручную неудобно, т.к. параметры придется самому ставить 🙁
http://infostart.ru/public/65526/
лучше пользоваться спец.консолями, которые могут отлаживать сам запрос.
В итоге в отладчике вычисляешь код Отладить(Запрос) и в режиме Предприятия открывается консоль с полным запросом (текст, параметры, временные таблицы и т.д.)
Посмотрите мою разработку
В ней я описал различные фичи, в т.ч. и мощнейшие консоли.
(18) Ой, конечно, Вы абсолютно правы! Поспешил с написанием комментария. У меня просто обычно этот приём используется как часть сложного условия (то есть, например, условие на Организацию есть всегда). Тогда пустой строки никак не бывает.
В простом же случае можно писать либо «ИСТИНА ИЛИ &УсловиеСклада», либо в СтрЗаменить() включать строку с указанием ГДЕ («ГДЕ Учет.Склад.Ссылка = &Склад»)
А в комментарии смешал оба этих случая. 🙂 спасибо что указали на неточность.
Выбор варианта зависит от удобства в конкретном случае.
с выводами по скорости не согласен, если выполнять запросы в цикле, выборка идет из кэша! Надо не запрос в цикле делать, а 1 запрос по большой базе.
(24) Согласен, я для этого и приложил конфу, чтобы можно было по-разному попробовать.
в если из ГДЕ Учет.Склад.Ссылка убрать ссылку?
(26) Про ссылку еще в самом начале говорили, она там случайно оказалась.
Наверное, надо подредаткировать…
(22) я именно так и смотрю, просто в ЗУПе есть такие большие запросы что в этом окне только часть текста (например текст запроса расчета НДФЛ, в нем около 5000 строк, а помещается где-то 3000 с лишним).
Способ Alias’a опасен тем, что при достаточно сложной логике условия есть риск запутаться и налажать. Простыми «истина» и «ложь» тоже можно напутать — поставить, например, «Истина» в условие «И», а потом поменять где-то что-то на «Или», условие-то большое, и получить ошибку.
(14) «в иерархии» работает медленно!
мне больше нравится (1) и (15)
(29) Не согласен. Разбивание большого и сложного условия на несколько маленьких наоборот, упростит понимание условия! Сравните, например, один из предложенных вариантов:
|ВЫБОР
| КОГДА &Склад <> ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
| ТОГДА Учет.Склад = &Склад
| ИНАЧЕ ИСТИНА
|КОНЕЦ И
|ВЫБОР
| КОГДА &Организация <> ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)
| ТОГДА Учет.Организация = &Организация
| ИНАЧЕ ИСТИНА
|КОНЕЦ
и то что предлагаю я:
|&СкладПодходит И &ОрганизацияПодходит
Что из этого проще? 🙂
Ваш довод работает против Вас — так как в сложном условии как раз-таки проще запутаться, чем в условии, разбитом на простые блоки.
Вместо (31) я использую иногда:
|ГДЕ
| &Склад В (Выборка.Склад, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка))
(0) добавлю свои пять копеек. Похоже на уже описанные тут варианты..
довольно стандартная реализация чекбокса в запросе:
|ГДЕ (&флПДК = ложь ИЛИ (&флПДК = истина И ДокументРасчетов.ПризнакДополнительногоКонтроля = истина))
вместо динамических запросов использую часто также СтрЗаменить() через примерно такие конструкции:
|ГДЕ Истина
|//секцияКонтрагент И Контрагент = &Контрагент
|//секцияДоговор И Договор = &Договор
|//секцияДокументРасчетов И ДокументРасчетов = &ДокументРасчетов
Конструктор, конечно, срубит ремарку, но я им практически не пользуюсь. Только при первоначальном написании в консоле запросов, чтоб имена реквизитов он мне все вытащил :).
Мне лично еще нравится следующая конструкция:
|
|Где &ВсеСклады ИЛИ Документ.Склад = &Склад
|
(34) max082, Тоже неплохо, а &ВсеСклады это что?
Да, я тоже пользуюсь модификацией текста запроса.
Но я все же применил бы параметр &УсловиеПоДатеДоговора, который бы в зависимости от ситуации менял бы на строку «ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода» или на «Истина».
Так в конструкторе запроса, я увижу что у меня есть какое-то условие, которое в последствии будет определяться в коде модуля. А если просто убирать строчку «И ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода», то про то, что она в последствии может исчезнуть во время отладки запроса очень просто забыть. И думать потом — вот у меня же четко стоит отбор по датам. Почему ж оно не отбирает-то?
(38) а текст кода нормально виден? У меня что-то нет 🙂
P.S. Вопрос снят. Разобрался.
Непонятны восторги.
Ну да, хорошо, собрал в одном месте варианты проверок (да и то не все), — но не систематизированные, без описания применимости и раскрытия смысла.
Есть масса способов сделать условие в запросе.
Их уже множество тут накидали.
1С наделала столько всего, что оно и не нужно так много. Достаточно было сделать одно — но путное и быстрое.
Можно и ВЫБОР…КОГДА, можно и через параметр &Параметр, можно и заменой текста запроса перед выполнением.
ПостроительОтчета для выполнения запроса используют только тру-1сники.
А все же посыл статьи не раскрыт: без динамического формирования запросов во многих случаях не обойтись никак, ничем это не заменишь, и никаких инструментов в 1С для отладки нет.
(38)
> И думать потом — вот у меня же четко стоит отбор по датам. Почему ж оно не отбирает-то?
Если это сделать системой, то думать не придется.
Логика простая — если есть параметр запроса, значит он должен заполняться.
А раз он заполняется, то есть код его заполнения.
И в том же самом месте происходит и модификация текста запроса.
Плюс немного экономии — раз параметр не используется, то зачем его вставлять?
ОФФ: А вообще, при отладке очень сложных запросов, текст которых может модифицироваться несколько раз и в нескольких разных местах, лучше в отладчике отловить окончательный текст прямо на стоке Запрос.Выполнить()
(42) Altair777, Ага. Ну, с этой позиции да, полностью согласен.
Но я-то исходил из того, что код могут смотреть и другие люди, которые могут не знать о такой системе и воспринимать выражение «ДоговорыКонтрагентов.Дата МЕЖДУ &НачалоПериода И &КонецПериода» однозначно — есть такое условие, полагая, что заполнение параметров это… Просто заполнение параметров! =) И там только обычное заполнение дат!
А одиночным параметром мы однозначно заставляем того, кто читает код, проверить что за условие скрывается за параметром. Естественно, к имени параметра тот кто будет писать запрос, должен выставлять требования сходные с требованиям к именованию функций. Имя этого параметра должно отражать суть условия.
Собственно, это на самом деле уже детали, и дело вкуса. Кому-то кажется понятнее одно, кому-то другое. Суть одна — модификация текста запроса.
(43)
> Ну, с этой позиции да, полностью согласен.
Спасибо 🙂
Такой подход дает 2 неоспоримых преимущества — возможность использовать конструктор и ускорение выполнения запроса.
P.S. Видел я и второй подход — по условию добавлять строки в текст запроса. Но это гораздо затратнее.
(42) Altair777,
оо, выдал все профессиональные тайны … 🙁
(46) AlexO, да?!!! 🙂
Я бы мог отредактировать свой коммент чтобы не раскрывать тайну, но… все равно останется в цитате.
(45)
понял! А если этот текст перекинуть в консоль запросов, то как его отлаживать?
Два понятных параметра НачалоПериода И КонецПериода заменяется на нечто… совсем не понятное 🙂
(47) Да, добавлением не очень удобно.
(49) Свои минусы есть. В консоли отлаживать не очень удобно, но как вы справедливо заметили для отладки лучше использовать итоговый текст из строки «Выполнить()». =) Раз уж мы тут все замешаны в выдаче страшных секретов. =)))
(50)
вся проблема — даже не в получить окончательный текст запроса (хотя он и будет в каждом другом случае — разный), а собрать размазанные параметры, чтобы воспроизвести в консоли именно текущий запрос.
Это проблема проблем 🙂
Я решаю совсем уж оригинальным способом, здесь не указанным.
(48) Altair777,
я отредактировал цитату, теперь ваша очередь 🙂
но вдруг уже попала в поисковую базу яндекса?!
(6) Yashazz, так же пользуюсь заменой условия, но предпочитаю использовать сравнения одинаковых цифр или символов.
Показать
(52) Красиво! Спасибо за идею. В случае 666=666 вероятность совпадения практически нулевая, и читаться конструктором будет в большем количестве случаев. 🙂
Еще необходима статья как заменить &ПустаяСсылка на ЗНАЧЕНИЕ(Документ.ПустаяСсылка) И &ПустаяДата например на Год(&Дата)=1(есть варианты.)
Могу предложить еще вариант
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст);
СхемаЗапроса.ПакетЗапросов[0].Операторы[0].Отбор.Добавить(«Учет.Склад = &Склад»);
Запрос.Текст = СхемаЗапроса.ПолучитьТекстЗапроса();
Подробнее тутhttp://infostart.ru/public/307045/
(55) ekaruk, Тоже хорошо. Жаль, что только для новых версий.
Очень любопытно
(58) _Sasha_, Циферки чем не удобно. Тем, что сидя в конструкторе запроса не понятно что за 1=1, что за 2=2. Надо идти смотреть в код.
еНаИсхождение. Синтаксису не противоречит, перед выполнением все-равно будет заменено и иллюстрирует о чем же условие.
Заменяемый параметр типа &УсловиеСклада более «говорящее» название. Можно писать что угодно, хоть &ТутСложноеУсловиеГдеПроверяетсяВходящиеНаВхождениеАИсходящи
Но и циферками, конечно тоже можно.
Подскажите, как в СКД сделать условное условие «МЕЖДУ &НачалоПериода И &КонецПериода»?
Это все работает когда запрос пишется в модуле . А как быть если мне нужно данное условие засунуть в «ДинамическийСписок» через параметры формы
Пробовал
Пишет ошибку . «Не понимает «?Справочник» «.
Пробовал передать пустое значение «Контрагента» (я по Контрагенту фильтрую) выходит пустой отбор . Подскажите как быть ? как сделать так чтобы условие работало только когда передан Контрагент