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




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2026-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 не будет опубликован. Обязательные поля помечены *