Доработка ERP 2 для отражения акциза при реализации подакцизных товаров (табачной продукции)




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

6 Comments

  1. teller

    У вас кол-во сигарет в пачке прописано явно в коде?

    АкцизТНС   = ПолучитьТвердуюСтавкуДляСигарет(Дата) * (ТекущаяСтрока.Количество*20/1000);
    АкцизАНС   = РазмерМРЦ * (ПолучитьАдвалорнуюСтавкуДляСигарет(Дата)/100) * ТекущаяСтрока.Количество;
    АкцизСумма = АкцизТНС+АкцизАНС;
    АкцизМин   = ПолучитьМинимальнуюСтавкуДляСигарет(Дата) * (ТекущаяСтрока.Количество*20/1000);
    
    
    Reply
  2. dima_home

    У нас количество всегда в пачках, и только в пачках (единицы хранения товара).

    Упаковки так же имеются.

    Тут надо пояснить:

    В ЕРП на форме нет поля «Количество» и «Единица», вернее они есть на форме, только на самом деле это «Количество упаковок» и «Единица упаковки».

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

    Конечно, правильно было поступить так: проверить что единица — это пачка, но у нас ВСЯ номенклатура в пачках, и я это пропустил.

    PS/ Акциз для сигарет рассчитывается тоже исходя из единицы «пачка», поскольку МРЦ определяется только на пачку.

    Раз такая пьянка, вот вам еще несколько курьезов из табачной промышленности:

    1. На конференции по ЕРП в 2017 году сотрудник компании 1С заявил что в России нет табачной промышленности, по этому они не реализуют решения по табачному акцизу. А как же мы? ))

    2. Регламент производства и реализации табачных изделий четко описывает, что сигареты должны продаваться только в «ПАЧКАХ»!!!!! по 20 штук сигарет внутри. Тогда как в классификаторе единиц измерений (ОКЕИ) существуют только либо «штуки», либо «тысячи пачек». И все бы ничего, да вот некоторые покупатели обязательно требуют указание кода ОКЕИ для единиц товаров (это особенно касается крупных сетей).. все время приходится разъяснять.

    3. 1С не разрешает в ГТД указывать страну происхождения «РОССИЯ» мотивируя тем, что в счетах фактурах, для Российских товарах ставится в ГТД прочерк. Хочется задать вопрос сотрудникам 1С: «А ничего, что при производстве продукции на территории Калининградской области и вывозе ее на большую землю, при перемещении (продажи) необходимо в документах указывать ГТД, где страна происхождения РОССИЯ?»

    4. В расчетных документах, в том числе в реестрах чеков и реестрах на получение средств с аккредитива, первичных учетных документах и счетах-фактурах соответствующая сумма акциза выделяется отдельной строкой! Приходится самим лепить в унифицированные формы, такие как ТОРГ-12 строки (столбцы) с суммой акциза.

    Reply
  3. *Svetlana*

    Добрый вечер! Большое спасибо за статью. Не подскажете по такому вопросу: если мне нужно добавить свою проводку по забалансу к типовому документу — я добавила тоже текст запроса по шаблону (с Вашей помощью разобралась в шаблоне). Но есть сложность — мне надо получить стоимость товара на забалансе при проведении, а для этого надо как минимум дату в параметры передать как-то в запрос…. Или временную таблицу с этой забалансовой себестоимостью организовать… не понимаю, как это в данной конфигурации реализовать…

    Reply
  4. dima_home

    Если вы обратили внимание, в запросе уже существуют разного рода временные таблицы с данными, например «ДокументыКОтражению», они формируются в начале запроса.

    Через их можно выдернуть любой реквизит документа через внутреннее соединение.

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

    Reply
  5. corbenSG

    Спасибо огромное за статью! Многое в ней мне помогло. Особенно что касается проводки.

    Вставлю свои пять копеек.

    в процедуру ПересчитатьАкцизВСтрокеТЧ я бы добавил еще условие

    Если ТекущаяСтрока = Неопределено или не ТекущаяСтрока.Количество>0 Тогда
    Возврат;
    КонецЕсли;

    Что бы при первом добавлении товара не гонять на сервер.

    И еще у вас не где не написано что у общего модуля ИТ_АкцизСервер должны стоять галки «Сервер» и «Вызов сервера»

    Еще хотел уточнить у вас, а как вы уменьшаете НУ Кт 90.01.1 на сумму акциза?

    Reply
  6. dima_home

    Для решения вопроса с доходами пришлось переделать регистр:

    Регистр накопления «Выручка и себестоимость продаж».

    Для решения задач по отделению НДС с акциза от обычного НДС пришлось задеть

    Регистр накопления «НДС Продажи»

    Хотя соблазн просто прикрутить проводку, не задевая регистры был велик, но все же склонились к добавлению ресурса «Акциз» в эти регистры. Это нужно, чтобы в управленческих отчетах мы видели нормальную прибыльность.

    Извините что долго не отвечал, занят работай на маркировкой табачной продукции, передаваемые в ЦРПТ.

    Reply

Leave a Comment

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