<?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='\
Автор честно скажу сам не люблю когда кто то умничает но прими мои комментарии не лично к себе а коду.
Не спорю «код читаем», но «не понимаем».
1. У меня сомнения что код вообще выполнится ибо вряд ли у поля ПоступлениеТоваровУслугТовары.Ссылка.Дата тип Булево
2. При желании в выборку не попадают дубли, для этого используются разные способы (к примеру сгруппировать)
3. Стоило бы понимать почему регистр отказывается делать записи с одинаковой номенклатурой
никаких сомнений не остается после такого кода база действительно станет ‘ «запущеной» и базы’
4. Есть предложение именовать регистры словами и выражениями отражающими суть данного регистра, потому «ЦеныЗакупаАнадо» — вызывает сомнения действительно А НАДО ли ? И последнее, надеюсь никому этот код не пригодится разве что для наглядного пособия как не нужно делать.
вот запрос который сделает сам то что ты писал в коде тебе останется только передать в него:
1) две Даты(Дата1 — дата начала и ДАта2 дата окончания)
2) Записать результаты в регистр уже без всяких условий и проверок
|ВЫБРАТЬ
| ПоступлениеТоваровУслугТовары.Ссылка.Дата КАК Дата,
| ПоступлениеТоваровУслугТовары.Номенклатура КАК Номенклатура,
| МАКСИМУМ(ПоступлениеТоваровУслугТовары.Цена) КАК Цена
|ИЗ
| Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
|ГДЕ
| ПоступлениеТоваровУслугТовары.Ссылка.Проведен = ИСТИНА
| И ПоступлениеТоваровУслугТовары.Ссылка.Дата МЕЖДУ &Дата1 И &Дата2
| И ПоступлениеТоваровУслугТовары.Номенклатура.ТипНоменклатуры <> ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Услуга)
| И ПоступлениеТоваровУслугТовары.Номенклатура <> ЗНАЧЕНИЕ(Справочник.Номенклатура.пустаяссылка)
|
|СГРУППИРОВАТЬ ПО
| ПоступлениеТоваровУслугТовары.Номенклатура,
| ПоступлениеТоваровУслугТовары.Ссылка.Дата
|
|УПОРЯДОЧИТЬ ПО
| Дата,
| Номенклатура
ну и немного по логике работы : может в регистр стоит добавить также поставщика ? а то выяснится что минимальная цена закупки на такую то дату равна «X», а какого поставщика цена останется неизвестным… И мне так кажется что УТ 11 умеет сама делать эти штуки и настройка называется регистрировать цены поставщиков…..
(1) sanek_gk,
— насколько я понял это проблема платформы, но с вами согласен не мешало бы разобраться и попинать 1С
(1) sanek_gk,
вот запрос который сделает сам то что ты писал в коде тебе останется только передать в него:
1) две Даты(Дата1 — дата начала и ДАта2 дата окончания)
Ваш пример не учитывает того, что Дата1=ДАта2, значит в регистр уйдет все тоже самое что и уходит в типовой, но тогда при регистрации цены поставщика (вы об этом тоже писали)- цена не привяжется, так как в регистре будет несколько цен и 1С тупо не поймет какую брать. Это кстати один из косяков почему неправильно считается себестоимость — так что вопрос «а надо ли это?» очень актуален.
P.S. АНАДО это название организации. По вопросам каламбура — смысл вложенный в названия фирмы: «А Надо!»
(0) anado,
Тут, видимо, полагался вопрос. Тогда вопрос встречный: из какой выборки? Выборка из результата запроса? Тогда просто запрос нужно составить так, чтобы не осталось дублей, то есть «ЗАПРОСОМ УДАЛИТЬ ДУБЛИ!». Если выборка это СправочникВыборка или ДокументВыборка (или прочее), то это отдельная история.
(1) sanek_gk,
человек писал статью в пятницу вечером. Вместе с тем, что в запрос передается лишний параметр — понятно, что кусок строки из запроса просто отрезан.
Тем не менее, согласен, что приведенный код для данной задачи совершенно неприемлем. Конечно, нужно использовать правильно написанный запрос. И обойтись без цикла, например, что-то типа
Да стоило бы понимать вообще что ты делаешь. И что уже сделали до тебя (и для тебя в том числе). Тогда вместо изобретания велосипеда можно будет на нем сразу кататься.
а что именно не понятно?
в данном коде есть прием, который как раз таки может пригодиться. Не часто, но может.
(На всякий случай поясню, что прием этот — сравнение с текущей номенклатурой на каждом шаге, и действие только в случае отличия от нужной.)
(3) anado,
это не «проблема» платформы, а суть понятия «измерение» для регистра сведений (да и не только сведений).
В каком смысле «попинать»? В смысле разобраться как работает 1С? Или в смысле научить фирму 1С, что в регистр можно складывать неоднозначные записи? 0_0
(5) ShantinTD,
В том смысле что 1с умеет складывать в регистр «неоднозначные» записи, а потом сама же не может их использовать. То есть напрашиваются решения: или 1С не должна складывать «неоднозначные» записи в регистр; или уметь использовать «неоднозначные» записи. Иначе, действительно не нужно было бы изобретать велосипед.
P.S. Кстати Автор статьи и кода не я — мы просто вместе над одной проблемой работаем.
(6) anado, конкретно к Вашему посту я ответил на «насколько я понял».
Про неоднозначные записи заинтриговал. Можно увидеть пример, как сложить в регистр неоднозначные записи? Ну и как их потом пытаться использовать тоже? Без примера — «не верю!» ((с) К.С. Станиславский)
(1) sanek_gk, Дополню: в запросе надо брать не Ссылка.Дата, а началопериода(ссылка.дата, <периодичность регистра>
Спасибо всем за комментарии в статье. Были запарки дома и на работе, прошу простить за запоздалый ответ.
(1) sanek_gk, вы написали замечательный запрос, однако мне нужны были несколько иные данные. Как верно тут написал ShantinTD —
(На всякий случай поясню, что прием этот — сравнение с текущей номенклатурой на каждом шаге, и действие только в случае отличия от нужной.)
Еще раз и более подробно, я при помощи обработки заливаю данные во вспомогательный регистр сведений — независимый, с периодом в одну секунду. Дальше я могу оттуда дергать куда угодно нужные мне данные, используя — СрезПоследних() и СрезПервых(). На то и регистры, чтобы оттуда брать данные.
(5) ShantinTD, ага, вы совершенно верно поняли про текущую номенклатуру на каждом шаге, и с вашей идеей о том что циклы вредят производительности и что все нужно получать одним запросом нельзя не согласиться. Вы даже начали писать сам запрос, хотелось бы увидеть такой запрос, который бы решал эту задачу. Я это в разумные сроки придумать не смог.
Да, параметр, который передается в процедуру он не лишний. Мне нужно было чтобы в регистр не улетели не проверенные данные. Например по 1 ноября, в базе все данные проверены и соответствуют, а дальше может быть и лажа. Так вот, чтобы лажа не летела в регистр, этот параметр Дата и ограничивает дату документов по времени.
Я на это каким образом смотрю, если перед программистом встала задача, которую он с налету решить не смог (конец недели, конец дня, человек начал немного тупить)и программист полез гуглить, нашел чужой код, понял его, свои мысли в голову пришли, написал свой код, решил задачу. Я как раз для подобных ситуаций написал статью.
Что касается родного регистра ЦеныНоменклатуры. У этого регистра штатно установлена периодичность в пределах дня. Я изменял период на в пределах секунды на УТ 11.0, все нормально было, сейчас УТ 11.1, есть вероятность что изменения периодичности может сломать логику программы. Тут так просто нельзя, надо тестировать. Как я уже писал, в приходной накладной от поставщиков есть одни и те же товары по разным ценам. Эта специфика бизнеса не укладывается в логику УТ 11. Так бывает.
(9) Petr54-ru,
глядя на запрос из (0) так не скажешь. В запрос нужно вернуть выпавший кусок текста (собственно параметр в тексте запроса).
да его передо мной уже написал sanek_gk в (1).
тогда не совсем понимаю, чем приведенный в (1) запрос не попадает под Вашу задачу.
Вам предложили воспользоваться регистром ЦеныНоменклатурыПоставщиков, а у него периодичность в пределах секунды.
из результата запроса можно получить выборку, а можно — выгрузку. Выгрузка может быть таблицей или деревом. И набор записей регистра — тоже таблица. Улавливаете? Зачем переписывать от руки, если можно сделать ксерокопию?
У меня под руками УТ11.1.2.16 Базовая (не думаю, что в этом вопросе это критично), у регистра ЦеныНоменклатуры периодичность в пределах секунды.
согласен, бывают ситуации, когда грамотное решение требует слишком много времени, тщательной проработки или еще чего-то, то делаешь «аварийное» решение, потом переделываешь нормально. И нужно разделять «проблемы» на технические (не можешь написать хороший запрос и выгрузить его результат в набор записей — пишешь запрос попроще и заталкиваешь в регистр поштучно) и концептуальные («что и куда я буду записывать?»). В решении технических проблем, конечно, гугл поможет, а вот концептуальных — далеко не всегда. Но и тут не нужно торопиться изобретать велосипед: есть Библиотека Стандартных Подсистем, есть типовые конфигурации, есть рекомендации, есть глобальные концепции. Так что вполне может найтись почти подходящий велосипед, к которому придется прикрутить свои колеса.
(4) anado, в запросе выражение «между» означает проверку на вхождение и равенство границам интервала. Т.Е. дата1 и дата2 могут запросто быть равны друг другу, и записи всё равно в запросе будут отобраны верно. По поводу того почему не пишутся одинаковые записи Период,Номенклатура — дело в том что в 1с Измерения не могут дублироваться в регистре сведений, так как записью считается именно пересечение указанных Измерений (ну и + значение Периода к измерениям — раз уж регистр периодический) платформа и ругается на неоднозначные записи, что в принципе логично и правильно. Ничего в запросе исправлять под описанную задачу не надо, так как он точно соответствует описанию задачи и приведенному примером коду. Единственное наводит на мысли, а правильно ли вообще в пределах секунды фиксировать записи, по мне так я бы предложил фиксировать одну запись в день (в настройках регистра «В пределах дня») потому что максимум в пределах секунды это не максимум в пределах дня + записей будет на порядок меньше(примерно во столько раз сколько документов поступления в день). В запросе я не задавал никаких новых правил алгоритма,я просто избавился от необходимости проверки на дубли потому что их там не будет. По поводу себестоимости могу сказать следующее : там все считает нормально так как определителем партии практически всегда выступает документ из чего следует что себестоимость единицы Номенклатура1 = (Сумма Сумм этих номенклатур)/(Сумма количества этих номенклатур).
(11) sanek_gk,
это если задача описана правильно.
да это и не только в 1С. Просто называться оно может по другому (например — ключевое поле). Тут хочется или увидеть как anado складывает (успешно складывает) в регистр неоднозначные записи, или увидеть понимание, что это не 1С нужно попинать, а подучить матчасть.
(10) ShantinTD,
Вернул, спасибо за замечание не заметил.
Строчка выпала, когда я делал «подсветку синтаксиса» кода
Обсуждение идет уже 5 день, а в статье текст запроса кривой.
| И ПоступлениеТоваровУслугТовары.Ссылка.Дата | И ПоступлениеТоваровУслугТовары.Номенклатура.ТипНоменклатуры <> &ТипНоменклатуры
Как понять этот кусок, как неуважение к читателям. Типа мое дело прокукарекать, а там хоть и не рассветай.
Теперь о самой статье. Не совсем понятна решаемая задача, а от поставленной задачи зависит и алгоритм решения. Само решение тоже не понятно. Каждый раз перезаполнять весь регистр ???
А если в базе документы за последние 5 лет и в день приходов не один десяток.
Сюда принято выкладывать решения, которые обладают какой-либо универсальностью. А данное решение очень узкое и совсем не оптимальное.
По этому поводу хорошо сказал М.М. Жванецкий: «Писать как и писать нужно когда уже не можешь.
(14) AleksSF,
Прошу прощенья, в статье было написано
Что конкретно не понятно?
(15) Petr54-ru,
В том то и дело, что однократно, а здесь место для решений которые обладают хоть какой-то универсальностью.
У на у всех есть не одна сотня куском кода для решения частных задач. Если мы все это будем сюда выкладывать, то Инфостарт за полгода вырастет как на дрожжах. И пользователям чтобы найти нужную информацию придется просмотреть не одну сотню нашего флуда на тему, а кто лучше посчитал факториал.
(16) AleksSF,
У на у всех есть не одна сотня куском кода для решения частных задач. Если мы все это будем
Есть философский вопрос — A что делать с «убитой» базой? Быстро вытащить оттуда нужные для управленческого учета данные и стартануть в новой базе, тщательно контролируя и организуя работу пользователей или убивать время на восстановление работоспособности старой «убитой» базы? В ряде случаев первый вариант предпочтительней.
С другой стороны, я искал в гугле реализацию исключения дублей по двум полям, что и написано в заголовке статьи, не нашел ничего. Теперь это в сети есть.
Спасибо
Привет! А попробуй так?
ТекстЗапроса = «ВЫБРАТЬ
| ПоступлениеТоваровУслугТовары.Номенклатура,
| ПоступлениеТоваровУслугТовары.Ссылка,
| ПоступлениеТоваровУслугТовары.Цена
|ПОМЕСТИТЬ втДоки
|ИЗ
| Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
|ГДЕ
| ПоступлениеТоваровУслугТовары.Ссылка.Проведен
| И ПоступлениеТоваровУслугТовары.Номенклатура.ВидНоменклатуры.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Услуга)
| И ПоступлениеТоваровУслугТовары.Ссылка.Дата <= &НашаДата
|
|СГРУППИРОВАТЬ ПО
| ПоступлениеТоваровУслугТовары.Номенклатура,
| ПоступлениеТоваровУслугТовары.Ссылка,
| ПоступлениеТоваровУслугТовары.Цена
|;
|
|ВЫБРАТЬ
| втДокНом.Номенклатура,
| втДокНом.Ссылка
|ПОМЕСТИТЬ втДокНом
|ИЗ
| втДоки КАК втДокНом
|
|СГРУППИРОВАТЬ ПО
| втДокНом.Номенклатура,
| втДокНом.Ссылка
|;
|
|ВЫБРАТЬ
| втДокНом.Номенклатура,
| втДокНом.Ссылка,
| втДоки.Цена,
| втДокНом.Ссылка.Дата КАК Период
|ИЗ
| втДокНом КАК втДокНом
| ЛЕВОЕ СОЕДИНЕНИЕ втДоки КАК втДоки
| ПО втДокНом.Номенклатура = втДоки.Номенклатура
| И втДокНом.Ссылка = втДоки.Ссылка
| И (втДоки.Цена В
| (ВЫБРАТЬ ПЕРВЫЕ 1
| втДоки2.Цена
| ИЗ
| втДоки КАК втДоки2
| ГДЕ
| втДоки2.Номенклатура = втДокНом.Номенклатура
| И втДоки2.Ссылка = втДокНом.Ссылка
| УПОРЯДОЧИТЬ ПО
| втДоки2.Цена УБЫВ))»;
Запрос = Новый Запрос;
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр(«НашаДата», НашаДата);
НаборЗаписей = РегистрыСведений.ЦеныЗакупаАнадо.СоздатьНаборЗаписей();
НаборЗаписей.Загрузить(Запрос.Выполнить().Выгрузить());
НаборЗаписей.Записать();
Спасибо, помоголо очень)
Я понимаю, что это было квартал назад, но все равно спасибо, вам! Читая как вы на полном серьезе пишете:
очень сильно поднимается самооценка! Еще раз спасибо! Вы лучшие, продолжайте радовать своими «креативами»
Неплохая версия запроса, а если попробовать ЧЕРЕЗ «Объединить» две таблицы, чтобы свернуть одинаковые поля!
мда вот у меня цель сохранить порядок записей при этом искючить дубли