Расчет оборачиваемости дебиторской задолженности




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

14 Comments

  1. big60

    Идея хорошая. В нашей организации давно витала в воздухе идея учёта этого показателя. Только я, с Вашего позволения, немножко переделаю. Расчёт буду производить по формуле: отношение объёма продаж к средневзвешенному (а не к среднему) размеру дебиторской задолженности. Сложнее, зато точнее. Ведь начальная сумма деб. задолженности может быть погашена на следующий день, а конечная может возникнуть за день до окончания периода.

    И ещё параллельно можно рассчитывать среднее число дней для сбора долгов. Оно равно числу дней в периоде делённому на оборачиваемость деб. задолженности в этом периоде. Обычно рассчитывается за год.

    В общем наговорил много, а самого главного не сказал: плюс однозначно.

    Reply
  2. Sk0rp

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

    Reply
  3. rdm

    Спасибо, полезная штучка…

    +

    Reply
  4. anig99

    (2) Использование таких простых формул средних показателей в экономике — наследие времен ручных расчетов. Современные технологии позволяют делать намного более точные расчеты, так как времени для этого на компьютере затрачивается капля. В данном случае можно было не писать отчет….А сделать всё в екселе…

    Нужно думать, а не повторять, тем более формулы, которые даже в СТАРЫХ учебниках по эк.теории, эконометрики и статистики указаны как простейшие и очень грубые.

    Reply
  5. Sk0rp

    (4) Грубость не в формулах, а в используемых приближениях. Так в теории среднее для расчета коэффициентов оборачиваемости надо считать так:



    X1 / 2 + X2 + … + Xn / 2

    ——————————

    n — 1



    где n — количество отрезков, на которые делится анализируемый период, чем больше — тем точнее. А в наиболее часто применяемом приближении n берут равным 2 независимо от периода. Т.е. проблема не в формуле.

    Период оборачиваемости имеет следующий экономический смысл — за какой период продается количество товара равное среднему остатку. А вот если вместо среднего взять средневзвешенное это будет число с туманным экономическим смыслом.

    Reply
  6. anig99

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

    Средневзвешенные показатели хороши для сравнения. В моей статье по дебиторке это расписано. У среднего показателя экономический смысл может и есть… Но с практической точки зрения — нет. Один этот показатель нам ничего не даёт. Он даст какую-то информацию только в сравнении с другими периодами или точками/складами. А в этом случае средневзвешенные показатели всё-таки лучше.

    Полезность показателя должна быть не в простоте объяснения, чем он по сути является, а в применимости его для контроля за текущей ситуацией (скорее всего в комплексе с другими показателями)

    Ещё один пример непростого для понимания, но широко используемого в практике показателя — тонно километр…

    Reply
  7. climepost

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

    Пусть у нас n периодов. Тогда можно взять

    с 1-го периода по n конечные остатки,

    с 1 по n остатки начальные,

    1 – начальные, а со 2 по n конечные,

    с 1 по n-1 начальные, n – конечные,

    с 0 по n конечные,

    с 1 по n+1 начальные.

    Какую из формул считать правильной?

    Reply
  8. Sk0rp

    (7) Брать конечные или начальные абсолютно без разницы, т.к. конечный одного периода, это начальный следующего, а начальный и конечный остатки всего периода анализа в любом случае брать надо.

    Т.е., к примеру, если анализируем 3 дня и бьем на куски по одному дню: Надо взять

    X1 — начальный остаток 1-го дня

    X2 — конечный остаток 1-го дня или начальный 2-го (пофиг, ибо равны)

    X3 — конечный остаток 2-го дня или начальный 3-го (пофиг, ибо равны)

    X4 — конечный последнего дня

    n = 4, т.е. среднее = (X1/2 + X2 +X3 + X4/2) / 3

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

    Единственное дополнение к формуле которое я использую, это не суммирую нулевые значения, — но это для оборачиваемости товаров. Для расчета оборачиваемости дебиторки или кредиторки возможно этого делать не стоит.

    И, кстати, говоря о средневзвешенных значениях, не указывать по какому параметру надо взвешивать — это беспредметно.

    Reply
  9. galauto_oxy

    у меня почему-то не работает выбор покупателя. вместо этого выбор только по группе «ценные бумаги». зашла в конфигуратор, поменяла в модуле счет 62 (векселя) на 36 (покупатели).

    выбор работает но отчет не формирует — все пусто.

    помогите.

    спасибо

    Reply
  10. climepost

    (9) Посмотрите в плане счетов у сч.36 есть субконто? Оно (одно из них) называется Контрагенты?

    Откройте конфигуратор, выберите пункт меню Конфигурация — Открыть конфигурацию. В дереве метаданных откройте ветвь «Планы счетов», два раза щелкните на пункте Основной. Посмотрите, какой(ие) вид субконто значится у счета 36? Запомните его название. В дереве метаданных откройте ветвь «Виды субконто», найдите субконто, приписанное к сч.36, щелкните на него два раза, в форме Свойства посмотрите тип значения этого субконто. Если справочник называется не «Контрагенты», то вам надо будет в модуле отчета заменить и это слово на название вашего справочника.

    Или сделайте проще: в строке ТЗ.НоваяКолонка(«Наим»,»Справочник.Контрагенты»); удалите .Контрагенты.

    Reply
  11. galauto_oxy

    Спасибо, убрала в строке ТЗ.НоваяКолонка («Наим»,»Справочник.Контрагенты»); значение .Контрагенты.

    заработало.

    спасибо огромное.

    еще вопрос: в сформированной таблице колонки «продажи» не заполняются.

    и если выбирать несколько контагентов, то в колонке «оборачиваемость, дней» — показивает только общия показатель в строке «ИТОГО»

    Reply
  12. climepost

    Сформируйте оборотно-сальдовую ведомость по сч.36 за тот период, за который формируете отчет по оборачиваемости. Посмотрите, есть ли дебитовый оборот у тех нескольких контрагентов, которых вы выбираете в отчете? Колонка «Продажи» заполняется по данным дебета сч.36. Если у контрагента нет продаж, то и оборачиваемость у него нулевая.

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

    Reply
  13. 375295

    Интересно.

    Reply
  14. Nikolay

    А для 1С8 такой отчёт есть у кого нибудь?

    Reply

Leave a Comment

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