Автоматизация заполнения документа "Возврат товаров от покупателя" в УТ 10.3




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

5 Comments

  1. Re:аниматор

    Ни чего не запрещает продавцу добавить товар через подбор и указать любое кол-во.

    У себя решил эту проблему через контроль возвращаемого товара при проведении документа по регистру накопления «Продажи».

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

    часть кода

    Запрос = Новый Запрос;
    Запрос.Текст = «ВЫБРАТЬ РАЗРЕШЕННЫЕ
    | ПродажиОбороты.Номенклатура,
    | ПродажиОбороты.Качество,
    | СУММА(ПродажиОбороты.КоличествоОборот) КАК Количество
    |ИЗ
    | РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, , ДокументПродажи = &ДокументПродажи) КАК ПродажиОбороты
    |ГДЕ
    | ПродажиОбороты.Номенклатура = &Номенклатура
    | И ПродажиОбороты.Качество = &Качество
    |
    |СГРУППИРОВАТЬ ПО
    | ПродажиОбороты.Номенклатура,
    | ПродажиОбороты.Качество»;
    Запрос.УстановитьПараметр(«ДатаНач», СтрокаТаблицы.ДокументПартии.Дата);
    Запрос.УстановитьПараметр(«ДатаКон», ДокументОбъект.МоментВремени());
    Запрос.УстановитьПараметр(«ДокументПродажи», СтрокаТаблицы.ДокументПартии);
    Запрос.УстановитьПараметр(«Номенклатура», СтрокаТаблицы.Номенклатура);
    Запрос.УстановитьПараметр(«Качество», СтрокаТаблицы.Качество);
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
    КоличествоПродажа = КоличествоПродажа + Выборка.Количество;
    КонецЦикла;
    
    Если СтрокаТаблицы.КоличествоДок > КоличествоПродажа Тогда
    СтрокаСообщенияОбОшибке = СтрокаНачалаСообщенияОбОшибке + «количество превышает количество продажи. » + »
    |  Номенклатура: » + СтрокаТаблицы.Номенклатура + «, партия: » + СтрокаТаблицы.ДокументПартии + «, продано » + КоличествоПродажа + «, возврат: » + СтрокаТаблицы.КоличествоДок;
    ЗаписьЖурналаРегистрации(«Возврат товаров от покупателя. Превышение количества», УровеньЖурналаРегистрации.Ошибка, ДокументОбъект.Ссылка.Метаданные(), ДокументОбъект.Ссылка, СтрокаСообщенияОбОшибке);
    ОбщегоНазначения.СообщитьОбОшибке(СтрокаСообщенияОбОшибке, Отказ, Заголовок);
    КонецЕсли;
    
    

    Показать

    Reply
  2. splitter01

    (1) Re:аниматор, Верное замечание. На данный момент проблема уже устранена. Но в Вашем предложении не учитываются ранее возвращенные товары. В ближайшее время исправлю публикацию. И еще: в Вашем варианте рассмотрите ситуацию, когда было продано 2 холодильника и 1 пылесос, а в документе возврата указать 2 пылесоса и 1 холодильник.

    Reply
  3. Re:аниматор

    (2)

    Но в Вашем предложении не учитываются ранее возвращенные товары.

    Вообще то учитываются ранее возвращенные товары. Возврат делает записи в регистр «Продажи» со знаком «-«, СУММА(ПродажиОбороты.КоличествоОборот) это учтется в суммировании


    И еще: в Вашем варианте рассмотрите ситуацию, когда было продано 2 холодильника и 1 пылесос, а в документе возврата указать 2 пылесоса и 1 холодильник.

    Разрешит сделать возврат только на 1 холоднильник, т.к. пылесоса продано 1

    А для чего рассмотреть данную ситуацию?

    Reply
  4. V.Nikonov

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

    При первичном заполнении документа возврата обычно используется Подбор по справочнику, при этом не заполняются данные по Себестоимости…

    Добавил обработку Табличных частей, которая анализировала продажи (с учетом проведенных возвратов) за период (например, 3 мес.). При необходимости разбивала строку на несколько строк под каждую отгрузку (Учет по Заказам и Заказ=Реализация). При необходимости снимались ограничения по Договорам и добавлялся период анализа. Найденные отгрузки использовались как ПартиеОбразующие документы, использовались для определения Цены возвращаемого товара и становилось видны попытки вернуть «НеОтгруженный товар». Возможно отгружались двойники номенклатуры…

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

    Обработка позволяла при необходимости повторить распределение по отгрузкам,предварительно свернув строки по Номенклатуре (очистив документы партий). Дополнительно Обработка печатала отчет по сформированному распределению (практиковалась корректировка «свежих Реализаций»).

    Кстати, добавил проверку перед записью: наличие нужного товара в заявленных документах партий…

    Reply
  5. white-mount

    Возвратом товаров обычно занимается не продавец, а менеджер, имеющий выше полномочия. Это всегда чп. Либо дефект, либо пересортица — продано не то. Для маленькой фирмы предложенный механизм подходит, для крупной нет.

    Reply

Leave a Comment

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