Честное распределение суммы по таблице значений (3.1.4.1)




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2025-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='\

56 Comments

  1. seermak

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

    Reply
  2. Shaman100M

    у меня тоже, правда для семерки, третий вариант.

    http://infostart.ru/profile/8196/projects/840/

    Reply
  3. alexk-is

    Добавил еще один вариант. Назвал условно «Статистический». Методика распределения направлена на снижение средней ошибки округления, путем корректировки строк с наибольшей ошибкой (отклонением) при округлении.

    Вариант реализации с запросом работает эффективно только при большом количестве строк (более нескольких десятков тысяч).

    Reply
  4. Трактор

    Прикольно. Плюс за постановку вопроса.

    Reply
  5. alexk-is

    Добавил пример использования в УТ на базе типовой обработки из версии 10.3.6.8. В обработке ОбработкаТабличнойЧастиТовары изменил процедуру РаспределитьСуммуПоКолонке.

    Для использования можно заменить или процедуру РаспределитьСуммуПоКолонке, или целиком обработку ОбработкаТабличнойЧастиТовары.

    Reply
  6. alexk-is

    Добавил пример использования в ТиС на базе типовой обработки из версии 7.70.954. В обработке ГрупповаяОбработкаМнЧДокументов изменил функцию РаспределитьСуммуПоКолонке и обработку константы РозничныйТипЦен в процедуре ПересчитатьСтрокуТаблицы.

    Для использования можно заменить или процедуру РаспределитьСуммуПоКолонке, или целиком обработку ГрупповаяОбработкаМнЧДокументов.

    Reply
  7. alexk-is

    Добавил пример использования в УПП на базе типовой обработки из версии 1.2.9.1. В обработке ОбработкаТабличнойЧастиТовары изменил процедуру РаспределитьСуммуПоКолонке.

    Для использования можно заменить целиком обработку ОбработкаТабличнойЧастиТовары или только процедуру РаспределитьСуммуПоКолонке.

    Reply
  8. alexk-is

    Добавил пример использования в БП на базе типовой обработки из версии 1.6.11.7. В обработке ОбработкаТабличнойЧастиТовары изменил процедуру РаспределитьСуммуПоКолонке.

    Для использования можно заменить целиком обработку ОбработкаТабличнойЧастиТовары или только процедуру РаспределитьСуммуПоКолонке.

    Reply
  9. Сафик

    а можно получить подробную инструкцию добавления отчета для ТиС 9.2? Я не прогаммист и поэтому тяжеловато, а очень нужно 🙁

    Reply
  10. alexk-is

    (9) Это не отчет, а обработка…

    1. Проверить соответствие версии конфигурации и обработки. 7.70.954

    2. Скачать с сайта обработку и сохранить, например, на рабочий стол

    3. Запустить 1С:Предприятие 7.7 в режиме «Конфигуратор» и выбрать соответствующую базу

    4. Сделать архивную копию. В меню «Администрирование» — «Сохранить данные…» указать имя файла архива, например: db_20090220-1512.zip

    5. Открыть конфигурацию. В меню «Конфигурация» — «Открыть конфигурацию»

    6. В дереве конфигурации выделить строку «Обработки» — «ГрупповаяОбработкаМнЧДокументов»

    7. В меню «Действия» — «Внешний отчет(обработка)» — «Заменить на внешний отчет(обработку)…» и указать имя скаченного файла на рабочем столе

    8. Сохранить конфигурацию. В меню «Файл» — «Сохранить»

    9. Закрыть конфигуратор и запустить базу в режиме 1С:Предприятия

    10. Проверить работу обработки в документе реализация с заполненными строками. Нажать кнопку «Действия…» — «Изменить спецификацию». Сменить режим работы «Установить ставку НДС» на «Установить сумму по суммам». Ввести сумму. Нажать «Выполнить». Проверить результат

    Reply
  11. alexk-is

    +10 Не «Установить сумму по суммам», а «Распределить сумму по суммам» — опечатался…

    Reply
  12. Сафик

    спасибо, все получилось

    Reply
  13. Shaman100M

    Основательно

    Reply
  14. LS

    В качестве примера, думаю, пригодится, спасибо!

    Reply
  15. alexk-is

    Добавил распределение одним пакетным запросом для четвертого варианта.

    Reply
  16. RayCon

    Столько копий на эту тему сломано! Молодец, что взялся за решение проблемы!

    Вот только остался открытым вопрос: а как правильно? 😀

    Было бы идеально, если ещё были бы даны рекомендации по применению каждого метода и озвучены ограничения на применение. И особенно важно осветить проблему не просто с точки зрения математики, а спроецировать математику на бухгалтерию и разобрать примеры с учётом сумм НДС.

    Reply
  17. Worst

    Особенно интересно когда перегружаешь валютные документы в рублевые или наоборот…Спасибо автору за классификацию! Если бы еще бухгалтера могли понять это в своей массе! а то может случиться непонятка.

    Reply
  18. Worst

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

    Reply
  19. alexk-is

    (16) С НДС шутки плохи. Суммы по НДС должны быть такими, как в строках счет-фактур. Любое отклонение — налоговое преступление.

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

    Reply
  20. RayCon

    (19) Ну, так никто и не говорит о преступлении. 🙂

    Речь идёт совсем о другом.

    Поставщик оплатил продавцу некую сумму А, в т.ч. НДС=А*18/118. Продавец делает отгрузку из нескольких товарных позиций. Задача такова: каким образом рассчитать в накладной налогооблагаемую базу по НДС и сам НДС, чтобы итоговая сумма отгрузки без НДС была равна значению А*100/118, итоговая сумма НДС — значению А*18/118, а итоговая сумма, включая НДС, — значению А? При этом, естественно, по каждой строке сумма НДС должна составлять положенные по законодательству 18% от налогооблагаемой базы.

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

    Reply
  21. nika14

    Здоровенская обработка!

    Reply
  22. svbel85

    полезный пример , спасибо

    Reply
  23. alexk-is

    (25)

    > Я всегда при распределении делаю так:

    Это почти вариант 3. Только без сортировки, а значит с большей погрешностью.

    > В результате никогда не остается никаких хвостов требующих каких-то еще повторных распределений да еще к тому же каких-то «честных». Что я делаю не правильно?

    Не берусь судить. Может быть дорогу переходите в неположенном месте?

    > Обработку качать и смотреть западло

    Разьве кто-то кого-то заставляет?

    > но судя по описанию — фуфло галимое.

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

    Reply
  24. Altair777

    (26)

    Ну, что же еще можно было ожидать от того…

    Верное замечание 🙂 Тем более, что человек просто не понимает значения слова погрешность.

    Метод, описанный в 25, не дает хвостов просто потому что он не может дать. Вся сумма будет распределена, но их погрешности могут быть большими.

    А ведь даже самый лучший и «честный» метод может иметь непозволительные результаты.

    Простой пример: распределить 3 коп на 2 строки, в каждой из которых по 1 коп. Точность — 1 коп.

    Reply
  25. Altair777

    (29) Кошки рулят,

    Понятие погрешность в данном контексте вообще бессмысленно.

    я же говорил — не понимаешь :)))

    Reply
  26. alexk-is

    (29) Про погрешность. Считаем по строкам сумму отклонений от «идеальной», т.е. максимально математически точную:

    БазаПоСтроке * СуммаДляРаспределения / ВсегоБаза

    На 3000 строк раскидываем 10 рублей

    Вариант 1. Сумма отклонений: 2,20999953732376972592242046022

    Вариант 2. Сумма отклонений: 1,2641759109412526656930230297

    Вариант 3. Сумма отклонений: 0,63393937726647997736821462216

    Вариант 4. Сумма отклонений: 0,3776659164007059985008264175

    Ваш вариант. Сумма отклонений: 2,73341800769621530044471409828

    Вариант 5 дает с 10 рублей 2.73 рубля отлонений от «идеальной».

    Да, конечно, во всех 5 вариантах распределяютя все 10 рублей до копеечки. Но поделить-то можно по разному — поровну, по чесному или просто свалить всё на одну строку.

    Reply
  27. alexk-is

    (34) Серьёзный аргумент. А я уж было подумал, что претензии действительно серьёзные и придется что-то долго и нудно объяснять. А так просто смотрим картинку и считаем по строке 3043 для варианта 5.

    БазаПоСтроке * СуммаДляРаспределения / ВсегоБаза

    Расчет по варианту 5:

    2 * 10 / 4754944.94 = 0.01

    Расчет по формуле в табло 1С:

    2 * 10 / 4754944.94 = 0.000004206147547946159813998

    Отклонение по строке 3043 для варианта 5

    0.01 — 0.000004206147547946159813998 = 0.009995793852452053840186002

    Замечу, что только вариант 1 и вариант 5 дают столь неожиданные результаты. Разумеется, что ничего этого не будет при распределении больших сумм всего по нескольким строкам.

    Здесь уместнее говорить о накапливаемой погрешности при округлении. В вариантах 1 и 5 этот момент не учтен.

    Reply
  28. alexk-is

    (28) Честно говоря из объяснения так и не понял за что минус?

    Приведенный пример с распределением 3 копеек, наверное, не совсем корректен. При одинаковых базах распределения не важно куда будет отнесена копейка, лишь бы не потерялась.

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

    Reply
  29. Altair777

    (36) про какой минус ты говоришь?

    Одинаковые базы я взял просто для примера, что бы кошкам легче было считать 🙂

    Reply
  30. alexk-is

    (37) Какой минус? Обыкновенный. Точнее так, для меня это второй «обыкновенный» минус.

    22.03.2012 19:29:13

    Новый голос за «Честное распределение суммы по таблице значений (3.1.4.1)» от пользователя Altair777.

    Оценка: -1

    Как про тот минус не смог добиться ответа, так и про этот тоже не могу понять «за что»?

    Тоже не нравится публикация? Тоже считаешь её «Бредом сивой кабылы в ясную лунную ночь»?

    Reply
  31. Altair777

    (38) извини! Я промахнулся 🙂

    уже исправил, причем дважды

    Reply
  32. alexk-is

    (39) А-а-а-а, ну, тогда ладно…

    Reply
  33. Altair777

    (40) а какой еще тот минус?

    Reply
  34. alexk-is

    (41) Вот тут http://infostart.ru/public/66680/

    Спросил в личку, молчит. Так я и не узнал, чем плохо поздравлять красавиц с 8 марта?

    Reply
  35. Altair777

    (42) я уже подумал что ты про какой-то мой минус сказал

    Reply
  36. nickVZ
    А ведь даже самый лучший и «честный» метод может иметь непозволительные результаты.

    Простой пример: распределить 3 коп на 2 строки, в каждой из которых по 1 коп. Точность — 1 коп.

    Блестяще. А что «позволительно»? Применить «полторы копейки»? Здесь вариантов просто нет: 2+1. И если объекты распределения равнозначны, то иного и не будет. А перестановка объектов местами не имеет никакого отношения к алгоритму, ибо алгоритм не следит, на какой объект вы глядите более ласково.

    Некорректными примерами доказывать корректность своих убеждений? Как НТВ?

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

    Reply
  37. nickVZ

    (35) вообще-то, правильный аргумент, но не раскрытый.

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

    Как следует из (26), это и есть «вариант 3». «Предварительная сортировка» есть предварительная сортировка, никак не относящаяся к алгориту, а только определяющая список, как таковой.

    Смотрим недостатки этой функции. Во-первых, и это существенно, нужны еще параметры: точность округления раз, и направление округления, два. Это когда надо заранее оговорить: 0.5 — это 1.0 или 0.0?

    Во вторых, что много существеннее, надо предусмотреть деление на 0. Увы нам, но «база» из +1 и -1 обеспечит нам если не голубой экран, то неприятное сообщение точно 🙂

    И вот тут, чтоб построить правильный алгоритм, надо представить данные «геометрически». Ну, как на каком-то графике. После этого понимаем, что нужны еще две манипуляции: сдвиг осей графика так, чтоб все точки оказались в правой верхней четверти, и, после распределения, вертание осей взад 😉

    Приятного размышления 😀

    Reply
  38. Altair777

    (44) nickVZ,

    Коэффициент «все равны, а этот равнее на ххх.ххх».

    ха-ха-ха 🙂 у меня этот лозунг в профиле записан

    Все животные равны, но некоторые равнее других

    © Джордж Оруэлл «Скотный двор»

    Кошки вообще ничего не говорили (тем более, кошки вообще говорить не умеют 🙂 ) по поводу веса и справедливости. В том алгоритме — кто первый встал, того и тапочки.

    А пример с 3 копейки как раз и утверждает, что справедливого на 100% алгоритма не может существовать. Там так и написано.

    Reply
  39. alexk-is

    (46) Начнем с того, что с самого начала «честный» было написано в кавычках, т.е. уже 3,5 года.

    По поводу «В том алгоритме — кто первый встал, того и тапочки».

    А вот и нет. По варианту в (25) на больших массивах информации погрешность может активно накапливаться и «тапки» будут розданы самым неожиданным образом. См. картинку в (35)

    Reply
  40. alexk-is

    (45) Нужно как-то уже определяться.

    Сначала приводите для примера не очень удачную реализацию (25). Потом хаете её, при этом утверждая, что автор варианта 5 хоть и груб, но во всем абсолютно прав. А потом описываете схему работы варианта 3 как желаемую. Хотя вариант 3 уже работает у меня по этой схеме лет этак 20.

    И вообще, почему привязались к варианту 3? Все варианты (1,2,3) приведены в публикации только для того, чтобы можно было сравнить результаты их работы с вариантом 4. Именно варианту 4 в основном и посвящена эта публикация.

    Если что-то и обсуждать, так это вариант 4. (самый «честный»)

    Reply
  41. alexk-is

    (49) Да, речь о распределении.

    Интересно как можно разделить распределение по списку и составление списка для варианта 4?

    Reply
  42. Altair777

    (49) nickVZ, и в чем же демагогия?

    Reply
  43. dyh

    Скачал, вставил все варианты в печатную, предупредил о бессмысленности таких перераспределений, т.к. правильная сумма важнее, дал ссылок на статьи… Зато бух теперь играется — каким же вариантом получатся одинаковые суммы для равноценной номенклатуры? )) Как показывает практика, универсального рецепта нет. (

    PS Пересчет из уе в руб при печати счетов на оплату.

    Reply
  44. ZLENKO

    А если в базе распределения будут не только положительные суммы а и отрицательные — алгоритмы корректно будут работать ?

    Reply
  45. alexk-is

    (54) Конечно

    Reply
  46. Miha.L

    Варианты «честного» распределения суммы по таблице значений

    Это от того, что последняя копейка все равно не ляжет правильно, или как ?

    А вообще, интересная разработка.

    Автор — молодец. Мой +

    Reply
  47. Synoecium

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

    Вот только что за куча файлов доступна для скачки, какой из них нужный?

    Reply
  48. ildarovich

    (3) Тоже считаю лучшим вариант 4 (как я его понял по словесному описанию). Однако обоснование кажется не совсем точным. При использовании этого варианта достигается не «снижение средней ошибки округления», а минимизация максимальной ошибки округления. С точки зрения средней ошибки все варианты равноценны.

    Reply
  49. alexk-is

    (57) Куда-то делись названия файлов. Исправил.

    Reply
  50. alexk-is

    (58) Это уже больше похоже на игры словами: «Кто точнее выразит мысль и сделает при этом меньше опечаток».

    Мне больше всего нравится обоснование из поста (33)

    В (36) тоже занятная картинка. Можно ли ее тоже считать обоснованием?

    Reply
  51. Synoecium

    Нашел ошибку в реализации способа 4 с помощью одного запроса (4_3). Если ввести 2 строки с одинаковым весом и попытаться распределить 1 копейку этим способом, то в обеих строках будет стоять по 1 копейке.

    Исправил, заменив строку 382 в модуле объекта:

    СУММА(1) КАК НомерСтрокиОкругления

    на

    КОЛИЧЕСТВО(ВременнаяТаблицаРасчетов1.ВеличинаОтклонения) КАК НомерСтрокиОкругления

    П.С. Ваша обработка очень помогла)

    Reply
  52. endym

    Соглашусь что проблема не новая;)

    Как обстоят дела с сверх малыми суммами?;)

    ставится ли минимальное значение 0,01 или вообще 0?

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

    Reply
  53. alexk-is

    (62) А если взять, да попробовать, то как? Получилось?

    Reply
  54. jsmith

    спасибо

    Reply
  55. tailer2

    Оптимальность распределения — вещь в себе, однозначно 🙂

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

    Единственно возможный критерий — незаметность.

    Ошибку округления нельзя устранить, ее можно только спрятать. Поэтому критерий — незаметность.

    А незаметность достигается в цикле по единицам округления (копейкам).

    Каждую копейку — отдельно по критерию незаметности на каждом шаге распределения.

    А этого в одном запросе не достигнешь по той простой причине, что неизвестно количество копеек.

    Значит, на сколько копеек надо поправить итог, столько раз пробегаем строки таблицы.

    Вся фишка в том, чтобы найти, куда сунуть очередную копейку, за один проход.

    Reply
  56. qwerty45

    Здравствуйте! Хочу подключить обработку к УТ 10,3. В Реквизитах в поле ДокументОбъект добавил ЧекККМ. Обработка сохранена в базу, на документе ЧекККМ добавлена кнопка для запуска обработки. При нажатии получаю : «Не задан документ для обработки…» Что не доделано?

    Reply

Leave a Comment

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