Автоматическое создание заказов поставщику по статистическим данным продаж в 1С 7.7 ТиС




Принцип обмена данными из 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='\

24 Comments

  1. Lada385

    Отличная вещь! Говорю спасибо!

    Reply
  2. maskva

    Хотели попробовать и вот:

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда

    {C:1С_БАЗАDB0EXTFORMSPRNFORMSИНФО_ПЛАНИРОВАНИЕЗАКУПОК.ERT(1788)}: Регистр.Продажи.ТекущийДокумент.Сторно. <<?>> Контрагент,

    Запрос[20] : Неверно заданный путь ‘Контрагент’

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда

    {C:1С_БАЗАDB0EXTFORMSPRNFORMSИНФО_ПЛАНИРОВАНИЕЗАКУПОК.ERT(1788)}: Условие (Фирма в ВыбРазделитель1 <<?>> );

    Запрос[38] : Ошибка в условии

    Обработку просто скопировали в базу и открыли.

    Reply
  3. maskva

    А, ну и вкладка «Таблица анализа номенклатуры» не открывается совсем.

    Reply
  4. sonic112

    Здравствуйте!

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

    Регистр.Продажи.ТекущийДокумент.Сторно.СторнируемыйДокумент.Контрагент, но нужно проверить, возможно, что не все сторнированные документы в вашей базе имеют реквизит «Контрагент».

    2. Закладка «Таблица анализа номенклатуры» до проведения расчета пустая, она вам не нужна. После проведения расчета, доступ откроется. Сделано это для того, чтобы операции с пустой таблицей не приводили к ошибкам. Это сделать проще, чем при каждом действии с таблицей проверять ее заполненность.

    3. Сообщение об ошибке в условии скорее всего наведенная ошибка, условие стандартное в 1С ТиС.

    Будут еще вопросы, — пишите.

    Reply
  5. Самоделкин

    Хорошая обработка.

    Строку Регистр.Продажи.ТекущийДокумент.Сторно. закоментировал, все работает.

    Reply
  6. Самоделкин

    (4) sonic112, что считает немного не так: отчет беру с 1.01 по сегодня, у меня есть товар, который был закуплен в январе, в начале февраля продан и закуплен по новой, в конце февраля продан и до настоящего времени не закуплен, в Вашем отчете выдает, что его нет в наличии и в заказ он не попадает, по мне должна быть хотя бы 1, а то получается товара нет и не надо.

    Reply
  7. sonic112

    Не имея базы сложно сказать, что конкретно у вас работает не так. Могу посоветовать, где искать.

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

    2. Остаток считается по регистру «ПартииНаличие». Этот же регистр используется в стандартных отчетах 1С, например, «Ведомость по партиям ТМЦ». Попробуйте сформировать этот отчет, если там остаток будет, повторите настройки отчета для обработки. Расхождений быть не должно, так как запрос, по сути, одинаковый.

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

    4. Проверьте наличие записей в нужных регистрах по вашим документам отчетом «Отчет о движениях документа».

    Если ничего не поможет, нужно более подробное описание: какой документ, какие настройки и т.д.

    Пишите.

    Reply
  8. vita55555

    Автору спасибо!

    Есть вопрос:

    В Шапке сказано:

    »

    чтобы заказ, поставленный в установленные сроки, обеспечил наличие товара до следующей поставки

    «


    я так понимаю, что в форме обработки:

    есть поле: Период закупок

    где первая дата = «…поставленный в установленные сроки..», т.е. дата Текущей поставки над которой работаем \r

    и где второя дата =»..обеспечил наличие товара до следующей поставки …», т.е. Планируемая дата следующей Поставки.

    Правильно ?

    Reply
  9. sonic112

    Здравствуйте!

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

    1. До даты начала периода закупок учитываются заказы поставщикам, еще не поступившие на склад.

    2. До даты конца периода закупок учитываются заявки покупателей, которые предполагается отгрузить.

    3. Программа не проверяет возможный недостаток товара до даты начала закупок.

    Reply
  10. vita55555

    Спасибо за ответ!

    Еще есть вопрос:

    1)

    есть колонки — Снижение продаж из-за отсутствия товара.

    Я так понимаю, это снижение рассчитывается за период с даты поставки текущего заказа и до даты поставки следующего заказа, если не будет текущей поставки,

    Т.к.Правильно?

    2) А можно ли как из отчета узнать — сколько за прошлые периоды уже потеряно из-за ситуация отсутствия товара ?

    Сколько например длилась в днях эта ситуация ?

    Reply
  11. sonic112

    Здравствуйте!

    1. Неправильно. Снижение продаж за счет отсутствия товара считается по периоду анализа, а не по периоду закупок. Это естественно, так как только в периоде анализа нам известно количество дней, когда товар на складе отсутствовал. В периоде закупок мы должны обеспечить наличие товара, там пропусков товара в наличии быть не должно. Снижение продаж считается как произведение средней скорости продаж на число дней отсутствия товара на складе.

    2. Можно, включив интересующий вас период в период анализа. Число дней отсутствия товара на складе = Число рабочих дней в периоде анализа — Число дней нахождения товара на складе.

    Reply
  12. ipbilalova@mail.ru

    ПОДСКАЖИТЕ, ПОЖАЛУЙСТА ЧТО ДЕЛАТЬ!!!

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда

    {C:USERSADMINISTRATORDESKTOPINFO.PLANIROVANIEZAKUPOK1.ERT(1841)}: Регистр.Продажи.ТекущийДокумент.Сторно. <<?>> Контрагент,

    Запрос[20] : Неверно заданный путь ‘Контрагент’

    Reply
  13. sonic112

    Здравствуйте!

    Это обсуждалось в сообщении №4:

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

    Регистр.Продажи.ТекущийДокумент.Сторно.СторнируемыйДокумент.Контрагент, но нужно проверить, возможно, что не все сторнированные документы в вашей базе имеют реквизит «Контрагент».

    Reply
  14. svoiludi.8

    Добрый день!

    Для 1С 8.3 есть такое приложение?

    Reply
  15. sonic112

    Нет.

    Reply
  16. N2

    (15) Вадим, добрый день!

    Подскажите пожалуйста, можно ли данной обработкой разбивать заказы по поставщикам?

    И чем отличаются обработки Инфо_ПланированиеЗакупок.ert и Инфо_ПланированиеЗакупок1.ert ?

    Reply
  17. sonic112

    Добрый день!

    Да, разбивка заказов по поставщикам идет. Поставщик определяется как последний поставщик данной номенклатуры.

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

    Reply
  18. N2

    (17) Вадим, а есть возможность сформировать заказ не от номенклатуры, а от поставщика? Т.е. помимо отбора по продажам, делать отбор по приходам за определенный период, либо где-то хранить, что Номенклатура1 может приходить от Контрагент1 и Контрагент2, а уже при формировании заказа выбирать, что заказ формируется для Контрагента1? Или данный вопрос уже за пределами Вашего решения и требует доработки штатных механизмов ТиСа? Т.е. нужно где-то хранить прайс-листы например для Контрагента1 с определенным реестром номенклатуры и уже с этим реестром делать отбор по продажам за период. Не подскажите, такие механизмы в ТиСе есть?

    p.s. Понимаю, что вопросы немного глупые, т.к. не очень сильно знаком с ТиСом.

    Reply
  19. sonic112

    Отбор есть по последнему поставщику, по свойствам номенклатуры, по основному свойству номенклатуры, и т.д. — полный список отбора можно посмотреть на странице «Множественный фильтр». Можно присвоить свойству номенклатуры наименование контрагента и проводить отбор по этим свойствам, т.е. Номенклатура может иметь свойство Контрагент1 и Контрагент2, при выборе этих свойств в таблице останется номенклатура, у которой есть такие свойства. Если нужен отбор, не упомянутый в списке, — нужно дорабатывать программу.

    Сделать один заказ можно при установке флага «Объединить заказы поставщикам в один заказ».

    Reply
  20. N2

    (19) Вадим, подскажите пожалуйста, я правильно понял, что у номенклатуры может быть несколько свойств? Т.е. «Номенклатура1», может иметь два свойства «Контрагент1» и «Контрагент2»? Т.е. если не реализовывать прайс-листы, то можно при поступлении «Номенклатуры1» допустим от «Контрагента3», добавлять ещё одно свойство «Контрагент3». Подведу итог: у номенклатуры в ТиСе может быть несколько свойств?

    Reply
  21. sonic112

    Да, свойств может быть много, основное свойство одно.

    Reply
  22. N2

    (21) хорошо, спасибо!

    Reply
  23. stas919

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда

    {C:DOWN1С77027БАЗАEXTFORMSИНФО_ПЛАНИРОВАНИЕЗАКУПОК1.ERT(1841)}: Регистр.Продажи.ТекущийДокумент.Сторно. <<?>> Контрагент,

    Запрос[20] : Неверно заданный путь ‘Контрагент’

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда

    {C:DOWN1С77027БАЗАEXTFORMSИНФО_ПЛАНИРОВАНИЕЗАКУПОК1.ERT(1841)}: Условие (Фирма в ВыбРазделитель1 <<?>> );Условие (Номенклатура в ВыбТМЦ);

    Запрос[38] : Ошибка в условии

    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда

    {C:DOWN1С77027БАЗАEXTFORMSИНФО_ПЛАНИРОВАНИЕЗАКУПОК1.ERT(1841)}: Условие (Фирма в ВыбРазделитель1);Условие (Номенклатура в ВыбТМЦ <<?>> );

    Запрос[38] : Ошибка в условии

    Reply
  24. sonic112

    Здравствуйте!

    Это обсуждалось в сообщении №4:

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

    Регистр.Продажи.ТекущийДокумент.Сторно.СторнируемыйДокумент.Контрагент, но нужно проверить, возможно, что не все сторнированные документы в вашей базе имеют реквизит «Контрагент».

    Остальные ошибки, по-видимому, наведенные, так как являются стандартными для ТиС.

    Reply

Leave a Comment

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