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




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

63 Comments

  1. highlander

    А я вот интересуюсь… а возможно такое на 7-ке?

    Reply
  2. Evg-Lylyk

    (2) посмотрел вроде нет предопределенной процедуры аналогичной 8.1 аналогично наверно не сделать

    Надеюсь ветка не превратится в ветку, а как сделать тоже самое на 7.7 🙂

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

    (1) Да

    Reply
  4. highlander

    Нет не превратиться… не волнуйтесь 😀 Но за идею плюс однозначно

    Reply
  5. Evg-Lylyk

    (4) самая идея подсчета суммы работает через 5 минут, а вот над оптимизацией пришлось поломать голову

    Reply
  6. Stepa86

    (5) какое самое узкое место? наверно получение одиночной области и вынимание из нее текста…

    Reply
  7. bashta.aleksey

    Evg-Lylyk в конфе «Бухгалтерия предприятия КОРП» рел 2.0.6.3 этот механизм уже есть в стандартных отчетах.

    Думаю это тебе поможет:

    Функция ВычислитьСуммуВыделенныхЯчеекТабличногоДокумента(ПолеТабличногоДокумента) Экспорт
    Сумма = 0;
    Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл
    Если ТипЗнч(Область) = Тип(«ОбластьЯчеекТабличногоДокумента») Тогда
    Для ИндексСтрока = Область.Верх По Область.Низ Цикл
    Для ИндексКолонка = Область.Лево По Область.Право Цикл
    Попытка
    Сумма = Сумма + Число(СтрЗаменить(ПолеТабличногоДокумента.Область(«R» + Формат(ИндексСтрока, «ЧГ=0») + «C» + Формат(ИндексКолонка, «ЧГ=0″)) .Текст, » «, «»));
    Исключение
    КонецПопытки;
    КонецЦикла;
    КонецЦикла;
    КонецЕсли;
    КонецЦикла;
    Возврат Сумма;
    КонецФункции

    Показать

    Reply
  8. bashta.aleksey

    Извините.

    Функция ВычислитьСуммуВыделенныхЯчеекТабличногоДокумента(ПолеТабличногоДокумента) Экспорт

    Сумма = 0;

    Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл

    Если ТипЗнч(Область) = Тип(«ОбластьЯчеекТабличногоДокумента») Тогда

    Для ИндексСтрока = Область.Верх По Область.Низ Цикл

    Для ИндексКолонка = Область.Лево По Область.Право Цикл

    Попытка

    Сумма = Сумма + Число(СтрЗаменить(ПолеТабличногоДокумента.Область(«R» + Формат(ИндексСтрока, «ЧГ=0») + «C» + Формат(ИндексКолонка, «ЧГ=0″)) .Текст, » «, «»));

    Исключение

    КонецПопытки;

    КонецЦикла;

    КонецЦикла;

    КонецЕсли;

    КонецЦикла;

    Возврат Сумма;

    КонецФункции

    Reply
  9. Evg-Lylyk

    (8) и это в типовой? ))))))))))

    Reply
  10. Evg-Lylyk

    (7) мой метод «нормальный» 8)

    Reply
  11. bashta.aleksey

    😀

    Reply
  12. 4ish

    Не сочтите за каприз, но попробовал выделять отдельные ячейки через Ctrl — не работает. 🙁

    Reply
  13. venger

    (1) > А я вот интересуюсь… а возможно такое на 7-ке?

    Вот, например: http://infostart.ru/public/16000/

    Reply
  14. Evg-Lylyk

    (12) Мультивыделение работает и система оптимизации для мультивыделений тоже. Просто это пример… функция «ПолучитьИнформациюПоВыделеннымОбластям» возвращает информацию по каждой области в структуре дальше используете как хотите я просто не стал делать сумму выделенных областей т.к. просто пример. Сейчас поправлю.

    Reply
  15. Yashazz

    О! Всё ждал, пока кто-нибудь сделает…

    Спасибо!

    Reply
  16. 4ish

    (15) Благодарю. 🙂

    Reply
  17. Gleb K.

    Всем привет. А я себе сделал вот так.

    У меня учитывается мультивыделение, наличие скрытых строк и/или столбцов, плюс парочка проверок «на дурака».

    [1C-CODE]Процедура ТДПриАктивизацииОбласти(Элемент)
    Сумма = 0;
    Для Каждого Область из ЭлементыФормы.ТД.ВыделенныеОбласти Цикл
    Если Не Область = Неопределено И НЕ (Область.Верх = 0 И Область.Низ = 0) И НЕ (Область.Лево = 0 И Область.Право = 0) Тогда
    Для i = Область.Верх по Область.Низ Цикл
    Для j = Область.Лево по Область.Право Цикл
    Ячейка = ЭлементыФормы.ТД.Область(i,j);
    Если Ячейка.СодержитЗначение
    И Ячейка.Видимость
    И Ячейка.ТипЗначения = Новый ОписаниеТипов(«Число»)
    И Не Ячейка.Значение = Неопределено Тогда
    Сумма = Сумма + Ячейка.Значение;
    КонецЕсли;
    КонецЦикла;
    КонецЦикла;
    КонецЕсли;
    КонецЦикла;
    КонецПроцедуры
    

    Показать

    [/1C-CODE]

    Reply
  18. Evg-Lylyk

    (17) метод сабжа более оптимален почитайте внимательно и посмотрите код

    Reply
  19. Evg-Lylyk

    (17)

    «Если Не Область = Неопределено И НЕ (Область.Верх = 0 И Область.Низ = 0) И НЕ (Область.Лево = 0 И Область.Право = 0) Тогда»

    Нужно только «Если Не Область = Неопределено» и то не знаю пример когда

    Во внутреннем условии тоже не все условия нужны

    Строка 100 не будет суммироваться, что как мне кажется, неправильно.

    Видимо волна материалов захлестнула инфостарт и все ждут примитивизма, а вот фиг 🙂 это не ко мне

    Reply
  20. Gleb K.

    (18, 19) Если Не Область = Неопределено возникает когда щелкаешь мышью между заголовков колонок или строк.

    С внутренними условиями я перемудрил, у вас лучше.

    На счет 100 строки не понял.

    А вот скрытые ячейки у вас будут суммироваться, что правильно, но не логично 🙂 Хотя это зависит от процедуры вызывающей функцию ВычислитьСуммуОбласти.

    Reply
  21. Evg-Lylyk

    (20) Я имел ввиду что строка «100» не будет суммироваться т.к. имеет Тип(«Строка»)

    На счет скрытых ячеек поправил так логичные (не подумал)

    Reply
  22. artbear

    (21) Пробовал писать ПолучитьЧислоИзСтроки(Текст) без блока Попытка-Исключение ?

    ИМХО должно быть быстрее.

    Reply
  23. Evg-Lylyk

    (22) Рад тебя слышать. Конечно быстрее, а что с ошибками делать

    Reply
  24. Ish_2

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

    В этом случае подсчет сумм будет неверным.

    Я правильно понял ?

    Reply
  25. Ish_2

    В строке функции :

    ОдиночнаяОбласть = ТабличныйДокумент.Область(ЯчВерт,ЯчГориз)

    приведено неверное обращение к ячейке.

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

    ОдиночнаяОбласть =
    ТабличныйДокумент.Область(ЯчВерт,ЯчГориз,ЯчВерт,ЯчГориз)

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

    Reply
  26. Ish_2

    Не приводит к неправильно вычисленной сумме и обращение к ячейке , используемое в Бухгалтерии КОРП («R..C..»).

    Reply
  27. Evg-Lylyk

    (26) Спасибо понял поправлю … по мне лучше ТабличныйДокумент.Область(ЯчВерт,ЯчГориз,ЯчВерт,ЯчГориз)

    Reply
  28. Evg-Lylyk

    (24) должно нормально отрабатывать кэш для каждой отдельно

    Reply
  29. Ish_2

    (28) Не понял.

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

    сначала в одной выделенной области , потом в другой.

    Reply
  30. Ish_2

    +28 Я налетел на этот эффект у себя в теме , где используется не одиночное выделение ячейки в табличном документе , а множественное выделение : «строка» или «крест».

    Reply
  31. Evg-Lylyk

    (30) да т.к. это две разные выделенные области.

    Reply
  32. Evg-Lylyk

    31+ будут показываться сумма каждой выделенной области + сумма

    Reply
  33. elizarovs

    (+) Классно! Еще бы в форме документа такое сделать…

    Reply
  34. artbear

    (23) Я к тому, что может быть быстрее вместо Попытки анализировать первый символ — если это цифра, то суммировать.

    Также сначала можно использовать СокрЛ (не СокрЛП)

    или вообще регулярным выражением проверить 🙂

    Reply
  35. Evg-Lylyk

    (33) добавить можно в любую форму с ТабДок это пример

    (34) Это проверено еще на консоли медленнее, регуляры так вообще. Вариан описан в p.s. нужно функции ВычислитьСуммуОбласти, ПолучитьЧислоИзСтроки реализовать через ВК должно быть быстрее

    Reply
  36. Ish_2

    (34) Странно.

    Пусть текст ячейки начинается с цифры и мы начинаем его суммировать без попытки. В этом случае пользователь получит сообщение об ошибке, если в тексте ячейки — » 1 показатель».

    Хрен редьки не слаще.

    Применение ВК для подсчета сумм тоже смотрится , на мой взгляд, диковато.

    Думаю ,при практическом применении ,например ,в бухгалтерских отчетах скорость подсчета мало существенна. Неоходим лишь быстро вычисляемоый грубый подсчет количества ячеек в выделенных ячейках. И ограничение на их количество.

    Reply
  37. zag2art

    А чем это лучше чем выделить группу ячее и нажать M+ в калькуляторе 8.1?

    Reply
  38. Evg-Lylyk

    (37) тем что не надо ничего нажимать плюс можно среднее посчитать или еще чтото

    про М+ мало кто знает

    Reply
  39. banne

    Обработка СУПЕР!!! 😀

    Reply
  40. elizarovs

    (35) Вот именно, с ТабДок, а там везде ТЗ. А у ТЗ нет события ПриАктивизацииОбласти, как и объекта ВыделенныеОбласти.

    Reply
  41. Evg-Lylyk

    (40) В ТЗ нельзя выделить одну ячейку в Колонке1 Строке1 и одну ячейку в Колонке2 Строке2 только построчно.

    Reply
  42. elizarovs

    (41) Похоже, что так, во всяком случае я не нашёл описания такой возможности или примера. Хотя, если поставить в свойствах выделения строки — Ячейка, а в режиме выделения — множественное, то в форме прекрасно выделяются ячейки в любой комбинации. Выцепить же список выделенных ячеек из кода я не смог. Може кто поможет? Ну очень нужного свойства в 1С не хватает (сумма группы выделенных ячеек)…

    Reply
  43. Evg-Lylyk

    (42) опиши когда это нужно (я даже не представляю примера)

    Reply
  44. elizarovs

    (43) Большая организация, несколько подразделений и даже несколько баз данных оперативного учета. В базу бухгалтерии сливаются все документы из первичных баз. Любимое занятие бухов — сравнивать документы по наличию и по суммам. Открывают журнал, берут калькулятор и строчат, как из пулемёта. А так бы просто мышкой потыкали. Думаю, можно много ситуаций похожих найти.

    Другой пример (реальный). На фирме, на базе 1С, стоит система, в которой итого по документу не сходится с итого по таблице. Не говорю, что это правильно, но так получилось. А я пытаюсь разгрести… Приходится вываливать каждый раз в список, чтобы сложить

    Reply
  45. Evg-Lylyk

    (44) как сделать подобное в ТЗ, ТЧ не представляю. Может поможет: для сравнения данных есть СравнениеФайлов очень полезная вещь

    Reply
  46. kate123

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

    Reply
  47. Evg-Lylyk

    (46) Для ТЧ не получится. Почитайте внимательно комментарии этот вопрос поднимали.

    Reply
  48. tango

    ну, не знаю.

    открыли калькулятор.

    выделили область.

    нажали кнопку.

    чем встроеная фича хуже всей этой возни?

    Reply
  49. Evg-Lylyk

    (48) Потому что автоматически и не надо ничего нажимать

    Вы не первый почитайте комментарии

    Даже 1С решили что это нужно и в Бух. КОРП сделали в шаблонах отчетов эту функцию

    Reply
  50. Ish_2

    (48),(49) И в скоро выходящей на замену 1.6 новой версии БП 2.0 предусмотрен этот функционал.

    И получается , Миша, что автор предвосхитил появление такого функционала в типовых конфигурациях.

    Reply
  51. tango

    или содрал в КОРПе :). Гоша.

    Reply
  52. Evg-Lylyk

    (51) было давно в http://infostart.ru/public/16782/

    Reply
  53. Fisherru

    (13)

    Ваша ссылочка хороша, плюсик поставил, но это не совсем тоже самое…

    У вас там идет работа с печатными формами, а хочется с табличными частями документа и со справочниками в форме списка…

    Вот что очень хочется http://infostart.ru/forum/forum19/topic31264/

    Reply
  54. Evg-Lylyk

    (53) на семерке не подскажу

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

    Reply
  55. zba

    В управляемой форме не побывал сделать, а то чета там данная функция не работает

    Reply
  56. tamaks

    Использовал представленые в публикации процедуры для выгрузки привязаных фото для выделеной пользователем в отчете номенклатуры. Сформировал отчет — выделил строки с наименованием номенклатуры — нажал выгрузить фото.

    Reply
  57. le0nard

    вот чуть измененная из типовой, скрытые не учитывает.

    Функция ВычислитьСуммуВыделенныхЯчеекТабличногоДокумента(ПолеТабличногоДокумента) Экспорт
    Сумма = 0;
    Для Каждого Область Из ПолеТабличногоДокумента.ВыделенныеОбласти Цикл
    Если ТипЗнч(Область) = Тип(«ОбластьЯчеекТабличногоДокумента») Тогда
    Для ИндексСтрока = Область.Верх По Область.Низ Цикл
    Для ИндексКолонка = Область.Лево По Область.Право Цикл
    Попытка
    адресЯчейки=»R» + Формат(ИндексСтрока, «ЧГ=0») + «C» + Формат(ИндексКолонка, «ЧГ=0″);
    ячейка=ПолеТабличногоДокумента.Область(адресЯчейки);
    если ячейка.Видимость тогда
    ЧислоЯчейки=Число(СтрЗаменить(ячейка.Текст, » «, «»));
    Сумма = Сумма +ЧислоЯчейки;
    конецесли;
    Исключение
    КонецПопытки;
    КонецЦикла;
    КонецЦикла;
    КонецЕсли;
    КонецЦикла;
    Возврат Сумма;
    КонецФункции
    

    Показать

    Reply
  58. German_Tagil

    (53)

    Вот что очень хочется http://infostart.ru/forum/forum19/topic31264/

    Подскажите а что там — пытаюсь обратиться — у вас нет прав на просмотр топика

    Reply
  59. Evg-Lylyk

    (58) Не подскажу, с 7.7 давно не работаю

    Reply
  60. German_Tagil

    (59) А я не про 7.7 спрашиваю

    думал что что-то по данному вопросу для 8.2

    задачка нудная — учет реально отработанного времени

    по операционно — документ сделал — теперь пытаюсь упростить ввод данных

    Reply
  61. Evg-Lylyk

    (60) Там 50 сообщений, поясни здесь о чем речь

    Reply
  62. German_Tagil

    (61) Вот что очень хочется http://infostart.ru/forum/forum19/topic31264/

    думал что это для 8.1

    Reply
  63. Evg-Lylyk

    (62) Прошу уточнить ты пишешь тоже самое. Попытаюсь угадать

    Если нужно что в т.ч. документа или обработки подсчитывалась сумма выделенных строк

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

    Reply

Leave a Comment

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