Еще один взгляд на проблему "жизнь без последовательностей"




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

22 Comments

  1. Арчибальд

    По-моему, в данном случае математическая модель не проясняет, а маскирует ситуацию. Поскольку никому не нужно складывать булки с отвертками, мы всегда находимся ровно в одном «слое», так что задача линейного программирования (ЗЛП) не более чем двумерна. А с учетом того, что Приход = -Расход, размерность и вовсе единична. Далее, ограничение «приход раньше расхода» на практике несущественно, ибо физически невозможна отгрузка несуществующего товара. Вот документально, даже юридически, она вполне возможна — хоть «задним числом» это назови, хоть «фьючерсным контрактом». И наконец, никакой целевой функции нет, так что это вообще не ЗЛП.

    Reply
  2. kayen

    Интересная модель но к сожалению неприменима к жизни. Как например быть с себестоимостью в рамках конкретного периода?

    Reply
  3. ildarovich
    Reply
  4. tango

    (3) «Таблица — это регистр остатков с измерениями: номенклатура, документ прихода, документ расхода и ресурсом: количество.»

    Таблица — это регистр сведений … без количества, поскольку вводим запись на каждую минимальную единицу учета, т.е. кол == 1

    **

    В измерения кроме Номенклатуры впихнем еще ЗначенияНабораХарактеристикНоменклатуры

    **

    В набор характеристик можно добавить число ЦенаПоступления

    Reply
  5. ildarovich

    (2) Имея актуальную «структуру списания», то есть зная: что, когда и по какому документу приходило, в каком количестве, когда и по какому документу списывалось Вы дальше можете рассчитать что угодно.

    Не хотелось усложнять, но, наверное понятно, что ЛИФО будет отличаться видом целевой функции (разность времен в числителе), при среднем в таблице будет одна строка, при среднемесячном — столько, сколько месяцев и так далее.

    Reply
  6. Арчибальд

    (3) Повеселил 😀

    Вы думаете о проблеме: как вести учет, забыв о последовательностях

    Ничего подобного я не думаю. Я это знаю и делаю. Нет у меня никаких последовательностей, и я прекрасно себя чувствую.

    нам будет выгоднее списывать более ранние партии для конкретного расхода. И вот этот Ваш заветный наилучший способ Вы и найдете, решив ЗЛП

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

    То есть ограничения не допускают никаких, хотя бы секундных «косяков». Метод просто отвергнет очередное изменение, не найдя решения

    Тогда как бухгалтер/менеджер решение легко найдут…

    Можете удивляться или нет

    Меня удивить вряд ли получится 😀

    http://infostart.ru/profile/46936/blog/843/

    Reply
  7. CheBurator

    прочитал бегло… так что не взыщите…

    > То есть нам будет выгоднее списывать более ранние партии для конкретного расхода. И вот этот Ваш заветный наилучший способ …

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

    .. но это все пока написал «на бегу».. в порядке дежурного бреда…

    Reply
  8. ildarovich

    (7) Слово «выгоднее» я употребил для объяснения значения параметров целевой функции. Имелось ввиду, что это требование заставит считать лучшим решение распределения партий «как при списании по ФИФО». Не имелась ввиду динамика наших действий — целевая функция определяет требование к результату, который может быть получен хоть алгоритмом случайного поиска. Про алгоритм «метод потенциала» и его реализацию я вообще не упоминал, считая, что он и так известен. Этот алгоритм довольно мудреный и, если тут еще и его описывать, вообще запутаемся. Просто считаем, что он применяется и таким образом мы переходим от одного разрешенного состояния к другому в направлении оптимума (правильно распределенных партий). Не применяя абстракции от используемого алгоритма поиска оптимального решения, нам потребуется рассматривать отдельно уменьшение прихода, увеличение прихода, уменьшение расхода, увеличение расхода, перестановку приходов, перестановку расходов. А затем просматривать «волну изменений» в «таблице списания». Этого не нужно, если на данном этапе представить алгоритм «метод потенциала» как черный ящик, дающий оптимальное решение. Возьмите хотя бы Эксель и решение транспортной задачи через подбор параметра. Там Вы не видите процесса решения — видите результат.

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

    Reply
  9. Шёпот теней

    … не согласен с :

    «Обозначим номенклатуру i, приход j, расход k. Функция X(i,j,k) »

    почему:

    1. эта функция истинна в случае номенклатура = приходу …

    2. если номенклатура = НЕприход тогда это множество без сортировки …

    3. если мы к п.2. добавляем партии, то номенклатура превращается в двойное множество …

    4. если мы берём лифо-фифо то функции усложняется ещё и сортировкой внутри п.3 …

    5. в связи с усложнённостью функции учитывающей пп. 2,3,4 мы имеем систему охреНительной сложность … а если ещё добавить сложность перекрёстных ссылок (влияние документов друг на друга) — то будет полная амба — типа 1С ….

    … ВОТтакоеМНЕНИЕесть …


    Reply
  10. vuzurp

    Что-то мне непонятно в этой прикладной математике! 😀

    В реальном учете (не виртуальном, не теоретическом!) у «изменения документа задним числом» одна единственная задача — привести все последующие показатели к требуемым величинам. Т.е. переделать движения всех последующих документов!

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

    Механизмы для решения обеих задач существуют. Что нового предлагает обсуждаемая медота?

    Reply
  11. ildarovich

    (10)

    В реальном учете (не виртуальном, не теоретическом!) у «изменения документа задним числом» одна единственная задача — привести все последующие показатели к требуемым величинам. Т.е. переделать движения всех последующих документов!

    Когда Вы говорите «переделать движения всех последующих документов», Вы как-будто подразумеваете, что последующий документ делает движения по регистру партий и что, не перепроводя его, ничего не сделать, поскольку нельзя (или сложно) изменить движения без перепроведения. То есть связываете себя конкретной реализацией партионного учета.

    Я же смотрю на проблему в целом. Что есть регистр партий? — Всего лишь структура для определения того, из какого документа прихода взят конкретный расход (X(i,j,k)). Функция X(i,j,k) может быть реализована как угодно. И рассчитываться не обязательно последовательным проведением документов. В моем предложении — небольшими или большими (если изменение в массиве документов существенное) точечными корректировками dX(i,j,k).

    Другими словами, НЕ переделать ДВИЖЕНИЯ ВСЕХ ПОСЛЕДУЮЩИХ документов, а пересчитать только измененные связи документов, возникшие из-за исходного изменения.

    Механизмы для решения обеих задач существуют. Что нового предлагает обсуждаемая медота?

    Я говорю только о первой задаче. Новое в том, что она сведена к известным оптимизационным задачам. В результате можем использовать готовые хорошо исследованные алгоритмы решения, которые, я, кстати, здесь не описывал, если не все это заметили!

    Кроме того, предлагаемое решение не использует понятие «последовательность».

    Также мне показалось ценным то, что в классе возможных алгоритмов решения определено место стандартного алгоритма 1С, а следовательно — его достоинства и недостатки относительно других методов. В итоге, я и предлагаю осознанно искать лучшие методы, зная, что мы можем выиграть и нужно ли это вообще!

    Reply
  12. phsin

    кажется, для 7.7 это не применимо, т.к. движения можно делать только в модуле документа. а здесь получается придется изменять движения по регистрам обработкой…

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

    хотя с теорией я увы на ВЫ, поэтому так и хочется крикнуть «Пример в студию!» 😉

    Reply
  13. ildarovich

    (12) Понимаю Ваши сомнения. Намеренно хотел уйти от технических подробностей реализации, чтобы взглянуть на корень проблемы.

    Вижу, без примера не все понятно. Пример подготовлю. Нужно какое-то время.

    Reply
  14. phsin

    (13) будем ждать

    Reply
  15. ildarovich

    (12)

    поправьте меня, если я не прав

    Вы не совсем правы. Хитрым способом я предлагаю не восстанавливать последовательность, а корректировать структуру списания X(i,j,k), которая ее заменяет. Привлекается не транспортная логистика, а математически схожая с распределением по партиям задача линейного программирования.

    Reply
  16. bulpi

    Уважаемый автор! Я поставил плюс за новый, свежий взгляд на известные вещи. Но должен Вас предупредить : те самые «готовые хорошо исследованные алгоритмы решения» неприятно удивят Вас своей сходимостью для случая большого количества переменных. Сам пробовал, удивлялся. Теоретически вроде все ОК, а практически до числа довести — фиг!

    Reply
  17. ildarovich

    (16) Большое спасибо. Вы уловили суть дела. Но все же хочу попробовать. В данном случае критерием истины будут результаты практического исследования на задачах реальной размерности. Обнадеживает легко просматриваемое сходство с приемами ускоренного проведения по партиям.

    Reply
  18. hogik

    (0)

    В данной статье меня заинтересовал текст после слов: «…зачем?». Я согласен с каждым утверждением этой части статьи. И попробую дополнить этот текст некоторыми деталями своего понимания задачи.

    1) «…1С …нацеливает решения не на отражение настоящего, а на рисование прошлого.»

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

    2) «Бухгалтер раскладывает на столе первичку и решает: в какой момент произвести списание? Когда товар был подороже или подешевле? Показывать или нет авансы?»

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

    3) «Ну и пусть попробует один вариант, восстановит последовательность (пересчитает себестоимость), подождет.»

    — Т.к. данные этого расчета (например, себестоимости) никак не влияют на «отражение настоящего», то не имеет смысла хранить эти расчеты в базе данных в момент «восстановления последовательности» прошлого периода. И, тем более не имеет смысла, нагружать систему лишней работой в момент отражения настоящего (проведение документов текущего периода). Т.е. «себестоимость» надо не пересчитывать, а считать всегда заново после перестановки документов (см. пункт #5).

    4) «Вам хочется, чтобы это делалось максимально быстро? … Раз в месяц, раз в квартал — компьютер не перетрудится!»

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

    5) «… эта задача «рисования прошлого» … не требует высокой скорости расчетов.»

    — Сам расчет существует всегда. А быстро он выполняется, если в процессе расчета не делается перепроведение документов. Т.е. документы расставлены в соответствии с пунктом #2, а окончательные цифирьки рассчитываются и выводятся отчетом. И не хранятся в базе данных!

    Reply
  19. hansel

    (0) Как говорят англоязычные коллеги: if you are so clever, show me your money.

    Переводя с «ихнего», и адаптируя к сути Вашей статьи: если Вы такой умный, нам код работающий покажите.

    Сразу PS: Не сочтите реплику за неуважение. Будет практический результат Ваших идей — обсудим, а так — мутно всё это.

    Reply
  20. ildarovich

    (19) Будет сделано.

    Reply
  21. quick

    Интересная идея по поводу того что можно проверять приход за весь период с сравнивать его с предполагаемым расходом. А если без дельта и т.д. напрямую?

    Приход = ПолучитьПриходЗаВесьПериод();

    РасчетныйРасход = ПолучитьРасходЗаВесьПериод + КолвоСписать;

    Если Приход — РасчетныйРасход < 0 Тогда

    Сообщить(«Списание в минус»);

    Подумать только как бы общий расход приход хранить для быстрого расчета.

    Reply
  22. ildarovich

    (12)(16)(19) В статье http://infostart.ru/public/74343/ описывается практическая реализация данного метода, приводятся: тестовая конфигурация, программный код, оценки быстродействия.

    Reply

Leave a Comment

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