BiTel WiKi - Вклад участника [ru] http://wiki.bitel.ru/index.php/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/SinTeZWh1te Материал из BiTel WiKi ru MediaWiki 1.15.1 Thu, 28 Mar 2024 23:01:23 GMT Рекомендации по настройке MySQL http://wiki.bitel.ru/index.php/%D0%A0%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8_%D0%BF%D0%BE_%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B5_MySQL <p>SinTeZWh1te:&#32;Отмена правки 5400 участника SinTeZWh1te (обсуждение)</p> <hr /> <div>База MySQL данных должна быть настроена с поддержкой транзакций. <br /> Для биллинга версий от 5.2 и старше это требование обязательно, т.к. транзакции используются для отката результатов неудавшихся операций.<br /> <br /> == Настройка MySQL ==<br /> Рекомендуемая конфигурация, разбор параметров после. Пример сделан для ОС *NIX типа, как наиболее подходящей для высоконагруженных серверов БД. При необходимости его можно адаптировать для Windows системы, изменив соответственно пути файловой системы и пропустив секцию mysqld.safe.<br /> <br /> Кодировка 1251 базы данных по-умолчанию - исторически сложившаяся и не изменяемая как не несущая в себе существенных неудобств. Но при большой необходимости (например, требования хранения в БД символов других алфавитов) может быть изменена на UTF-8 или иную, при этом необходимо также скорректировать .properties файлы приложений биллинга на предмет кодировки БД.<br /> &lt;pre&gt;<br /> [mysqld]<br /> datadir=/var/lib/mysql<br /> tmpdir = /tmp<br /> socket=/var/lib/mysql/mysql.sock<br /> user=mysql<br /> log-slow-queries=/var/log/slowquery.log<br /> skip-name-resolve<br /> #<br /> default-storage-engine = innodb<br /> default-character-set=cp1251<br /> default-collation=cp1251_general_ci<br /> sql-mode=<br /> #<br /> max_allowed_packet=50M<br /> max_connections=1000<br /> #<br /> memlock<br /> table_cache=4096<br /> thread_cache_size=300<br /> thread_concurrency=2<br /> #<br /> # InnoDb<br /> innodb_file_per_table<br /> #<br /> innodb_log_group_home_dir = /var/lib/mysql/<br /> innodb_buffer_pool_size = 1G<br /> innodb_additional_mem_pool_size = 16M<br /> #<br /> innodb_log_files_in_group = 2<br /> innodb_log_file_size = 128M<br /> innodb_log_buffer_size = 8M<br /> innodb_lock_wait_timeout = 120<br /> #<br /> innodb_thread_concurrency = 2<br /> innodb_flush_log_at_trx_commit = 2<br /> innodb_flush_method = O_DIRECT<br /> #<br /> # MyIsam<br /> #key_buffer_size = 1G<br /> #myisam_recover<br /> #myisam_repair_threads = 1<br /> #myisam_data_pointer_size = 6<br /> #<br /> # Replication<br /> #server-id=1<br /> #log-bin=/var/lib/mysql-binlog/mysql-bin<br /> #expire_logs_days=3<br /> #replicate-do-db=bgbilling<br /> #relay-log-space-limit = 10G<br /> #<br /> [mysqld_safe]<br /> open-files-limit=32000<br /> log-error=/var/log/mysqld.log<br /> pid-file=/var/run/mysqld/mysqld.pid<br /> #<br /> [client]<br /> default-character-set=cp1251<br /> #<br /> [mysqldump]<br /> max_allowed_packet=50M<br /> default-character-set=cp1251<br /> &lt;/pre&gt;<br /> <br /> Опции mysqld - общие параметры:<br /> * '''datadir''' - каталог для хранения БД, лучше если это будет отдельный диск (RAID); высокие требования по надёжности и скорости.<br /> * '''tmpdir''' - каталог для хранения временных файлов, лучше сделать отдельным быстрым диском; невысокие требования по надёжности, высокие по скорости; можно использовать RAM диск.<br /> * '''socket''' - файловый сокет, возможность подключения консольным клиентом.<br /> * '''user''' - пользователь ОС, под которым запускается БД.<br /> * '''log-slow-queries''' - логирование запросов, выполняющихся длительное время.<br /> * '''skip-name-resolve''' - отключает DNS резолвинг для устанавливаемых соединений.<br /> * '''default-storage-engine''' - тип хранилища таблиц по-умолчанию, InnoDB - транзакционный тип хранилища.<br /> * '''default-character-set''' - кодировка по-умолчанию для вновь создаваемых таблиц.<br /> * '''default-collation''' - collation (порядок букв, используется при сортировке) по-умолчнию для вновь создаваемых таблиц.<br /> * '''sql-mode''' - запрещается установка режимов '''STRICT_TRANS_TABLES''' и '''STRICT_ALL_TABLES''', это приведёт к неработоспособности некоторых компонентов биллинговой системы.<br /> * '''max_allowed_packet''' - максимальный размер пакета с запросом, принимаемого сервером.<br /> * '''max_connections''' - ограничение на максимальное число соединений с БД.<br /> * '''memlock''' - запрет на перенос процесса mysqld в свап.<br /> * '''table_cache''' - максимальное количество описаний структур открытых таблиц в кэше.<br /> * '''thread_cache_size''' - размер кэша потоков для предотвращения их повторного создания.<br /> * '''thread_concurrency''' - число одновременно работающих потоков, рекомендуется ставить 2 * '''количество CPU''' + количество дисков. <br /> <br /> Запрещается установка опции '''skip-networking''', т.к. Java приложение подключается к серверу с использованием TCP протокола, а не через файловый сокет.<br /> <br /> Опции mysqld - InnoDB:<br /> * '''innodb_file_per_table''' - для возможности использования [[Database_backup | Backup базы с помощью snapshot'ов (Linux, LVM)]] в ОС LINUX.<br /> * '''innodb_log_group_home_dir''' - путь к каталогу под журнал транзакций, лучше если это будет отдельный диск; высокие требования по скорости и надёжности, низкие по объёму.<br /> * '''innodb_buffer_pool_size''' - размер буфера под все нужды, он должен составлять порядка 70-80 % от общей памяти сервера БД.<br /> * '''innodb_additional_mem_pool_size''' - параметр можно не изменять, размер буфера под доп. цели.<br /> <br /> * '''innodb_log_files_in_group''' - количество файлов журналов транзакций в группе журналов; InnoDB производит запись в файлы по круговому способу; увеличение ускоряет запись но тормозит восстановление информации в случае сбоя.<br /> * '''innodb_log_file_size''' - размер каждого файла журнала в группе журналов (указывается в мегабайтах).<br /> * '''innodb_log_buffer_size''' - размер буфера, который в InnoDB используется для записи информации файлов журналов на диск.<br /> * '''innodb_lock_wait_timeout''' - время простоя (в секундах), на протяжении которого транзакция InnoDB может ожидать прекращения блокировки прежде, чем будет произведен откат.<br /> <br /> * '''innodb_thread_concurrency''' - должно совпадать с '''thread_concurrency'''; число одновременно работающих потоков, рекомендуется ставить 2 * '''количество CPU''' + количество дисков.<br /> * '''innodb_flush_log_at_trx_commit''' - 2 отменяет сброс данных на диск при каждой транзакции, ускорение работы. <br /> * '''innodb_flush_method''' - O_DIRECT отключает двойную буферизацию (самим mysql и ОС).<br /> <br /> Опции mysqld -MyIsam, если используется (например, для некритичных таблиц):<br /> * '''key_buffer_size''' - размер кэша для хранения индексов;<br /> * '''myisam_recover''' -восстановление битых таблиц при старте сервера.<br /> * '''myisam_repair_threads''' - число потоков восстановления.<br /> * '''myisam_data_pointer_size''' - возможность создания больших первичных ключей в таблицах.<br /> <br /> Опции mysqld - репликации, если используется:<br /> * '''server-id''' - идентификатор сервера.<br /> * '''log-bin''' - место хранение bin-логов; лучше если это будет отдельный диск, высокие требования по скорости и надёжности, малые по объёму.<br /> * '''expire_logs_days''' - автоматическое удаление старых bin-логов.<br /> * '''replicate-do-db''' - реплицируемая БД.<br /> * '''relay-log-space-limit''' - ограничение на объём bin-логов.<br /> <br /> Опции mysqld_safe:<br /> * '''open-files-limit''' - лимит количества открытых файлов для ОС Linux.<br /> * '''log-error''' - файл для логирования ошибок.<br /> * '''pid-file''' - PID файл процесса. <br /> <br /> Опции mysqldump:<br /> * '''max_allowed_packet''' - установка маскимально возможного размера пакета при снятии дампов утилитой mysqldump.<br /> * '''default-character-set''' - кодировка по-умолчанию при снятии дампов БД.<br /> <br /> Опции client:<br /> * '''default-character-set''' - кодировка по-умолчанию при подключении консольным клиентом.<br /> <br /> В качестве примера конфигурации вы также можете использовать примеры конфигурации MySQL ('''/usr/share/mysql/my-innodb-heavy-4G.cnf''').<br /> <br /> Ссылки: <br /> * [http://mysql.ru/docs/man/ http://mysql.ru/docs/man/] - общее руководство по администрированию.<br /> * [http://mysql.ru/docs/man/InnoDB_start.html http://mysql.ru/docs/man/InnoDB_start.html] - параметры настройки InnoDb.<br /> * [http://mysql.ru/docs/man/Replication_Options.html http://mysql.ru/docs/man/Replication_Options.html] - параметры настройки репликации.<br /> * [http://maxq.ru/lib/53/ http://maxq.ru/lib/53/] - рекомендации по настройке InnoDb базы, MyIsam базы.<br /> * [http://mysqltuner.pl/mysqltuner.pl http://mysqltuner.pl/mysqltuner.pl] - скрипт автоматической настройки параметров БД.<br /> <br /> == Набор Perl утилит для работы с MySQL ==<br /> В архиве [[Медиа: mysql_perl_utilites.zip]] размещены файлы:<br /> * '''access.pm''' - параметры доступа к MySQL для остальных скриптов.<br /> * '''extract_myisam.pl''' - выбор MyIsam таблиц из базы и вывод в файл '''tables'''.<br /> * '''convert.pl''' - конвертация таблиц из файла '''tables''' в InnoDb.<br /> * '''drop.pl''' - удаление таблиц, перечисленных в файле '''tables'''.<br /> <br /> Конвертацию можно выполнять только после включения в my.cnf поддержки InnoDb. Следует учитывать, что конвертация больших таблиц может быть очень длительной, поэтому оптимальным будет исключить из конвертации помесячные таблицы с сессиями, наработками и т.п.<br /> Для транзакционной работы они не критичны. Достаточно, что в последующие месяцы эти таблицы также будут создаваться в формате InnoDb. Также можно предварительно отработать конвертацию таблиц на стороннем MySQL сервере.<br /> <br /> Выберите MyIsam таблицы в файл '''tables''' с помощью скрипта '''extract_myisam.pl''', скорректируйте файл '''tables''', оставив только последние месячные и постоянные таблицы.<br /> Затем выполните скрипт '''convert.pl'''.<br /> <br /> == Алгоритм конвертации с репликацией ==<br /> # Включить поддержку InnoDb на slave-сервере.<br /> # Включить поддержку InnoDb на master-сервере.<br /> # Запустить скрипт конвертации в InnoDB (см. ранее) для master-сервера.</div> Mon, 24 Jun 2013 07:39:55 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8_%D0%BF%D0%BE_%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B5_MySQL Рекомендации по настройке MySQL http://wiki.bitel.ru/index.php/%D0%A0%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8_%D0%BF%D0%BE_%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B5_MySQL <p>SinTeZWh1te:&#32;</p> <hr /> <div>База MySQL данных должна быть настроена с поддержкой транзакций. <br /> Для биллинга версий от 5.2 и старше это требование обязательно, т.к. транзакции используются для отката результатов неудавшихся операций.<br /> <br /> == Настройка MySQL ==<br /> Рекомендуемая конфигурация, разбор параметров после. Пример сделан для ОС *NIX типа, как наиболее подходящей для высоконагруженных серверов БД. При необходимости его можно адаптировать для Windows системы, изменив соответственно пути файловой системы и пропустив секцию mysqld.safe.<br /> <br /> Кодировка 1251 базы данных по-умолчанию - исторически сложившаяся и не изменяемая как не несущая в себе существенных неудобств. Но при большой необходимости (например, требования хранения в БД символов других алфавитов) может быть изменена на UTF-8 или иную, при этом необходимо также скорректировать .properties файлы приложений биллинга на предмет кодировки БД.<br /> &lt;pre&gt;<br /> [mysqld]<br /> datadir=/var/lib/mysql<br /> tmpdir = /tmp<br /> socket=/var/lib/mysql/mysql.sock<br /> user=mysql<br /> log-slow-queries=/var/log/slowquery.log<br /> skip-name-resolve<br /> #<br /> default-storage-engine = innodb<br /> default-character-set=cp1251<br /> default-collation=cp1251_general_ci<br /> sql_mode=<br /> #<br /> max_allowed_packet=50M<br /> max_connections=1000<br /> #<br /> memlock<br /> table_cache=4096<br /> thread_cache_size=300<br /> thread_concurrency=2<br /> #<br /> # InnoDb<br /> innodb_file_per_table<br /> #<br /> innodb_log_group_home_dir = /var/lib/mysql/<br /> innodb_buffer_pool_size = 1G<br /> innodb_additional_mem_pool_size = 16M<br /> #<br /> innodb_log_files_in_group = 2<br /> innodb_log_file_size = 128M<br /> innodb_log_buffer_size = 8M<br /> innodb_lock_wait_timeout = 120<br /> #<br /> innodb_thread_concurrency = 2<br /> innodb_flush_log_at_trx_commit = 2<br /> innodb_flush_method = O_DIRECT<br /> #<br /> # MyIsam<br /> #key_buffer_size = 1G<br /> #myisam_recover<br /> #myisam_repair_threads = 1<br /> #myisam_data_pointer_size = 6<br /> #<br /> # Replication<br /> #server-id=1<br /> #log-bin=/var/lib/mysql-binlog/mysql-bin<br /> #expire_logs_days=3<br /> #replicate-do-db=bgbilling<br /> #relay-log-space-limit = 10G<br /> #<br /> [mysqld_safe]<br /> open-files-limit=32000<br /> log-error=/var/log/mysqld.log<br /> pid-file=/var/run/mysqld/mysqld.pid<br /> #<br /> [client]<br /> default-character-set=cp1251<br /> #<br /> [mysqldump]<br /> max_allowed_packet=50M<br /> default-character-set=cp1251<br /> &lt;/pre&gt;<br /> <br /> Опции mysqld - общие параметры:<br /> * '''datadir''' - каталог для хранения БД, лучше если это будет отдельный диск (RAID); высокие требования по надёжности и скорости.<br /> * '''tmpdir''' - каталог для хранения временных файлов, лучше сделать отдельным быстрым диском; невысокие требования по надёжности, высокие по скорости; можно использовать RAM диск.<br /> * '''socket''' - файловый сокет, возможность подключения консольным клиентом.<br /> * '''user''' - пользователь ОС, под которым запускается БД.<br /> * '''log-slow-queries''' - логирование запросов, выполняющихся длительное время.<br /> * '''skip-name-resolve''' - отключает DNS резолвинг для устанавливаемых соединений.<br /> * '''default-storage-engine''' - тип хранилища таблиц по-умолчанию, InnoDB - транзакционный тип хранилища.<br /> * '''default-character-set''' - кодировка по-умолчанию для вновь создаваемых таблиц.<br /> * '''default-collation''' - collation (порядок букв, используется при сортировке) по-умолчнию для вновь создаваемых таблиц.<br /> * '''sql-mode''' - запрещается установка режимов '''STRICT_TRANS_TABLES''' и '''STRICT_ALL_TABLES''', это приведёт к неработоспособности некоторых компонентов биллинговой системы.<br /> * '''max_allowed_packet''' - максимальный размер пакета с запросом, принимаемого сервером.<br /> * '''max_connections''' - ограничение на максимальное число соединений с БД.<br /> * '''memlock''' - запрет на перенос процесса mysqld в свап.<br /> * '''table_cache''' - максимальное количество описаний структур открытых таблиц в кэше.<br /> * '''thread_cache_size''' - размер кэша потоков для предотвращения их повторного создания.<br /> * '''thread_concurrency''' - число одновременно работающих потоков, рекомендуется ставить 2 * '''количество CPU''' + количество дисков. <br /> <br /> Запрещается установка опции '''skip-networking''', т.к. Java приложение подключается к серверу с использованием TCP протокола, а не через файловый сокет.<br /> <br /> Опции mysqld - InnoDB:<br /> * '''innodb_file_per_table''' - для возможности использования [[Database_backup | Backup базы с помощью snapshot'ов (Linux, LVM)]] в ОС LINUX.<br /> * '''innodb_log_group_home_dir''' - путь к каталогу под журнал транзакций, лучше если это будет отдельный диск; высокие требования по скорости и надёжности, низкие по объёму.<br /> * '''innodb_buffer_pool_size''' - размер буфера под все нужды, он должен составлять порядка 70-80 % от общей памяти сервера БД.<br /> * '''innodb_additional_mem_pool_size''' - параметр можно не изменять, размер буфера под доп. цели.<br /> <br /> * '''innodb_log_files_in_group''' - количество файлов журналов транзакций в группе журналов; InnoDB производит запись в файлы по круговому способу; увеличение ускоряет запись но тормозит восстановление информации в случае сбоя.<br /> * '''innodb_log_file_size''' - размер каждого файла журнала в группе журналов (указывается в мегабайтах).<br /> * '''innodb_log_buffer_size''' - размер буфера, который в InnoDB используется для записи информации файлов журналов на диск.<br /> * '''innodb_lock_wait_timeout''' - время простоя (в секундах), на протяжении которого транзакция InnoDB может ожидать прекращения блокировки прежде, чем будет произведен откат.<br /> <br /> * '''innodb_thread_concurrency''' - должно совпадать с '''thread_concurrency'''; число одновременно работающих потоков, рекомендуется ставить 2 * '''количество CPU''' + количество дисков.<br /> * '''innodb_flush_log_at_trx_commit''' - 2 отменяет сброс данных на диск при каждой транзакции, ускорение работы. <br /> * '''innodb_flush_method''' - O_DIRECT отключает двойную буферизацию (самим mysql и ОС).<br /> <br /> Опции mysqld -MyIsam, если используется (например, для некритичных таблиц):<br /> * '''key_buffer_size''' - размер кэша для хранения индексов;<br /> * '''myisam_recover''' -восстановление битых таблиц при старте сервера.<br /> * '''myisam_repair_threads''' - число потоков восстановления.<br /> * '''myisam_data_pointer_size''' - возможность создания больших первичных ключей в таблицах.<br /> <br /> Опции mysqld - репликации, если используется:<br /> * '''server-id''' - идентификатор сервера.<br /> * '''log-bin''' - место хранение bin-логов; лучше если это будет отдельный диск, высокие требования по скорости и надёжности, малые по объёму.<br /> * '''expire_logs_days''' - автоматическое удаление старых bin-логов.<br /> * '''replicate-do-db''' - реплицируемая БД.<br /> * '''relay-log-space-limit''' - ограничение на объём bin-логов.<br /> <br /> Опции mysqld_safe:<br /> * '''open-files-limit''' - лимит количества открытых файлов для ОС Linux.<br /> * '''log-error''' - файл для логирования ошибок.<br /> * '''pid-file''' - PID файл процесса. <br /> <br /> Опции mysqldump:<br /> * '''max_allowed_packet''' - установка маскимально возможного размера пакета при снятии дампов утилитой mysqldump.<br /> * '''default-character-set''' - кодировка по-умолчанию при снятии дампов БД.<br /> <br /> Опции client:<br /> * '''default-character-set''' - кодировка по-умолчанию при подключении консольным клиентом.<br /> <br /> В качестве примера конфигурации вы также можете использовать примеры конфигурации MySQL ('''/usr/share/mysql/my-innodb-heavy-4G.cnf''').<br /> <br /> Ссылки: <br /> * [http://mysql.ru/docs/man/ http://mysql.ru/docs/man/] - общее руководство по администрированию.<br /> * [http://mysql.ru/docs/man/InnoDB_start.html http://mysql.ru/docs/man/InnoDB_start.html] - параметры настройки InnoDb.<br /> * [http://mysql.ru/docs/man/Replication_Options.html http://mysql.ru/docs/man/Replication_Options.html] - параметры настройки репликации.<br /> * [http://maxq.ru/lib/53/ http://maxq.ru/lib/53/] - рекомендации по настройке InnoDb базы, MyIsam базы.<br /> * [http://mysqltuner.pl/mysqltuner.pl http://mysqltuner.pl/mysqltuner.pl] - скрипт автоматической настройки параметров БД.<br /> <br /> == Набор Perl утилит для работы с MySQL ==<br /> В архиве [[Медиа: mysql_perl_utilites.zip]] размещены файлы:<br /> * '''access.pm''' - параметры доступа к MySQL для остальных скриптов.<br /> * '''extract_myisam.pl''' - выбор MyIsam таблиц из базы и вывод в файл '''tables'''.<br /> * '''convert.pl''' - конвертация таблиц из файла '''tables''' в InnoDb.<br /> * '''drop.pl''' - удаление таблиц, перечисленных в файле '''tables'''.<br /> <br /> Конвертацию можно выполнять только после включения в my.cnf поддержки InnoDb. Следует учитывать, что конвертация больших таблиц может быть очень длительной, поэтому оптимальным будет исключить из конвертации помесячные таблицы с сессиями, наработками и т.п.<br /> Для транзакционной работы они не критичны. Достаточно, что в последующие месяцы эти таблицы также будут создаваться в формате InnoDb. Также можно предварительно отработать конвертацию таблиц на стороннем MySQL сервере.<br /> <br /> Выберите MyIsam таблицы в файл '''tables''' с помощью скрипта '''extract_myisam.pl''', скорректируйте файл '''tables''', оставив только последние месячные и постоянные таблицы.<br /> Затем выполните скрипт '''convert.pl'''.<br /> <br /> == Алгоритм конвертации с репликацией ==<br /> # Включить поддержку InnoDb на slave-сервере.<br /> # Включить поддержку InnoDb на master-сервере.<br /> # Запустить скрипт конвертации в InnoDB (см. ранее) для master-сервера.</div> Mon, 24 Jun 2013 07:33:14 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B5%D0%BA%D0%BE%D0%BC%D0%B5%D0%BD%D0%B4%D0%B0%D1%86%D0%B8%D0%B8_%D0%BF%D0%BE_%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B5_MySQL Свой список шаблонов договоров http://wiki.bitel.ru/index.php/%D0%A1%D0%B2%D0%BE%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 <p>SinTeZWh1te:&#32;</p> <hr /> <div>''Спасибо [http://forum.bgbilling.ru/memberlist.php?mode=viewprofile&amp;u=3161 nik247] за предоставленный пример''<br /> <br /> 1) в конфигурации сервера указываем список фильтров с id шаблонов, которые нужно показывать:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> user.template.filter.1=1<br /> user.template.filter.2=2<br /> user.template.filter.3=1,2,3<br /> &lt;/source&gt;<br /> Важно: id шаблонов указывать через &quot;,&quot; - так как потом используется прямо в SQL (пока сделал так)<br /> 2) в конфигурации пользователя указываем нужный фильтр:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> user.template.filterId=1<br /> &lt;/source&gt;<br /> '''Важно: если фильтр не указать, то выведется пустой список шаблонов.'''<br /> Мне так нужно было, для явного указания шаблонов для пользователей. Кому нужно - измените код.<br /> Если указан '''user.template.filterId=0''', то фильтр вообще не используется - выводит все шаблоны, включая шаблон &quot;По умолчанию&quot;<br /> Ну и сам код:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> package ru.bitel.bgbilling.modules.contract.action;<br /> <br /> import java.sql.*;<br /> import org.w3c.dom.Element;<br /> import ru.bitel.bgbilling.common.BGException;<br /> import ru.bitel.bgbilling.kernel.module.common.bean.User;<br /> import ru.bitel.bgbilling.kernel.module.server.bean.UserManager;<br /> import ru.bitel.bgbilling.server.util.UserMap;<br /> import ru.bitel.common.Preferences;<br /> import java.security.AccessController;<br /> import javax.security.auth.Subject;<br /> import bitel.billing.server.admin.bgsecure.bean.UserLoginModule.UserPrincipal;<br /> import ru.bitel.bgbilling.server.util.Setup;<br /> <br /> public class GetPatternList <br /> extends bitel.billing.server.contract.action.ActionGetPatternList<br /> {<br /> @Override<br /> public void doAction()<br /> throws SQLException, BGException<br /> {<br /> //получаем id текущего пользователя <br /> Integer currentUserId = getCurrentUserId();<br /> //получаем ID фильтра шаблонов с конфигурации пользователя.<br /> int filterId = getTemplateFilterId( currentUserId );<br /> String SqlTemplateFilter = &quot;&quot;;<br /> switch ( filterId )<br /> {<br /> case -1: <br /> {<br /> //вывод пустого списка шаблонов, если в конфиге не указан фильтр.<br /> log.debug(&quot;Custom TEMPLATES: filterId not set:&quot; + filterId ); <br /> SqlTemplateFilter = &quot; WHERE id = -1 &quot;;<br /> break;<br /> }<br /> case 0: <br /> {<br /> //вывод всех шаблонов - для администраторов.<br /> log.debug(&quot;Custom TEMPLATES: admin filterId=&quot; + filterId ); <br /> SqlTemplateFilter = &quot; &quot;;<br /> break;<br /> }<br /> default:<br /> {<br /> log.debug(&quot;Custom TEMPLATES: iserId=&quot; + currentUserId + &quot; filterId=&quot; + filterId );<br /> //считывание фильтров шаблонов с конфигурации от 1 до 99<br /> String tmplIds = &quot;&quot;;<br /> for (int t = 1; t &lt; 100; t++)<br /> {<br /> tmplIds = this.setup.get(&quot;user.template.filter.&quot; + t, null);<br /> //вывод пустого списка шаблонов по умолчанию<br /> SqlTemplateFilter = &quot; WHERE id = -1 &quot;;<br /> //поиск IDs шаблонов договоров<br /> if ( t == filterId ) <br /> {<br /> log.debug(&quot;Custom TEMPLATES: found tmplIds=&quot; + tmplIds ); <br /> SqlTemplateFilter = &quot; WHERE id IN (&quot; + tmplIds + &quot;) &quot;;<br /> break;<br /> }<br /> }<br /> }<br /> }<br /> <br /> //формирование списка шаблона договоров<br /> Element patterns = createElement(rootNode, &quot;patterns&quot;);<br /> //вывод шаблона &quot;по умолчанию&quot; - включаем для Админов<br /> if ( filterId == 0 )<br /> {<br /> if(request.getParameter(&quot;nondef&quot;) == null)<br /> addListItem(patterns, &quot;0&quot;, &quot;\u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E&quot;);<br /> }<br /> String query = &quot;SELECT id, title FROM contract_pattern &quot; + SqlTemplateFilter + &quot; ORDER BY title&quot;;<br /> //log.debug(&quot;Custom TEMPLATES: sql=&quot; + query );<br /> Statement st = con.createStatement();<br /> ResultSet rs;<br /> for(rs = st.executeQuery(query); rs.next(); addListItem(patterns, rs.getString(1), rs.getString(2)));<br /> rs.close();<br /> st.close();<br /> }<br /> <br /> public int getTemplateFilterId (int userId)<br /> throws BGException<br /> {<br /> User user = UserMap.getUser(Integer.valueOf(userId));<br /> String user_config = user.getConfig();<br /> Preferences userConfig = new Preferences(user_config, &quot;\r\n&quot;);<br /> int TemplateFilterId = userConfig.getInt(&quot;user.template.filterId&quot;, -1);<br /> return TemplateFilterId;<br /> }<br /> <br /> public Integer getCurrentUserId()<br /> {<br /> Subject subject = Subject.getSubject( AccessController.getContext() );<br /> if( subject != null )<br /> {<br /> for( UserPrincipal userPrincipal : subject.getPrincipals( UserPrincipal.class ) )<br /> {<br /> return userPrincipal.getUser().getId();<br /> }<br /> }<br /> return null;<br /> }<br /> }<br /> &lt;/source&gt;<br /> Ну и не забываем в конфиге сервера переопределить action:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> dynaction:contract.ActionGetPatternList=ru.bitel.bgbilling.modules.contract.action.GetPatternList<br /> &lt;/source&gt;</div> Tue, 21 May 2013 13:48:26 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B2%D0%BE%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 Свой список шаблонов договоров http://wiki.bitel.ru/index.php/%D0%A1%D0%B2%D0%BE%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 <p>SinTeZWh1te:&#32;</p> <hr /> <div>''Спасибо [http://forum.bgbilling.ru/memberlist.php?mode=viewprofile&amp;u=3161 nik247] за предоставленный пример''<br /> <br /> 1) в конфигурации сервера указываем список фильтров с id шаблонов, которые нужно показывать:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> user.template.filter.1=1<br /> user.template.filter.2=2<br /> user.template.filter.3=1,2,3<br /> &lt;/source&gt;<br /> Важно: id шаблонов указывать через &quot;,&quot; - так как потом используется прямо в SQL (пока сделал так)<br /> 2) в конфигурации пользователя указываем нужный фильтр:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> user.template.filterId=1<br /> &lt;/source&gt;<br /> '''Важно: если фильтр не указать, то выведется пустой список шаблонов.'''<br /> Мне так нужно было, для явного указания шаблонов для пользователей. Кому нужно - измените код.<br /> Если указан '''user.template.filterId=0''', то фильтр вообще не используется - выводит все шаблоны, включая шаблон &quot;По умолчанию&quot;<br /> Ну и сам код:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> package ru.bitel.bgbilling.modules.contract.action;<br /> <br /> import java.sql.*;<br /> import org.w3c.dom.Element;<br /> import ru.bitel.bgbilling.common.BGException;<br /> import ru.bitel.bgbilling.kernel.module.common.bean.User;<br /> import ru.bitel.bgbilling.kernel.module.server.bean.UserManager;<br /> import ru.bitel.bgbilling.server.util.UserMap;<br /> import ru.bitel.common.Preferences;<br /> import java.security.AccessController;<br /> import javax.security.auth.Subject;<br /> import bitel.billing.server.admin.bgsecure.bean.UserLoginModule.UserPrincipal;<br /> import ru.bitel.bgbilling.server.util.Setup;<br /> <br /> public class GetPatternList <br /> extends bitel.billing.server.contract.action.ActionGetPatternList<br /> {<br /> @Override<br /> public void doAction()<br /> throws SQLException, BGException<br /> {<br /> //получаем id текущего пользователя <br /> Integer currentUserId = getCurrentUserId();<br /> //получаем ID фильтра шаблонов с конфигурации пользователя.<br /> int filterId = getTemplateFilterId( currentUserId );<br /> String SqlTemplateFilter = &quot;&quot;;<br /> switch ( filterId )<br /> {<br /> case -1: <br /> {<br /> //вывод пустого списка шаблонов, если в конфиге не указан фильтр.<br /> log.debug(&quot;Custom TEMPLATES: filterId not set:&quot; + filterId ); <br /> SqlTemplateFilter = &quot; WHERE id = -1 &quot;;<br /> break;<br /> }<br /> case 0: <br /> {<br /> //вывод всех шаблонов - для администраторов.<br /> log.debug(&quot;Custom TEMPLATES: admin filterId=&quot; + filterId ); <br /> SqlTemplateFilter = &quot; &quot;;<br /> break;<br /> }<br /> default:<br /> {<br /> log.debug(&quot;Custom TEMPLATES: iserId=&quot; + currentUserId + &quot; filterId=&quot; + filterId );<br /> //считывание фильтров шаблонов с конфигурации<br /> String tmplIds = &quot;&quot;;<br /> for (int t = 1; tmplIds != null; t++)<br /> {<br /> tmplIds = this.setup.get(&quot;user.template.filter.&quot; + t, null);<br /> //вывод пустого списка шаблонов по умолчанию<br /> SqlTemplateFilter = &quot; WHERE id = -1 &quot;;<br /> //поиск IDs шаблонов договоров<br /> if ( t == filterId ) <br /> {<br /> log.debug(&quot;Custom TEMPLATES: found tmplIds=&quot; + tmplIds ); <br /> SqlTemplateFilter = &quot; WHERE id IN (&quot; + tmplIds + &quot;) &quot;;<br /> break;<br /> }<br /> }<br /> }<br /> }<br /> <br /> //формирование списка шаблона договоров<br /> Element patterns = createElement(rootNode, &quot;patterns&quot;);<br /> //вывод шаблона &quot;по умолчанию&quot; - включаем для Админов<br /> if ( filterId == 0 )<br /> {<br /> if(request.getParameter(&quot;nondef&quot;) == null)<br /> addListItem(patterns, &quot;0&quot;, &quot;\u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E&quot;);<br /> }<br /> String query = &quot;SELECT id, title FROM contract_pattern &quot; + SqlTemplateFilter + &quot; ORDER BY title&quot;;<br /> //log.debug(&quot;Custom TEMPLATES: sql=&quot; + query );<br /> Statement st = con.createStatement();<br /> ResultSet rs;<br /> for(rs = st.executeQuery(query); rs.next(); addListItem(patterns, rs.getString(1), rs.getString(2)));<br /> rs.close();<br /> st.close();<br /> }<br /> <br /> public int getTemplateFilterId (int userId)<br /> throws BGException<br /> {<br /> User user = UserMap.getUser(Integer.valueOf(userId));<br /> String user_config = user.getConfig();<br /> Preferences userConfig = new Preferences(user_config, &quot;\r\n&quot;);<br /> int TemplateFilterId = userConfig.getInt(&quot;user.template.filterId&quot;, -1);<br /> return TemplateFilterId;<br /> }<br /> <br /> public Integer getCurrentUserId()<br /> {<br /> Subject subject = Subject.getSubject( AccessController.getContext() );<br /> if( subject != null )<br /> {<br /> for( UserPrincipal userPrincipal : subject.getPrincipals( UserPrincipal.class ) )<br /> {<br /> return userPrincipal.getUser().getId();<br /> }<br /> }<br /> return null;<br /> }<br /> }<br /> &lt;/source&gt;<br /> Ну и не забываем в конфиге сервера переопределить action:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> dynaction:contract.ActionGetPatternList=ru.bitel.bgbilling.modules.contract.action.GetPatternList<br /> &lt;/source&gt;</div> Tue, 21 May 2013 13:24:48 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B2%D0%BE%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 Свой список шаблонов договоров http://wiki.bitel.ru/index.php/%D0%A1%D0%B2%D0%BE%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 <p>SinTeZWh1te:&#32;Новая страница: «''Спасибо [http://forum.bgbilling.ru/memberlist.php?mode=viewprofile&amp;u=3161 nik247] за предоставленный пример'' 1) в конфигур…»</p> <hr /> <div>''Спасибо [http://forum.bgbilling.ru/memberlist.php?mode=viewprofile&amp;u=3161 nik247] за предоставленный пример''<br /> <br /> 1) в конфигурации сервера увказываем список фильтров с id шаблонов, которые нужно показывать:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> user.template.filter.1=1<br /> user.template.filter.2=2<br /> user.template.filter.3=1,2,3<br /> &lt;/source&gt;<br /> Важно: id шаблонов указывать через &quot;,&quot; - так как потом используется прямо в SQL (пока сделал так)<br /> 2) в конфигурации пользователя указываем нужный фильтр:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> user.template.filterId=1<br /> &lt;/source&gt;<br /> '''Важно: если фильтр не указать, то выведется пустой список шаблонов.'''<br /> Мне так нужно было, для явного указания шаблонов для пользователей. Кому нужно - измените код.<br /> Если указан '''user.template.filterId=0''', то фильтр вообще не используется - выводит все шаблоны, включая шаблон &quot;По умолчанию&quot;<br /> Ну и сам код:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> package ru.bitel.bgbilling.modules.contract.action;<br /> <br /> import java.sql.*;<br /> import org.w3c.dom.Element;<br /> import ru.bitel.bgbilling.common.BGException;<br /> import ru.bitel.bgbilling.kernel.module.common.bean.User;<br /> import ru.bitel.bgbilling.kernel.module.server.bean.UserManager;<br /> import ru.bitel.bgbilling.server.util.UserMap;<br /> import ru.bitel.common.Preferences;<br /> import java.security.AccessController;<br /> import javax.security.auth.Subject;<br /> import bitel.billing.server.admin.bgsecure.bean.UserLoginModule.UserPrincipal;<br /> import ru.bitel.bgbilling.server.util.Setup;<br /> <br /> public class GetPatternList <br /> extends bitel.billing.server.contract.action.ActionGetPatternList<br /> {<br /> @Override<br /> public void doAction()<br /> throws SQLException, BGException<br /> {<br /> //получаем id текущего пользователя <br /> Integer currentUserId = getCurrentUserId();<br /> //получаем ID фильтра шаблонов с конфигурации пользователя.<br /> int filterId = getTemplateFilterId( currentUserId );<br /> String SqlTemplateFilter = &quot;&quot;;<br /> switch ( filterId )<br /> {<br /> case -1: <br /> {<br /> //вывод пустого списка шаблонов, если в конфиге не указан фильтр.<br /> log.debug(&quot;Custom TEMPLATES: filterId not set:&quot; + filterId ); <br /> SqlTemplateFilter = &quot; WHERE id = -1 &quot;;<br /> break;<br /> }<br /> case 0: <br /> {<br /> //вывод всех шаблонов - для администраторов.<br /> log.debug(&quot;Custom TEMPLATES: admin filterId=&quot; + filterId ); <br /> SqlTemplateFilter = &quot; &quot;;<br /> break;<br /> }<br /> default:<br /> {<br /> log.debug(&quot;Custom TEMPLATES: iserId=&quot; + currentUserId + &quot; filterId=&quot; + filterId );<br /> //считывание фильтров шаблонов с конфигурации<br /> String tmplIds = &quot;&quot;;<br /> for (int t = 1; tmplIds != null; t++)<br /> {<br /> tmplIds = this.setup.get(&quot;user.template.filter.&quot; + t, null);<br /> //вывод пустого списка шаблонов по умолчанию<br /> SqlTemplateFilter = &quot; WHERE id = -1 &quot;;<br /> //поиск IDs шаблонов договоров<br /> if ( t == filterId ) <br /> {<br /> log.debug(&quot;Custom TEMPLATES: found tmplIds=&quot; + tmplIds ); <br /> SqlTemplateFilter = &quot; WHERE id IN (&quot; + tmplIds + &quot;) &quot;;<br /> break;<br /> }<br /> }<br /> }<br /> }<br /> <br /> //формирование списка шаблона договоров<br /> Element patterns = createElement(rootNode, &quot;patterns&quot;);<br /> //вывод шаблона &quot;по умолчанию&quot; - включаем для Админов<br /> if ( filterId == 0 )<br /> {<br /> if(request.getParameter(&quot;nondef&quot;) == null)<br /> addListItem(patterns, &quot;0&quot;, &quot;\u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E&quot;);<br /> }<br /> String query = &quot;SELECT id, title FROM contract_pattern &quot; + SqlTemplateFilter + &quot; ORDER BY title&quot;;<br /> //log.debug(&quot;Custom TEMPLATES: sql=&quot; + query );<br /> Statement st = con.createStatement();<br /> ResultSet rs;<br /> for(rs = st.executeQuery(query); rs.next(); addListItem(patterns, rs.getString(1), rs.getString(2)));<br /> rs.close();<br /> st.close();<br /> }<br /> <br /> public int getTemplateFilterId (int userId)<br /> throws BGException<br /> {<br /> User user = UserMap.getUser(Integer.valueOf(userId));<br /> String user_config = user.getConfig();<br /> Preferences userConfig = new Preferences(user_config, &quot;\r\n&quot;);<br /> int TemplateFilterId = userConfig.getInt(&quot;user.template.filterId&quot;, -1);<br /> return TemplateFilterId;<br /> }<br /> <br /> public Integer getCurrentUserId()<br /> {<br /> Subject subject = Subject.getSubject( AccessController.getContext() );<br /> if( subject != null )<br /> {<br /> for( UserPrincipal userPrincipal : subject.getPrincipals( UserPrincipal.class ) )<br /> {<br /> return userPrincipal.getUser().getId();<br /> }<br /> }<br /> return null;<br /> }<br /> }<br /> &lt;/source&gt;<br /> Ну и не забываем в конфиге сервера переопределить action:<br /> &lt;source lang=&quot;java&quot;&gt;<br /> dynaction:contract.ActionGetPatternList=ru.bitel.bgbilling.modules.contract.action.GetPatternList<br /> &lt;/source&gt;</div> Tue, 21 May 2013 13:22:46 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B2%D0%BE%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 Заглавная страница http://wiki.bitel.ru/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Добро пожаловать на BG Биллинг Wiki ==<br /> Здесь вы можете получить больше информации о продукте BGBilling, а также поделиться своим опытом с другими пользователями. В то время как документация часто предоставляет общие сведения о системе и ее настройках, здесь вы встретите конкретные примеры.<br /> <br /> == Полезные ресурсы ==<br /> * &lt;b&gt;[[Как выложить статью на WiKi]]&lt;/b&gt;.<br /> * [[Оформление статей]].<br /> * [http://wiki.bitel.ru База знаний ООО &quot;Бител&quot;], на ней находятся статьи на общие темы, в том числе посвящённые используемым технологиям [http://wiki.bitel.ru/index.php/REGEXP REGEXP], [http://wiki.bitel.ru/index.php/XML XML], [http://wiki.bitel.ru/index.php/FO%28P%29 FO(P)] и другим.<br /> * [http://forum.bgbilling.ru/ Форум техподдержки BGBilling].<br /> <br /> == Специалисты ==<br /> Уважаемые &quot;продвинутые пользователи&quot;. Здесь вы можете располагать записи со своими контактами для оказания воздмездной или безвозмездной помощи по настройке системы BGBilling пользователям, не столь далеко продвинувшимся. Желательно указывать ваши контактные данные и &quot;специализацию&quot;.<br /> {| border=&quot;1&quot; cellpadding=&quot;2&quot; cellspacing=&quot;0&quot;<br /> |- valign=top align=&quot;center&quot; bgcolor=&quot;#eeeeee&quot; <br /> | Имя || Специализация || Контакт || Примечания<br /> |-<br /> | Рустам Тазуркаев || Mikrotik, переход с NetUp, CISCO || [[Изображение:Cpec_2_contact.png]] &lt;!-- ICQ: 648986--&gt; ||<br /> |-<br /> | Михаил Чернобаев || Скрипты биллинга, FreeBSD MPD || ICQ: 262986492 || Скриптование в биллинге, возможны крупные проекты.<br /> |- <br /> | Борис Близнюков || Скрипты биллинга, CISCO, Voip, Mera || [[Изображение:Cpec_4_contact.png]] &lt;!--ICQ: 1996944--&gt; || Только бесплатные краткие консультации. Очень хороший специалист по CISCO.<br /> |- <br /> | Ахмат Габуев || Интеграция биллинга с 1с 7.7, 1с 8.1 || ICQ: 566784343 || Краткие консультации. Возможна работа под заказ.<br /> |-<br /> | Андрей Бехтерев || Cisco, UNIX, ISP, Asterisk || ICQ: 7021464 WEB: http://behterev.su/ || Обширный спектр оборудования. Консалтинг.<br /> |-<br /> | Гершевич М.М. || Доработка конфигурации 1С и прочего ПО. || Тел. +79145584000 +7-(4162)-518-777 WEB: http://www.amurimpulse.ru/ mail: mike1008@mail.ru || Консалтинг. Информационная безопасность. Интеграция биллинга. Крупные проекты. Работа под заказ.<br /> |-<br /> | Конференция BGBilling || вопросы касаемо системы BGBilling || bgbilling@conference.jabber.ru || Администраторы АСР BGBillig(иногда и разработчики) помогают друг другу в разных вопросах.<br /> |}<br /> <br /> == Установка ==<br /> * [[Установка на gentoo]]<br /> * [[Установка на Sun Solaris]]<br /> * [[Установка на Slackware]]<br /> * [[Установка на FreeBSD]]<br /> * [[Установка на Ubuntu 8 Desktop]]<br /> * [[Установка на Ubuntu 9.10 Desktop]]<br /> <br /> === Перенос данных в биллинг ===<br /> *[[Пример конвертера данных из csv-файлов в базу BGBilling]]<br /> *[[Пример конвертера данных из CSV-файлов в базу BGBilling - 2]]<br /> *[[Пример конвертера данных из CSV-файлов в базу BGBilling - 3]]<br /> *[[Конвертер базы Netup]]<br /> *[[Примеры конвертеров данных из других биллинговых систем]]<br /> <br /> == Администрирование ==<br /> * [[Разграничение прав действий]]<br /> * [[Настройка безопасности сервера биллинга и компонентов биллинга]]<br /> * [[Принудительный останов процессов биллинга]]<br /> * [[Использование подписанного SSL сертификата]]<br /> * [[Запуск scheduler и data_loader с другими портами управления]]<br /> * [[bg-snmp-management|Мониторинг java-процессов по snmp]]<br /> * [[Скрипты автостарта демонов bgbilling для Debian]]<br /> * [[javaws|Запуск BGBillingClient через Java Web Start]]<br /> <br /> == Настройка вспомогательного ПО ==<br /> *[[Проксирование обращений к BGBillingServer посредством nginx]]<br /> <br /> === MySQL ===<br /> *[[Рекомендации по настройке MySQL]]<br /> *[[database backup|Backup MySQL базы с помощью snapshot'ов (Linux, LVM)]]<br /> *[[Настройка MySQL репликации]]<br /> *[[Установка триггера в MySQL для отслеживания изменений]]<br /> *[[Скрипт восстановления MySQL репликации]]<br /> <br /> === NetFlow ===<br /> *[[Настройка NetFlow-агента IPCAD]]<br /> *[[Разделение NetFlow-потоков]]<br /> <br /> == Технологии ==<br /> *[http://wiki.bitel.ru/index.php/REGEXP REGEXP]<br /> *[[MySQL REGEXP]]<br /> *[http://wiki.bitel.ru/index.php/XML XML]<br /> *[[XSLT]]<br /> *[http://wiki.bitel.ru/index.php/FO%28P%29 FO(P)]<br /> === Разработка ===<br /> *[[Отладка action'ов в IntelliJ IDEA]]<br /> *[[Разработка динамического кода в IDE Eclipse]]<br /> <br /> == [[XSLT]] шаблоны ==<br /> *[[Добавление параметров договора на страницу личного кабинета]]<br /> &lt;!-- *[[Красивые графики статистики в модуле IPN]] --&gt;<br /> *[[Карточки договора]]<br /> *[[Создание XSLT/FO шаблона со штрихкодами]]<br /> *[[Подстановка данных в зависимости от текущего пользователя биллинга]]<br /> *[[Генерация прайса модуля IP телефонии в карточке договора]]<br /> <br /> === Счета ===<br /> *[[Печать счета-фактуры и акта на отдельных листах]]<br /> *[[Расширенные счета модуля бухгалтерии]]<br /> *[[Квитанция телефонии физ. лицам]]<br /> *[[Шаблоны вывода названия месяца]]<br /> *[[Изменения в шаблоне в зависимости от месяца документа]]<br /> *[[Добавление новых шрифтов в FO шаблоны]]<br /> <br /> == Интеграция с внешними системами ==<br /> * [[Прямая интеграция с платежными терминалами ЭСФОР / SFOUR]]<br /> * [[Интеграция с платежной системой с использованием модуля Card]]<br /> * [[Интеграция с платежной системой Robokassa]]<br /> * [[SMS рассылка через SMPP]]<br /> * [[SMS рассылка через SMPP по средствам дин кода в 5.2]]<br /> * [[Система учета &quot;Заявки и Наряды&quot; на java]]<br /> * [[Bash скрипт-отсылка смс через телефон при отсутствие ping на заданный узел]]<br /> * [[Запросы в личный кабинет пользователя сторонними системами]]<br /> * [[Запросы к серверу биллинга сторонними системами]]<br /> <br /> === 1С ===<br /> * [[Пример обращения к биллингу из 1С v.7.7]]<br /> * [[amurimpulse.ru bgbilling]]<br /> * [[Integrator 1C-BGBilling]]<br /> * [[Пример интеграции с 1С v.7.7]]<br /> * [[Пример интеграции с 1С v.8.1]]<br /> * [[Установка unload_status счета через HTTP-запрос]]<br /> <br /> == Скрипты BGBS ==<br /> *[[Логгирование в скриптах поведения]]<br /> <br /> === Комплексные решения ===<br /> *[[Предоставление тестового периода пользования услугой]]<br /> *[[Организация системы отслеживания и отключения КТВ должников на BGBS с использованием CRM плагина]]<br /> *[[Автоматизация подключений VPN-клиентов с использованием CRM плагина]]<br /> *[[Пример автоматизации подключения новых клиентов]]<br /> <br /> === Глобальные скрипты ===<br /> *[[Скрипт глобальный отмены перехода на тарифы при неоплате]]<br /> *[[Скрипт предоставление скидки пенсионерам]]<br /> *[[Скрипт создания субдоговоров по шаблону]]<br /> *[[Глобальное событие запуска сервера]]<br /> *[[Перемещение в группу через 3 месяца если не было движения денег в наработке]]<br /> *[[Поиск и изменение статусов у договоров]]<br /> *[[Получение списка доступных действий в SQL]]<br /> *[[Глобальный скрипт для удаления старых таблиц]]<br /> <br /> === Пользовательские библиотеки скриптов ===<br /> *[[Пересчеты и бонусы]]<br /> *[[Архивирование логов netflow и radius accaunting]]<br /> <br /> === Ядро ===<br /> *[[Смена тарифного плана по заданию пользователя]]<br /> *[[Валидация текстового параметра]]<br /> *[[Проверка ИНН/КПП при вводе]]<br /> *[[Проверка параметра договора перед изменением]]<br /> *[[Обработка смены параметра договора]]<br /> *[[Создание списка дополнительных действий для договора]]<br /> *[[Обработка события создания договора]]<br /> *[[Обработка события &quot;добавление услуги RSCM в договор&quot; . Скипт сменяет тариф, подключает абонплату ]]<br /> *[[Приостановление договора клиентом через WEB]]<br /> *[[Скрипт проверки баланса и отключения договора]]<br /> *[[Изменение стандартной логики перетирания статусов]]<br /> *[[Пример продажи OEM ключей с помощью скрипта]]<br /> *[[Пример копирования тарифного плана]]<br /> *[[Получение текущего пользователя биллинга]]<br /> *[[Запуск скрипта до и после акшена]]<br /> *[[Примеры скриптов до и после акшена]]<br /> *[[Примеры динамического кода акшена и веб-сервисов]]<br /> *[[Начисление бонусов на счет при платежах определенного типа]]<br /> *[[Включение должников по приходу платежа]]<br /> *[[Снижение лимита при внесении расхода]]<br /> *[[Синхронизация услуг договора в соответствии с тарифными планами]]<br /> *[[Добавление группы и снятие в зависимости от статуса]]<br /> *[[Управление статусом договора по состоянию баланса]]<br /> *[[Запрет на вход в личный кабинет с закрытых договоров]]<br /> *[[Переход на понижающий тариф только со следующего месяца]]<br /> *[[Пример создания своего интерфейса в клиенте]]<br /> *[[Метки услуг]]<br /> *[[Сравнение прав пользователей]]<br /> *[[Свой список шаблонов договоров]]<br /> <br /> === Модуль Bill ===<br /> *[[Создание счета в модуле Bill]]<br /> *[[Создание счета из суммы платежей по классу договоров]]<br /> *[[Создание счета по таблице позиций]]<br /> *[[Создание счета и счет-фактур в модуле Bill(выполнение тех же действий что и руками)]]<br /> *[[Распечатка счетов в pdf по событию генерации счета]]<br /> *[[Внешняя программа на JAVA для синхронизации номеров счетов и актов выполненных работ (версия BGBilling 5.0)]]<br /> <br /> === Модуль DialUp ===<br /> *[[Запуск переначисления в модуле DialUp]]<br /> *[[Передача ACCEPT вместо REJECT вместе с доп. аттрибутами]]<br /> *[[Обработка запроса учетного периода]]<br /> *[[Переинициализация тарифа в пределах сессии | Обработка запроса учетного периода (переинициализация тарифа в пределах сессии) ]]<br /> *[[Ограничение доступа для различных групп пользователей для BGRadiusDialup]]<br /> *[[Детальное информирование абонентов о причинах ошибки 691]]<br /> *[[Аутентификация с учетом Calling-Id-Station]]<br /> *[[Доп. действие сброса активных соединений]]<br /> *[[Открытие абонплаты по первой установке соединения]]<br /> *[[Пересчет трафика по данным Radius (при потерянных Netflow-логах)]]<br /> *[[Отключение Fake сессий при приходе платежа]]<br /> *[[Ограничение доступа на основе объектов]]<br /> <br /> === Модуль DialUp / Cкрипты предобработки RADIUS запросов ===<br /> * [[Уcтановка услуги типа &quot;Время&quot; для BGRadiusDialup]]<br /> * [[Установка фиксированного пароля]]<br /> * [[Нормализация параметра Acct-Session-Id у маршрутизатора Cisco]]<br /> * [[Разделение атрибута User-Name на логин и пароль]]<br /> * [[Вынос MAC адреса из cisco-avp-pair в Calling-Station-Id]]<br /> * [[Копирование Тunnel-Client-Endpoint/Tunnel-Server-Endpoint в Calling-Station-Id/Called-Station-Id]]<br /> * [[Замена radius-атрибутов при авторизации]]<br /> <br /> === Модуль Inet / Cкрипты предобработки RADIUS запросов ===<br /> * [[Вынос MAC адреса из cisco-avp-pair в Calling-Station-Id для модуля Inet]]<br /> <br /> === Модуль СerberСrypt ===<br /> *[[Изменение подписки карты через web (cerbercrypt)]]<br /> *[[Управление подписками через веб (cerbercrypt)]]<br /> <br /> === Модуль NPay ===<br /> *[[Определение размера абонентской платы]]<br /> *[[Запуск переначисления в модуле NPay]]<br /> *[[Дебетовые абонплаты. Снятие штрафа за разблокировку.]]<br /> *[[Снятие абонентской платы в дебитовых договорах]]<br /> *[[Предварительное уведомление о блокировке по дебетовым абонплатам]]<br /> <br /> === Модуль Phone ===<br /> *[[При создании поинта модуля Phone добавление в него абонплат]]<br /> *[[Закрытие_телефонных_договоров]]<br /> <br /> === Модуль RSCM ===<br /> *[[Запуск переначисления в модуле RSCM]]<br /> *[[Перенос суммы расхода в наработку RSCM модуля]]<br /> <br /> === Модуль VoiceIp ===<br /> *[[Определение стоимости звонка VoiceIp]]<br /> <br /> === Модуль VoiceIp / Cкрипты предобработки RADIUS запросов ===<br /> * [[Идентификация Voip оператора по подсети (транзит)]]<br /> * [[Установка параметров звонка Voip]]<br /> * [[Установка фиксированного пароля]]<br /> * [[Разделение атрибута User-Name на логин и пароль]]<br /> * [[Замена radius-атрибутов при авторизации]]<br /> <br /> === Плагин CRM ===<br /> *[[Обработка выполненных задач в журнале задач]]<br /> *[[Обработка задач по событию ядра &quot;Поступление платежа&quot;, создание новой задачи и изменение существующей]]<br /> *[[Пример получения информации о задаче]]<br /> *[[Уведомления монтажников о новых активных задачах путем отправки SMS XML запросом]]<br /> <br /> === Плагин CashCheck ===<br /> *[[Чек: добавление позиции]]<br /> *[[Чек: завершение формирования]]<br /> *[[Примеры скриптов CashCheck]]<br /> <br /> === Плагин Documents ===<br /> *[[Создание копий документа на договорах]]<br /> <br /> == Решения для модулей и плагинов ==<br /> <br /> === Модуль DialUP ===<br /> *[[Настройка Lucent Ascend MAX6000 в качестве DialUP сервера]]<br /> *[[Настройка Dial-IN сервера FreeBSD PPPD]]<br /> *[[Настройка VPN сервера LINUX PPPD + POPTOP]]<br /> *[[Настройка шейпера в LINUX PPPD]]<br /> *[[Настройка VPN сервера FreeBSD MPD]]<br /> *[[Настройка PPPoE сервера на Cisco-роутере]]<br /> *[[Настройка PPPoE и/или РРТР (VPN) на Mikrotik]]<br /> *[[Проблема с прохождением update пакетов и сброса сессий в Debian и Ubuntu дистрибутивах]]<br /> *[[Настройка Dial-IN Windows RRAS сервера]]<br /> *[[VPN доступ с повременной тарификацией на базе FreeBSD MPD]]<br /> *[[Организация семейства UNLIMIT тарифов на базе FreeBSD MPD]]<br /> *[[Примеры тарифных планов VPN/DialUp]]<br /> *[[Отключение сессий по PoD на CISCO]]<br /> *[[Пример скрипта управления уровнями BGRadiusDialup]]<br /> *[[Настройка cisco с поддеркой ISG]]<br /> *[[Настройка BGBilling c поддеркой ISG]]<br /> *[[Настройка BGBilling с RedBack SmartEdge (PPPOE)]]<br /> <br /> === Модуль E-Mail ===<br /> *[[Почтовая система Exim + Cyrus + OpenLDAP на FreeBSD]]<br /> *[[Postfix/MySQL/BGBilling]]<br /> *[[Postfix+dovecot+ldap]]<br /> *[[Postfix+Mysql+Virtual domains]]<br /> <br /> === Модуль Inet ===<br /> *[[Схемы подключения]]<br /> *[[Конвертеры из IPN в INET]]<br /> *[[ISG, схема со стартом сессии и ее авторизацией по IP, выдача адресов на основе option82]]<br /> <br /> === Модуль IPN ===<br /> *[[IP/VPN]]<br /> *[[Примеры тарифных планов IPN]]<br /> *[[Настройка BGIPNNetflowCollector]]<br /> *[[Методика определения причины отсутствия трафика в отчете договора]]<br /> *[[Связка с flow-tools]]<br /> *[[Экспорт Netflow-данных в формат Nfdump]]<br /> *[[Реалиазация шлюза на Cisco]]<br /> *[[Реализация шлюзов на BeanShell,примеры стандартных и других шлюзов]] (Manad, Cisco, Zyxel, Mikrotik)<br /> *[[Изменения в manad для работы с одним pipe на множество IP адресов]]<br /> *[[FreeBSD manad, понимающий изменения правил в тарифах]]<br /> *[[Табличный FreeBSD manad, понимающий изменения правил в тарифах]]<br /> *[[Пример реализации скриптового универсального шлюза]]<br /> *[[Конвертер привязок услуг dialup в привязки ipn]]<br /> *[[Реализация скрипта Manad ]]<br /> *[[Настройка шлюза Mikrotik]]<br /> *[[Обновление номеров интерфейсов при замене роутера]]<br /> <br /> === Модуль Phone ===<br /> * [[Конвертация и загрузка тарифов Телефонии в биллинг]]<br /> * [[Примеры тарифных планов Телефонии]]<br /> * [[Примеры реализации конверторов логов]]<br /> * [[Генератор отчётности для Совинтел]]<br /> <br /> === Модуль VoiceIP ===<br /> *[[Интеграция Asterisk и BGBilling (Accounting) посредством скрипта предобработки запросов Radius]]<br /> *[[Интеграция Asterisk и BGBilling (Accounting) посредством изменения программного кода Asterisk]]<br /> *[[Интеграция c MVTS]]<br /> *[[Интеграция c Cisco Call Manager Express (CME)]]<br /> *[[Карточная IVR система на базе Cisco]]<br /> *[[Примеры IVR скриптов для Cisco]]<br /> *[[Пример настройки Cisco AS5350]]<br /> <br /> === Модуль Reports ===<br /> *[[Редактирование отчетов в iReport]]<br /> *[[Примеры отчётов]]<br /> *[[Использование отчётов для организации универсального поиска]]<br /> <br /> === Плагин Dispatch ===<br /> *[[Импорт старой схемы рассылок баланса в Dispatch]]<br /> <br /> == SQL-запросы ==<br /> *[[Схема связки таблиц тарифов]]<br /> *[[Разные SQL-запросы]]<br /> *[[SQL-запрос: кто сколько платит на каждом тарифе]]<br /> *[[Получение цен тарифов]]<br /> *[[Работа с группами, битовые маски]]<br /> *[[наработка по абонентке и услугам за месяц]]<br /> <br /> <br /> === CerberCrypt ===<br /> *[[Модуль CerberCrypt: Разные SQL-запросы]]<br /> *[[Модуль CerberCrypt: Поиск битых SQL-связей]]<br /> <br /> == Веб-Интерфейс ==<br /> *[[Свой action в личном кабинете]]<br /> **[[WebAction_CustomSuspend]] - управление статусом договора (v5.0)<br /> *[[Изменение параметров договора из личного кабинета]]<br /> *[[Как убрать ненужные действия в web]]<br /> <br /> == Протоколы ==<br /> *[[Протокол дилерский платежей]]<br /> *[[Протоколы, поддержанные в модуле MPS]]<br /> *[[Протоколы, поддержанные в модуле Phone]]<br /> *[[Медиа: Enaza.zip]]<br /> *[[Медиа: Payonline.zip]]<br /> <br /> == Faq ==<br /> * [[Не запускается служба BSBillingServer под Windows]]<br /> * [[Вопросы вместо русских букв]]<br /> * [[Что происходит с пользователями при рестарте сервера биллинга и BGRadiusDialup]]<br /> * [[Тарификация максимального трафика]]<br /> * [[Field ... doesn't have a default value ]]<br /> * [[Character set ‘cp1251' is not a compiled character set and is not specified in the ‘C:\mysql\\share\charsets\Index.xml’ file ]]<br /> * [[com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown database 'bgbilling' ]]<br /> * [[Договор не отображается в поиске]]<br /> * [[PPPD проблема с сессиями больше 4ГБ]]<br /> * [[Меню личного кабинета]]<br /> * [[Java.lang.NoClassDefFoundError:_javax/xml/bind/DataBindingException|FreeBSD: Java.lang.NoClassDefFoundError: javax/xml/bind/DataBindingException]]<br /> * [[Manad: после некоторого количества договоров начинает передавать данные на биллинг неправильно ]]<br /> * [[Ошибка выполнения скиптов: Undefined argument:]]<br /> * [[Ошибка в логе &quot;Too many open files&quot;]]<br /> * [[Ошибка в клиенте &quot;Action NOT FOUND!..&quot;]]</div> Tue, 21 May 2013 13:17:34 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 Заглавная страница http://wiki.bitel.ru/index.php/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 <p>SinTeZWh1te:&#32;Отмена правки 3349 участника SonolepIr (обсуждение)</p> <hr /> <div>== Добро пожаловать на BG Биллинг Wiki ==<br /> Здесь вы можете получить больше информации о продукте BGBilling, а также поделиться своим опытом с другими пользователями. В то время как документация часто предоставляет общие сведения о системе и ее настройках, здесь вы встретите конкретные примеры.<br /> <br /> == Полезные ресурсы ==<br /> * &lt;b&gt;[[Как выложить статью на WiKi]]&lt;/b&gt;.<br /> * [[Оформление статей]].<br /> * [http://wiki.bitel.ru База знаний ООО &quot;Бител&quot;], на ней находятся статьи на общие темы, в том числе посвящённые используемым технологиям [http://wiki.bitel.ru/index.php/REGEXP REGEXP], [http://wiki.bitel.ru/index.php/XML XML], [http://wiki.bitel.ru/index.php/FO%28P%29 FO(P)] и другим.<br /> * [http://forum.bgbilling.ru/ Форум техподдержки BGBilling].<br /> <br /> == Специалисты ==<br /> Уважаемые &quot;продвинутые пользователи&quot;. Здесь вы можете располагать записи со своими контактами для оказания воздмездной или безвозмездной помощи по настройке системы BGBilling пользователям, не столь далеко продвинувшимся. Желательно указывать ваши контактные данные и &quot;специализацию&quot;.<br /> {| border=&quot;1&quot; cellpadding=&quot;2&quot; cellspacing=&quot;0&quot;<br /> |- valign=top align=&quot;center&quot; bgcolor=&quot;#eeeeee&quot; <br /> | Имя || Специализация || Контакт || Примечания<br /> |-<br /> | Рустам Тазуркаев || Mikrotik, переход с NetUp, CISCO || [[Изображение:Cpec_2_contact.png]] &lt;!-- ICQ: 648986--&gt; ||<br /> |-<br /> | Михаил Чернобаев || Скрипты биллинга, FreeBSD MPD || ICQ: 262986492 || Скриптование в биллинге, возможны крупные проекты.<br /> |- <br /> | Борис Близнюков || Скрипты биллинга, CISCO, Voip, Mera || [[Изображение:Cpec_4_contact.png]] &lt;!--ICQ: 1996944--&gt; || Только бесплатные краткие консультации. Очень хороший специалист по CISCO.<br /> |- <br /> | Ахмат Габуев || Интеграция биллинга с 1с 7.7, 1с 8.1 || ICQ: 566784343 || Краткие консультации. Возможна работа под заказ.<br /> |-<br /> | Андрей Бехтерев || Cisco, UNIX, ISP, Asterisk || ICQ: 7021464 WEB: http://behterev.su/ || Обширный спектр оборудования. Консалтинг.<br /> |-<br /> | Гершевич М.М. || Доработка конфигурации 1С и прочего ПО. || Тел. +79145584000 +7-(4162)-518-777 WEB: http://www.amurimpulse.ru/ mail: mike1008@mail.ru || Консалтинг. Информационная безопасность. Интеграция биллинга. Крупные проекты. Работа под заказ.<br /> |-<br /> | Конференция BGBilling || вопросы касаемо системы BGBilling || bgbilling@conference.jabber.ru || Администраторы АСР BGBillig(иногда и разработчики) помогают друг другу в разных вопросах.<br /> |}<br /> <br /> == Установка ==<br /> * [[Установка на gentoo]]<br /> * [[Установка на Sun Solaris]]<br /> * [[Установка на Slackware]]<br /> * [[Установка на FreeBSD]]<br /> * [[Установка на Ubuntu 8 Desktop]]<br /> * [[Установка на Ubuntu 9.10 Desktop]]<br /> <br /> === Перенос данных в биллинг ===<br /> *[[Пример конвертера данных из csv-файлов в базу BGBilling]]<br /> *[[Пример конвертера данных из CSV-файлов в базу BGBilling - 2]]<br /> *[[Пример конвертера данных из CSV-файлов в базу BGBilling - 3]]<br /> *[[Конвертер базы Netup]]<br /> *[[Примеры конвертеров данных из других биллинговых систем]]<br /> <br /> == Администрирование ==<br /> * [[Разграничение прав действий]]<br /> * [[Настройка безопасности сервера биллинга и компонентов биллинга]]<br /> * [[Принудительный останов процессов биллинга]]<br /> * [[Использование подписанного SSL сертификата]]<br /> * [[Запуск scheduler и data_loader с другими портами управления]]<br /> * [[bg-snmp-management|Мониторинг java-процессов по snmp]]<br /> * [[Скрипты автостарта демонов bgbilling для Debian]]<br /> * [[javaws|Запуск BGBillingClient через Java Web Start]]<br /> <br /> == Настройка вспомогательного ПО ==<br /> *[[Проксирование обращений к BGBillingServer посредством nginx]]<br /> <br /> === MySQL ===<br /> *[[Рекомендации по настройке MySQL]]<br /> *[[database backup|Backup MySQL базы с помощью snapshot'ов (Linux, LVM)]]<br /> *[[Настройка MySQL репликации]]<br /> *[[Установка триггера в MySQL для отслеживания изменений]]<br /> *[[Скрипт восстановления MySQL репликации]]<br /> <br /> === NetFlow ===<br /> *[[Настройка NetFlow-агента IPCAD]]<br /> *[[Разделение NetFlow-потоков]]<br /> <br /> == Технологии ==<br /> *[http://wiki.bitel.ru/index.php/REGEXP REGEXP]<br /> *[[MySQL REGEXP]]<br /> *[http://wiki.bitel.ru/index.php/XML XML]<br /> *[[XSLT]]<br /> *[http://wiki.bitel.ru/index.php/FO%28P%29 FO(P)]<br /> === Разработка ===<br /> *[[Отладка action'ов в IntelliJ IDEA]]<br /> *[[Разработка динамического кода в IDE Eclipse]]<br /> <br /> == [[XSLT]] шаблоны ==<br /> *[[Добавление параметров договора на страницу личного кабинета]]<br /> &lt;!-- *[[Красивые графики статистики в модуле IPN]] --&gt;<br /> *[[Карточки договора]]<br /> *[[Создание XSLT/FO шаблона со штрихкодами]]<br /> *[[Подстановка данных в зависимости от текущего пользователя биллинга]]<br /> *[[Генерация прайса модуля IP телефонии в карточке договора]]<br /> <br /> === Счета ===<br /> *[[Печать счета-фактуры и акта на отдельных листах]]<br /> *[[Расширенные счета модуля бухгалтерии]]<br /> *[[Квитанция телефонии физ. лицам]]<br /> *[[Шаблоны вывода названия месяца]]<br /> *[[Изменения в шаблоне в зависимости от месяца документа]]<br /> *[[Добавление новых шрифтов в FO шаблоны]]<br /> <br /> == Интеграция с внешними системами ==<br /> * [[Прямая интеграция с платежными терминалами ЭСФОР / SFOUR]]<br /> * [[Интеграция с платежной системой с использованием модуля Card]]<br /> * [[Интеграция с платежной системой Robokassa]]<br /> * [[SMS рассылка через SMPP]]<br /> * [[SMS рассылка через SMPP по средствам дин кода в 5.2]]<br /> * [[Система учета &quot;Заявки и Наряды&quot; на java]]<br /> * [[Bash скрипт-отсылка смс через телефон при отсутствие ping на заданный узел]]<br /> * [[Запросы в личный кабинет пользователя сторонними системами]]<br /> * [[Запросы к серверу биллинга сторонними системами]]<br /> <br /> === 1С ===<br /> * [[Пример обращения к биллингу из 1С v.7.7]]<br /> * [[amurimpulse.ru bgbilling]]<br /> * [[Integrator 1C-BGBilling]]<br /> * [[Пример интеграции с 1С v.7.7]]<br /> * [[Пример интеграции с 1С v.8.1]]<br /> * [[Установка unload_status счета через HTTP-запрос]]<br /> <br /> == Скрипты BGBS ==<br /> *[[Логгирование в скриптах поведения]]<br /> <br /> === Комплексные решения ===<br /> *[[Предоставление тестового периода пользования услугой]]<br /> *[[Организация системы отслеживания и отключения КТВ должников на BGBS с использованием CRM плагина]]<br /> *[[Автоматизация подключений VPN-клиентов с использованием CRM плагина]]<br /> *[[Пример автоматизации подключения новых клиентов]]<br /> <br /> === Глобальные скрипты ===<br /> *[[Скрипт глобальный отмены перехода на тарифы при неоплате]]<br /> *[[Скрипт предоставление скидки пенсионерам]]<br /> *[[Скрипт создания субдоговоров по шаблону]]<br /> *[[Глобальное событие запуска сервера]]<br /> *[[Перемещение в группу через 3 месяца если не было движения денег в наработке]]<br /> *[[Поиск и изменение статусов у договоров]]<br /> *[[Получение списка доступных действий в SQL]]<br /> *[[Глобальный скрипт для удаления старых таблиц]]<br /> <br /> === Пользовательские библиотеки скриптов ===<br /> *[[Пересчеты и бонусы]]<br /> *[[Архивирование логов netflow и radius accaunting]]<br /> <br /> === Ядро ===<br /> *[[Смена тарифного плана по заданию пользователя]]<br /> *[[Валидация текстового параметра]]<br /> *[[Проверка ИНН/КПП при вводе]]<br /> *[[Проверка параметра договора перед изменением]]<br /> *[[Обработка смены параметра договора]]<br /> *[[Создание списка дополнительных действий для договора]]<br /> *[[Обработка события создания договора]]<br /> *[[Обработка события &quot;добавление услуги RSCM в договор&quot; . Скипт сменяет тариф, подключает абонплату ]]<br /> *[[Приостановление договора клиентом через WEB]]<br /> *[[Скрипт проверки баланса и отключения договора]]<br /> *[[Изменение стандартной логики перетирания статусов]]<br /> *[[Пример продажи OEM ключей с помощью скрипта]]<br /> *[[Пример копирования тарифного плана]]<br /> *[[Получение текущего пользователя биллинга]]<br /> *[[Запуск скрипта до и после акшена]]<br /> *[[Примеры скриптов до и после акшена]]<br /> *[[Примеры динамического кода акшена и веб-сервисов]]<br /> *[[Начисление бонусов на счет при платежах определенного типа]]<br /> *[[Включение должников по приходу платежа]]<br /> *[[Снижение лимита при внесении расхода]]<br /> *[[Синхронизация услуг договора в соответствии с тарифными планами]]<br /> *[[Добавление группы и снятие в зависимости от статуса]]<br /> *[[Управление статусом договора по состоянию баланса]]<br /> *[[Запрет на вход в личный кабинет с закрытых договоров]]<br /> *[[Переход на понижающий тариф только со следующего месяца]]<br /> *[[Пример создания своего интерфейса в клиенте]]<br /> *[[Метки услуг]]<br /> <br /> === Модуль Bill ===<br /> *[[Создание счета в модуле Bill]]<br /> *[[Создание счета из суммы платежей по классу договоров]]<br /> *[[Создание счета по таблице позиций]]<br /> *[[Создание счета и счет-фактур в модуле Bill(выполнение тех же действий что и руками)]]<br /> *[[Распечатка счетов в pdf по событию генерации счета]]<br /> *[[Внешняя программа на JAVA для синхронизации номеров счетов и актов выполненных работ (версия BGBilling 5.0)]]<br /> <br /> === Модуль DialUp ===<br /> *[[Запуск переначисления в модуле DialUp]]<br /> *[[Передача ACCEPT вместо REJECT вместе с доп. аттрибутами]]<br /> *[[Обработка запроса учетного периода]]<br /> *[[Переинициализация тарифа в пределах сессии | Обработка запроса учетного периода (переинициализация тарифа в пределах сессии) ]]<br /> *[[Ограничение доступа для различных групп пользователей для BGRadiusDialup]]<br /> *[[Детальное информирование абонентов о причинах ошибки 691]]<br /> *[[Аутентификация с учетом Calling-Id-Station]]<br /> *[[Доп. действие сброса активных соединений]]<br /> *[[Открытие абонплаты по первой установке соединения]]<br /> *[[Пересчет трафика по данным Radius (при потерянных Netflow-логах)]]<br /> *[[Отключение Fake сессий при приходе платежа]]<br /> *[[Ограничение доступа на основе объектов]]<br /> <br /> === Модуль DialUp / Cкрипты предобработки RADIUS запросов ===<br /> * [[Уcтановка услуги типа &quot;Время&quot; для BGRadiusDialup]]<br /> * [[Установка фиксированного пароля]]<br /> * [[Нормализация параметра Acct-Session-Id у маршрутизатора Cisco]]<br /> * [[Разделение атрибута User-Name на логин и пароль]]<br /> * [[Вынос MAC адреса из cisco-avp-pair в Calling-Station-Id]]<br /> * [[Копирование Тunnel-Client-Endpoint/Tunnel-Server-Endpoint в Calling-Station-Id/Called-Station-Id]]<br /> * [[Замена radius-атрибутов при авторизации]]<br /> <br /> === Модуль Inet / Cкрипты предобработки RADIUS запросов ===<br /> * [[Вынос MAC адреса из cisco-avp-pair в Calling-Station-Id для модуля Inet]]<br /> <br /> === Модуль СerberСrypt ===<br /> *[[Изменение подписки карты через web (cerbercrypt)]]<br /> *[[Управление подписками через веб (cerbercrypt)]]<br /> <br /> === Модуль NPay ===<br /> *[[Определение размера абонентской платы]]<br /> *[[Запуск переначисления в модуле NPay]]<br /> *[[Дебетовые абонплаты. Снятие штрафа за разблокировку.]]<br /> *[[Снятие абонентской платы в дебитовых договорах]]<br /> *[[Предварительное уведомление о блокировке по дебетовым абонплатам]]<br /> <br /> === Модуль Phone ===<br /> *[[При создании поинта модуля Phone добавление в него абонплат]]<br /> *[[Закрытие_телефонных_договоров]]<br /> <br /> === Модуль RSCM ===<br /> *[[Запуск переначисления в модуле RSCM]]<br /> *[[Перенос суммы расхода в наработку RSCM модуля]]<br /> <br /> === Модуль VoiceIp ===<br /> *[[Определение стоимости звонка VoiceIp]]<br /> <br /> === Модуль VoiceIp / Cкрипты предобработки RADIUS запросов ===<br /> * [[Идентификация Voip оператора по подсети (транзит)]]<br /> * [[Установка параметров звонка Voip]]<br /> * [[Установка фиксированного пароля]]<br /> * [[Разделение атрибута User-Name на логин и пароль]]<br /> * [[Замена radius-атрибутов при авторизации]]<br /> <br /> === Плагин CRM ===<br /> *[[Обработка выполненных задач в журнале задач]]<br /> *[[Обработка задач по событию ядра &quot;Поступление платежа&quot;, создание новой задачи и изменение существующей]]<br /> *[[Пример получения информации о задаче]]<br /> *[[Уведомления монтажников о новых активных задачах путем отправки SMS XML запросом]]<br /> <br /> === Плагин CashCheck ===<br /> *[[Чек: добавление позиции]]<br /> *[[Чек: завершение формирования]]<br /> *[[Примеры скриптов CashCheck]]<br /> <br /> === Плагин Documents ===<br /> *[[Создание копий документа на договорах]]<br /> <br /> == Решения для модулей и плагинов ==<br /> <br /> === Модуль DialUP ===<br /> *[[Настройка Lucent Ascend MAX6000 в качестве DialUP сервера]]<br /> *[[Настройка Dial-IN сервера FreeBSD PPPD]]<br /> *[[Настройка VPN сервера LINUX PPPD + POPTOP]]<br /> *[[Настройка шейпера в LINUX PPPD]]<br /> *[[Настройка VPN сервера FreeBSD MPD]]<br /> *[[Настройка PPPoE сервера на Cisco-роутере]]<br /> *[[Настройка PPPoE и/или РРТР (VPN) на Mikrotik]]<br /> *[[Проблема с прохождением update пакетов и сброса сессий в Debian и Ubuntu дистрибутивах]]<br /> *[[Настройка Dial-IN Windows RRAS сервера]]<br /> *[[VPN доступ с повременной тарификацией на базе FreeBSD MPD]]<br /> *[[Организация семейства UNLIMIT тарифов на базе FreeBSD MPD]]<br /> *[[Примеры тарифных планов VPN/DialUp]]<br /> *[[Отключение сессий по PoD на CISCO]]<br /> *[[Пример скрипта управления уровнями BGRadiusDialup]]<br /> *[[Настройка cisco с поддеркой ISG]]<br /> *[[Настройка BGBilling c поддеркой ISG]]<br /> *[[Настройка BGBilling с RedBack SmartEdge (PPPOE)]]<br /> <br /> === Модуль E-Mail ===<br /> *[[Почтовая система Exim + Cyrus + OpenLDAP на FreeBSD]]<br /> *[[Postfix/MySQL/BGBilling]]<br /> *[[Postfix+dovecot+ldap]]<br /> *[[Postfix+Mysql+Virtual domains]]<br /> <br /> === Модуль Inet ===<br /> *[[Схемы подключения]]<br /> *[[Конвертеры из IPN в INET]]<br /> *[[ISG, схема со стартом сессии и ее авторизацией по IP, выдача адресов на основе option82]]<br /> <br /> === Модуль IPN ===<br /> *[[IP/VPN]]<br /> *[[Примеры тарифных планов IPN]]<br /> *[[Настройка BGIPNNetflowCollector]]<br /> *[[Методика определения причины отсутствия трафика в отчете договора]]<br /> *[[Связка с flow-tools]]<br /> *[[Экспорт Netflow-данных в формат Nfdump]]<br /> *[[Реалиазация шлюза на Cisco]]<br /> *[[Реализация шлюзов на BeanShell,примеры стандартных и других шлюзов]] (Manad, Cisco, Zyxel, Mikrotik)<br /> *[[Изменения в manad для работы с одним pipe на множество IP адресов]]<br /> *[[FreeBSD manad, понимающий изменения правил в тарифах]]<br /> *[[Табличный FreeBSD manad, понимающий изменения правил в тарифах]]<br /> *[[Пример реализации скриптового универсального шлюза]]<br /> *[[Конвертер привязок услуг dialup в привязки ipn]]<br /> *[[Реализация скрипта Manad ]]<br /> *[[Настройка шлюза Mikrotik]]<br /> *[[Обновление номеров интерфейсов при замене роутера]]<br /> <br /> === Модуль Phone ===<br /> * [[Конвертация и загрузка тарифов Телефонии в биллинг]]<br /> * [[Примеры тарифных планов Телефонии]]<br /> * [[Примеры реализации конверторов логов]]<br /> * [[Генератор отчётности для Совинтел]]<br /> <br /> === Модуль VoiceIP ===<br /> *[[Интеграция Asterisk и BGBilling (Accounting) посредством скрипта предобработки запросов Radius]]<br /> *[[Интеграция Asterisk и BGBilling (Accounting) посредством изменения программного кода Asterisk]]<br /> *[[Интеграция c MVTS]]<br /> *[[Интеграция c Cisco Call Manager Express (CME)]]<br /> *[[Карточная IVR система на базе Cisco]]<br /> *[[Примеры IVR скриптов для Cisco]]<br /> *[[Пример настройки Cisco AS5350]]<br /> <br /> === Модуль Reports ===<br /> *[[Редактирование отчетов в iReport]]<br /> *[[Примеры отчётов]]<br /> *[[Использование отчётов для организации универсального поиска]]<br /> <br /> === Плагин Dispatch ===<br /> *[[Импорт старой схемы рассылок баланса в Dispatch]]<br /> <br /> == SQL-запросы ==<br /> *[[Схема связки таблиц тарифов]]<br /> *[[Разные SQL-запросы]]<br /> *[[SQL-запрос: кто сколько платит на каждом тарифе]]<br /> *[[Получение цен тарифов]]<br /> *[[Работа с группами, битовые маски]]<br /> *[[наработка по абонентке и услугам за месяц]]<br /> <br /> <br /> === CerberCrypt ===<br /> *[[Модуль CerberCrypt: Разные SQL-запросы]]<br /> *[[Модуль CerberCrypt: Поиск битых SQL-связей]]<br /> <br /> == Веб-Интерфейс ==<br /> *[[Свой action в личном кабинете]]<br /> **[[WebAction_CustomSuspend]] - управление статусом договора (v5.0)<br /> *[[Изменение параметров договора из личного кабинета]]<br /> *[[Как убрать ненужные действия в web]]<br /> <br /> == Протоколы ==<br /> *[[Протокол дилерский платежей]]<br /> *[[Протоколы, поддержанные в модуле MPS]]<br /> *[[Протоколы, поддержанные в модуле Phone]]<br /> *[[Медиа: Enaza.zip]]<br /> *[[Медиа: Payonline.zip]]<br /> <br /> == Faq ==<br /> * [[Не запускается служба BSBillingServer под Windows]]<br /> * [[Вопросы вместо русских букв]]<br /> * [[Что происходит с пользователями при рестарте сервера биллинга и BGRadiusDialup]]<br /> * [[Тарификация максимального трафика]]<br /> * [[Field ... doesn't have a default value ]]<br /> * [[Character set ‘cp1251' is not a compiled character set and is not specified in the ‘C:\mysql\\share\charsets\Index.xml’ file ]]<br /> * [[com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown database 'bgbilling' ]]<br /> * [[Договор не отображается в поиске]]<br /> * [[PPPD проблема с сессиями больше 4ГБ]]<br /> * [[Меню личного кабинета]]<br /> * [[Java.lang.NoClassDefFoundError:_javax/xml/bind/DataBindingException|FreeBSD: Java.lang.NoClassDefFoundError: javax/xml/bind/DataBindingException]]<br /> * [[Manad: после некоторого количества договоров начинает передавать данные на биллинг неправильно ]]<br /> * [[Ошибка выполнения скиптов: Undefined argument:]]<br /> * [[Ошибка в логе &quot;Too many open files&quot;]]<br /> * [[Ошибка в клиенте &quot;Action NOT FOUND!..&quot;]]</div> Tue, 23 Apr 2013 05:41:27 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0 Карточки договора http://wiki.bitel.ru/index.php/%D0%9A%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0 <p>SinTeZWh1te:&#32;/* Добавление списка тарифных планов в карточку договора */</p> <hr /> <div>С помощью карточек договора из биллинга возможна печать договоров, заявок, карт регистрации и т.п.<br /> <br /> <br /> == Пример 1 ==<br /> Договор, заявка и дополнительное соглашение на цифровое ТВ.<br /> {|<br /> |- valign=top<br /> | [[Изображение:card_telenettv_contract.png|thumb|300px|Договор]] <br /> | [[Изображение:card_telenettv_request.png|thumb|300px|Заявка]] <br /> | [[Изображение:card_telenettv_agreement.png|thumb|300px|Доп. соглашение]] <br /> |}<br /> Файлы с XSLT шаблонами: [[Медиа:card_telenettv.zip]]. Размещаются в '''BGBillingServer/webroot/xsl'''. В конфигурации сервера ('''Сервис=&gt;Настройка''') указывается:<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> contractcard.1=card_telenettv_contract.xsl:Карта Договора (Теленет)<br /> contractcard.2=card_telenettv_request.xsl:ЗАЯВЛЕНИЕ(Теленет)<br /> contractcard.3=card_telenettv_agreement.xsl:Дополнительное соглашение(Теленет)<br /> &lt;/source&gt;<br /> <br /> <br /> == Пример 2 ==<br /> Заказ к договору об оказании услуг связи (в двух экзеплярах)<br /> {|<br /> |- valign=top<br /> | [[Изображение:card_maglan_screen.jpg|thumb|300px|Заказ к договору]] <br /> |}<br /> Файлы с XSLT шаблонами: [[Медиа:card_maglan.zip]]. Размещаются в '''BGBillingServer/webroot/xsl'''. В конфигурации сервера ('''Сервис=&gt;Настройка''') указывается:<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> #здесь Х - номер карты по порядку<br /> contractcard.X=card_maglan.xsl:Заказ к договору (Маглан)<br /> &lt;/source&gt;<br /> <br /> == Добавление списка тарифных планов в карточку договора ==<br /> Для получения списка глобальных и персональных тарифов договора в его карточке, необходимо в шаблоне карточки в нужном месте вставить<br /> <br /> &lt;source lang=&quot;xml&quot;&gt; <br /> &lt;xsl:for-each select=&quot;contract/tariff&quot;&gt;<br /> &lt;fo:block xsl:use-attribute-sets=&quot;text&quot; text-align=&quot;center&quot;&gt;<br /> &lt;xsl:value-of select=&quot;@tariff_plan&quot;/&gt;<br /> &lt;/fo:block&gt;<br /> &lt;/xsl:for-each&gt;<br /> &lt;xsl:for-each select=&quot;contract/personal_tariff&quot;&gt;<br /> &lt;fo:block xsl:use-attribute-sets=&quot;text&quot; text-align=&quot;center&quot;&gt;<br /> &lt;xsl:value-of select=&quot;@title&quot;/&gt;<br /> &lt;/fo:block&gt;<br /> &lt;/xsl:for-each&gt;<br /> &lt;/source&gt;<br /> <br /> Выглядеть будет следующим образом.<br /> [[Файл:GnuPX.png]] &lt;br&gt;<br /> Где сначала выбираются все глобальные тарифы, а затем персональные.</div> Tue, 12 Mar 2013 13:18:19 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%9A%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0 Файл:GnuPX.png http://wiki.bitel.ru/index.php/%D0%A4%D0%B0%D0%B9%D0%BB:GnuPX.png <p>SinTeZWh1te:&#32;</p> <hr /> <div></div> Tue, 12 Mar 2013 13:16:32 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%84%D0%B0%D0%B9%D0%BB%D0%B0:GnuPX.png Карточки договора http://wiki.bitel.ru/index.php/%D0%9A%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0 <p>SinTeZWh1te:&#32;</p> <hr /> <div>С помощью карточек договора из биллинга возможна печать договоров, заявок, карт регистрации и т.п.<br /> <br /> <br /> == Пример 1 ==<br /> Договор, заявка и дополнительное соглашение на цифровое ТВ.<br /> {|<br /> |- valign=top<br /> | [[Изображение:card_telenettv_contract.png|thumb|300px|Договор]] <br /> | [[Изображение:card_telenettv_request.png|thumb|300px|Заявка]] <br /> | [[Изображение:card_telenettv_agreement.png|thumb|300px|Доп. соглашение]] <br /> |}<br /> Файлы с XSLT шаблонами: [[Медиа:card_telenettv.zip]]. Размещаются в '''BGBillingServer/webroot/xsl'''. В конфигурации сервера ('''Сервис=&gt;Настройка''') указывается:<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> contractcard.1=card_telenettv_contract.xsl:Карта Договора (Теленет)<br /> contractcard.2=card_telenettv_request.xsl:ЗАЯВЛЕНИЕ(Теленет)<br /> contractcard.3=card_telenettv_agreement.xsl:Дополнительное соглашение(Теленет)<br /> &lt;/source&gt;<br /> <br /> <br /> == Пример 2 ==<br /> Заказ к договору об оказании услуг связи (в двух экзеплярах)<br /> {|<br /> |- valign=top<br /> | [[Изображение:card_maglan_screen.jpg|thumb|300px|Заказ к договору]] <br /> |}<br /> Файлы с XSLT шаблонами: [[Медиа:card_maglan.zip]]. Размещаются в '''BGBillingServer/webroot/xsl'''. В конфигурации сервера ('''Сервис=&gt;Настройка''') указывается:<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> #здесь Х - номер карты по порядку<br /> contractcard.X=card_maglan.xsl:Заказ к договору (Маглан)<br /> &lt;/source&gt;<br /> <br /> == Добавление списка тарифных планов в карточку договора ==<br /> Для получения списка глобальных и персональных тарифов договора в его карточке, необходимо в шаблоне карточки в нужном месте вставить<br /> <br /> &lt;source lang=&quot;xml&quot;&gt; <br /> &lt;xsl:for-each select=&quot;contract/tariff&quot;&gt;<br /> &lt;fo:block xsl:use-attribute-sets=&quot;text&quot; text-align=&quot;center&quot;&gt;<br /> &lt;xsl:value-of select=&quot;@tariff_plan&quot;/&gt;<br /> &lt;/fo:block&gt;<br /> &lt;/xsl:for-each&gt;<br /> &lt;xsl:for-each select=&quot;contract/personal_tariff&quot;&gt;<br /> &lt;fo:block xsl:use-attribute-sets=&quot;text&quot; text-align=&quot;center&quot;&gt;<br /> &lt;xsl:value-of select=&quot;@title&quot;/&gt;<br /> &lt;/fo:block&gt;<br /> &lt;/xsl:for-each&gt;<br /> &lt;/source&gt;</div> Tue, 12 Mar 2013 13:12:33 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%9A%D0%B0%D1%80%D1%82%D0%BE%D1%87%D0%BA%D0%B8_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0 Закрытие телефонных договоров http://wiki.bitel.ru/index.php/%D0%97%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5_%D1%82%D0%B5%D0%BB%D0%B5%D1%84%D0%BE%D0%BD%D0%BD%D1%8B%D1%85_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 <p>SinTeZWh1te:&#32;</p> <hr /> <div>Пример скрипта блокировки телефонных шлюзов. Запускаем его 21го числа (где то в толщах закона о связи и правил предоставления услуг) и скрипт блокирует всех, у кого платежи за месяц не перекрыли долг на начало месяца (если на начало месяца был плюс - абонент не должник, естественно). <br /> <br /> &lt;source lang=&quot;java&quot;&gt; <br /> import bitel.billing.server.util.*;<br /> import bitel.billing.server.contract.bean.*;<br /> import java.math.*;<br /> import java.util.Calendar;<br /> import java.util.Date;<br /> import java.util.GregorianCalendar;<br /> import java.util.StringTokenizer;<br /> import ru.bitel.bgbilling.modules.phone.server.bean.PhoneContractStatusManager;<br /> import org.apache.log4j.Logger;<br /> <br /> import ru.bitel.bgbilling.server.util.Setup;<br /> <br /> public void main( setup, con, conSlave )<br /> {<br /> s=&quot;&quot;;<br /> cm=new ContractManager(con);<br /> bu=new BalanceUtils(con);<br /> pcsm=new PhoneContractStatusManager(con, 3);<br /> //Находим договора, где есть услуги телефонии. У меня такие договора называются МТС<br /> rs=con.prepareStatement(&quot;select * from contract where title like '%МТС%' and pgid=1 and status!=3 and date2 is null&quot;).executeQuery();<br /> ContractStatusManager csm=new ContractStatusManager(con);<br /> while(rs.next()){<br /> <br /> cid=rs.getInt(&quot;id&quot;);<br /> contract=cm.getContractById(cid); <br /> print(&quot;Договор: &quot;+rs.getString(&quot;title&quot;));<br /> print(&quot;Баланс на начало месяца: &quot;+bu.getBalanceSumma1(new Date(), cid));<br /> BigDecimal start=new BigDecimal(0);<br /> BigDecimal payments=new BigDecimal(0);<br /> <br /> rs2=con.prepareStatement(&quot;select SUM(summa) from contract_payment where cid=&quot;+cid+&quot; and dt&gt;='2012-05-01' &quot;).executeQuery();<br /> if(rs2.next()){<br /> <br /> if(rs2.getBigDecimal(1)!=null)<br /> payments=rs2.getBigDecimal(1);<br /> print(&quot;Платежи: &quot;+payments);<br /> }<br /> if(payments.add(bu.getBalanceSumma1(new Date(), cid)).compareTo(BigDecimal.ZERO)&lt;0){<br /> print(&quot;ЗАБЛОКИРОВАТЬ АБОНЕНТА!&quot;);<br /> s=s+&quot;\n&quot;+cid+&quot;:&quot;+contract.getTitle()+&quot;:&quot;+contract.getComment();<br /> status=new ContractStatus();<br /> status.setStatus(2);<br /> status.setComment(&quot;Баланс на начало месяца:&quot;+start+&quot;, платежи за месяц: &quot;+payments);<br /> status.setDateFrom(new java.util.Date());<br /> status.setContractId(contract.getId());<br /> csm.changeStatus(status, 0,true);<br /> //Т.к. телефония на субдоговоре<br /> for(String subcid:rs.getString(&quot;sub_list&quot;).split(&quot;,&quot;)){<br /> print(&quot;Блокируем поддоговор:&quot;+subcid);<br /> pcsm.changeContractStatus(Integer.parseInt(subcid), 1, 0);<br /> }<br /> }<br /> <br /> print(&quot;---&quot;);<br /> }<br /> //Смотрим кого в итоге заблокировало<br /> print(s);<br /> }<br /> <br /> &lt;/source&gt;</div> Thu, 17 Jan 2013 05:56:14 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%97%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B5_%D1%82%D0%B5%D0%BB%D0%B5%D1%84%D0%BE%D0%BD%D0%BD%D1%8B%D1%85_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> DELETE FROM contract_service WHERE cid= + id + public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> import bitel.billing.server.task.bean.*; <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;;<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:57:20 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Разные SQL-запросы http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%BD%D1%8B%D0%B5_SQL-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Тарифы договора ==<br /> Активные на сегодня тарифы для договора. Версия 4.6/5.0<br /> &lt;source lang=&quot;sql&quot;&gt; <br /> SELECT tariff_plan.title<br /> FROM tariff_plan<br /> INNER JOIN contract_tariff ON contract_tariff.tpid = tariff_plan.id AND (contract_tariff.date1 IS NULL OR contract_tariff.date1&lt;=CURDATE()) AND (contract_tariff.date2 IS NULL OR contract_tariff.date2&gt;=CURDATE())<br /> WHERE contract_tariff.cid=352715<br /> &lt;/source&gt;<br /> или лучше<br /> &lt;source lang=&quot;sql&quot;&gt; <br /> SELECT contract_tariff.tpid, contract_tariff.date1, contract_tariff.date2, tariff_plan.title<br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON tariff_plan.id=contract_tariff.tpid<br /> WHERE contract_tariff.cid=352715 AND (contract_tariff.date1 IS NULL OR contract_tariff.date1&lt;=CURDATE()) AND (contract_tariff.date2 IS NULL OR contract_tariff.date2&gt;=CURDATE())<br /> &lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 07:49, 18 февраля 2010 (UTC)<br /> <br /> == Активные договоры без тарифов ==<br /> <br /> Все договоры, у которых статус &quot;активен&quot; и у которых на сегодня нет ни одного тарифного плана. Версия 4.6/5.0<br /> <br /> &lt;source lang=&quot;sql&quot;&gt; <br /> SELECT contract.id, contract.title, contract.comment, contract.status, ct.id<br /> FROM contract<br /> LEFT JOIN contract_tariff AS ct ON contract.id=ct.cid AND (ct.date1 IS NULL OR ct.date1&lt;=CURDATE()) AND (ct.date2 IS NULL OR ct.date2&gt;=CURDATE())<br /> WHERE ct.id IS NULL AND contract.status=0<br /> &lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 12:32, 17 февраля 2010 (UTC)<br /> <br /> == Дублированные тарифы ==<br /> <br /> Показывает сколько в каждом договоре каждых тарифов, по убыванию.<br /> Было сделано для поиска одинаковых тарифов в договорах. Правда, не учитывает даты (добавить несложно), но для поиска дубляжей сойдёт.<br /> Версия 4.6/5.0<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT contract_tariff.cid, contract_tariff.tpid, count(contract_tariff.id) as tariff_count<br /> FROM contract_tariff<br /> GROUP BY contract_tariff.cid, contract_tariff.tpid<br /> ORDER BY tariff_count DESC<br /> &lt;/source&gt;<br /> или то же самое, с дополнительной инфой:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT count(contract_tariff.id) as tariff_count, contract_tariff.tpid, contract.id, contract.title, contract.comment, tariff_plan.title<br /> FROM contract_tariff<br /> LEFT JOIN contract ON contract.id=contract_tariff.cid<br /> LEFT JOIN tariff_plan ON tariff_plan.id=contract_tariff.tpid<br /> GROUP BY contract_tariff.cid, contract_tariff.tpid<br /> ORDER BY tariff_count DESC<br /> &lt;/source&gt;<br /> вот с добавлением учёта дат:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT count(contract_tariff.id) as tariff_count, contract_tariff.tpid, contract_tariff.cid, contract.title, contract.comment, tariff_plan.title<br /> FROM contract_tariff<br /> LEFT JOIN contract ON contract.id=contract_tariff.cid<br /> LEFT JOIN tariff_plan ON tariff_plan.id=contract_tariff.tpid<br /> WHERE (contract_tariff.date1 IS NULL OR contract_tariff.date1&lt;=CURDATE()) AND (contract_tariff.date2 IS NULL OR contract_tariff.date2&gt;=CURDATE())<br /> GROUP BY contract_tariff.cid, contract_tariff.tpid<br /> ORDER BY tariff_count DESC<br /> &lt;/source&gt;<br /> <br /> вместо &lt;source lang=&quot;sql&quot;&gt;ORDER BY tariff_count DESC&lt;/source&gt; можно сделать &lt;source lang=&quot;sql&quot;&gt;HAVING tariff_count&gt;1&lt;/source&gt;<br /> <br /> --[[Участник:DimOn|dimOn]] 12:32, 17 февраля 2010 (UTC)<br /> <br /> == Использование тарифов (трафик по договорам) ==<br /> Нужна таблица<br /> Тариф | Количество активных договоров (тех, у кого трафик за месяц больше определённого значения)<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> # чистыми цифрами: тарифный план -&gt; его использований в договорах<br /> SELECT contract_tariff.tpid, count(contract_tariff.id)<br /> FROM contract_tariff<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> # джойним название<br /> SELECT contract_tariff.tpid, tariff_plan.title, count(contract_tariff.id) <br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON contract_tariff.tpid=tariff_plan.id<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> Разбираемся с трафиком:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> # связка cid =&gt; сумма трафика за месяц (+выборка тех, у кого трафик больше чего-либо)<br /> SELECT <br /> `detail`.cid, sum(`detail`.`amount`) as trafic<br /> FROM<br /> `session_detail_21_200810` AS `detail`<br /> GROUP BY `detail`.cid<br /> HAVING trafic &gt; 10<br /> &lt;/source&gt;<br /> <br /> Вот первая версия запроса, &quot;в лоб&quot;. Просто объединяем предыдущие и суём вторую выборку в подзапрос. Работает оооооочень медленно %(<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT contract_tariff.tpid, tariff_plan.title, count(contract_tariff.id) <br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON contract_tariff.tpid=tariff_plan.id<br /> WHERE contract_tariff.cid in (SELECT cid FROM `session_detail_21_200810` GROUP BY cid HAVING sum(`amount`) &gt; 10)<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> <br /> Правильный запрос - это через создание (временной) таблицы.<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> CREATE TABLE _good_cid (SELECT cid FROM `session_detail_21_200810` GROUP BY cid HAVING sum(`amount`) &gt; 10);<br /> <br /> SELECT contract_tariff.tpid, tariff_plan.title, count(contract_tariff.id) <br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON contract_tariff.tpid=tariff_plan.id<br /> INNER JOIN _good_cid ON contract_tariff.cid=_good_cid.cid<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 09:42, 4 марта 2010 (UTC)<br /> <br /> == Распределение трафика по тарифам ==<br /> Делает статистику по месяцам - сколько в каждый час трафика прошло, с разбивкой по привязанным тарифам. Несколько синтетично, но кому-то бывает полезно. Получается таблица строки - все тарифы, столбцы - часы.<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT<br /> tariff.id,<br /> tariff.title,<br /> HOUR(detail.dtime) AS hh,<br /> SUM(IF(HOUR(detail.dtime)=0, detail.amount, 0)) AS 0_amount,<br /> SUM(IF(HOUR(detail.dtime)=1, detail.amount, 0)) AS 1_amount,<br /> SUM(IF(HOUR(detail.dtime)=2, detail.amount, 0)) AS 2_amount,<br /> SUM(IF(HOUR(detail.dtime)=3, detail.amount, 0)) AS 3_amount,<br /> SUM(IF(HOUR(detail.dtime)=4, detail.amount, 0)) AS 4_amount,<br /> SUM(IF(HOUR(detail.dtime)=5, detail.amount, 0)) AS 5_amount,<br /> SUM(IF(HOUR(detail.dtime)=6, detail.amount, 0)) AS 6_amount,<br /> SUM(IF(HOUR(detail.dtime)=7, detail.amount, 0)) AS 7_amount,<br /> SUM(IF(HOUR(detail.dtime)=8, detail.amount, 0)) AS 8_amount,<br /> SUM(IF(HOUR(detail.dtime)=9, detail.amount, 0)) AS 9_amount,<br /> SUM(IF(HOUR(detail.dtime)=10, detail.amount, 0)) AS 10_amount,<br /> SUM(IF(HOUR(detail.dtime)=11, detail.amount, 0)) AS 11_amount,<br /> SUM(IF(HOUR(detail.dtime)=12, detail.amount, 0)) AS 12_amount,<br /> SUM(IF(HOUR(detail.dtime)=13, detail.amount, 0)) AS 13_amount,<br /> SUM(IF(HOUR(detail.dtime)=14, detail.amount, 0)) AS 14_amount,<br /> SUM(IF(HOUR(detail.dtime)=15, detail.amount, 0)) AS 15_amount,<br /> SUM(IF(HOUR(detail.dtime)=16, detail.amount, 0)) AS 16_amount,<br /> SUM(IF(HOUR(detail.dtime)=17, detail.amount, 0)) AS 17_amount,<br /> SUM(IF(HOUR(detail.dtime)=18, detail.amount, 0)) AS 18_amount,<br /> SUM(IF(HOUR(detail.dtime)=19, detail.amount, 0)) AS 19_amount,<br /> SUM(IF(HOUR(detail.dtime)=20, detail.amount, 0)) AS 20_amount,<br /> SUM(IF(HOUR(detail.dtime)=21, detail.amount, 0)) AS 21_amount,<br /> SUM(IF(HOUR(detail.dtime)=22, detail.amount, 0)) AS 22_amount,<br /> SUM(IF(HOUR(detail.dtime)=23, detail.amount, 0)) AS 23_amount<br /> FROM<br /> session_detail_21_200909 AS detail<br /> LEFT JOIN contract_tariff ON contract_tariff.cid=detail.cid AND contract_tariff.date1&lt;=detail.dtime AND (contract_tariff.date2 IS NULL OR detail.dtime&lt;=contract_tariff.date2) <br /> LEFT JOIN tariff_plan AS tariff ON contract_tariff.tpid=tariff.id<br /> GROUP BY tariff.id<br /> ORDER BY tariff.title<br /> &lt;/source&gt;<br /> Если надо разделять по входящему/исходящему (и/или по прочим услугам), то добавить между JOIN и GROUP BY условие<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> WHERE detail.sid = &lt;ид услуги нужной&gt;<br /> &lt;/source&gt;<br /> Если были битые ссылки на тарифы, то будет строка с нулём, куда припишется всё левое, если надо откинуть поле с нулём, прибавить (к WHERE, разумеется) условие:<br /> &lt;source lang=&quot;sql&quot;&gt;AND ( tariff.id is not null )&lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 10:40, 10 марта 2010 (UTC)<br /> <br /> == Выбрать все договоры без установленного параметра ==<br /> Если pid параметра = 10, то:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> select contract.id from contract<br /> left join contract_parameter_type_1 on contract_parameter_type_1.cid=contract.id and contract_parameter_type_1.pid=10<br /> where contract_parameter_type_1.val IS NULL<br /> &lt;/source&gt;<br /> <br /> == Выбрать все информацию по тарифу( версия &lt;=5.1 ) ==<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM tariff_plan <br /> left join tariff_tree_link on tariff_tree_link.tpid= tariff_plan.id <br /> left join tariff_tree on tariff_tree.id = tariff_tree_link.tree_id<br /> left join module_tariff_tree on module_tariff_tree.tree_id = tariff_tree_link.tree_id<br /> left join mtree_node on mtree_node.mtree_id = module_tariff_tree.id<br /> where tariff_plan.id = XXX<br /> &lt;/source&gt;<br /> <br /> XXX - id тарифного плана<br /> <br /> <br /> == Выбрать все информацию по тарифу( версия &gt;= 5.2) ==<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM tariff_plan <br /> -- LEFT JOIN tariff_tree_link ON tariff_tree_link.tpid= tariff_plan.id <br /> LEFT JOIN tariff_tree ON tariff_tree.id = tariff_plan.tree_id<br /> LEFT JOIN module_tariff_tree ON module_tariff_tree.tree_id = tariff_plan.tree_id<br /> LEFT JOIN mtree_node ON mtree_node.mtree_id = module_tariff_tree.id<br /> WHERE tariff_plan.id = XXX <br /> &lt;/source&gt;<br /> <br /> XXX - id тарифного плана<br /> <br /> == Все тарифы, в которых есть узел модуля ==<br /> вариант предыдущего запроса<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM tariff_plan<br /> JOIN tariff_tree_link ON tariff_tree_link.tpid= tariff_plan.id<br /> JOIN module_tariff_tree ON module_tariff_tree.tree_id = tariff_tree_link.tree_id <br /> WHERE module_tariff_tree.mid=XXX<br /> ORDER BY tariff_plan.id<br /> &lt;/source&gt;<br /> <br /> == Работа с группами ==<br /> Установка группы с кодом 7 договору с кодом 455:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> UPDATE contract SET gr = gr | (1&lt;&lt;7) WHERE id=455<br /> &lt;/source&gt;<br /> <br /> Удаление группы с кодом 7 из договора с кодом 455:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> UPDATE contract SET gr = gr&amp;(~(1&lt;&lt;7)) WHERE id=455<br /> &lt;/source&gt;<br /> <br /> Поиск договоров с группой 7:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM contract WHERE gr&amp;(1&lt;&lt;7) &gt; 0<br /> &lt;/source&gt;<br /> <br /> == Генерация паролей ==<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> UPDATE CONTRACT SET pswd=SUBSTRING(RAND(9), 3, 14)<br /> &lt;/source&gt;<br /> <br /> == Выбор должников для системы автоматического обзвона ==<br /> Стоит задача написать некий код, который бы выбирал номера телефона из контракта, и сумму задолженности, для передачи в систему обзвона должников.<br /> Условия отбора должников - Контракт, входящий остаток которого меньше нуля и по которому нет поступлений в текущем месяце, а так же в параметрах которого установлен флаг &quot;Включить в систему обзвона должников&quot;.<br /> Обсуждение сдесь: http://forum.bgbilling.ru/viewtopic.php?f=19&amp;t=5303<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> в разработке<br /> &lt;/source&gt;<br /> <br /> == Удаление абонплат, привязанных к уже несуществующим договорам ==<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> DELETE service_object FROM npay_service_object_66 AS service_object LEFT JOIN contract ON service_object.cid=contract.id WHERE contract.id IS NULL;<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:22:11 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%BD%D1%8B%D0%B5_SQL-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B Разные SQL-запросы http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%BD%D1%8B%D0%B5_SQL-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Тарифы договора ==<br /> Активные на сегодня тарифы для договора. Версия 4.6/5.0<br /> &lt;source lang=&quot;sql&quot;&gt; <br /> SELECT tariff_plan.title<br /> FROM tariff_plan<br /> INNER JOIN contract_tariff ON contract_tariff.tpid = tariff_plan.id AND (contract_tariff.date1 IS NULL OR contract_tariff.date1&lt;=CURDATE()) AND (contract_tariff.date2 IS NULL OR contract_tariff.date2&gt;=CURDATE())<br /> WHERE contract_tariff.cid=352715<br /> &lt;/source&gt;<br /> или лучше<br /> &lt;source lang=&quot;sql&quot;&gt; <br /> SELECT contract_tariff.tpid, contract_tariff.date1, contract_tariff.date2, tariff_plan.title<br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON tariff_plan.id=contract_tariff.tpid<br /> WHERE contract_tariff.cid=352715 AND (contract_tariff.date1 IS NULL OR contract_tariff.date1&lt;=CURDATE()) AND (contract_tariff.date2 IS NULL OR contract_tariff.date2&gt;=CURDATE())<br /> &lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 07:49, 18 февраля 2010 (UTC)<br /> <br /> == Активные договоры без тарифов ==<br /> <br /> Все договоры, у которых статус &quot;активен&quot; и у которых на сегодня нет ни одного тарифного плана. Версия 4.6/5.0<br /> <br /> &lt;source lang=&quot;sql&quot;&gt; <br /> SELECT contract.id, contract.title, contract.comment, contract.status, ct.id<br /> FROM contract<br /> LEFT JOIN contract_tariff AS ct ON contract.id=ct.cid AND (ct.date1 IS NULL OR ct.date1&lt;=CURDATE()) AND (ct.date2 IS NULL OR ct.date2&gt;=CURDATE())<br /> WHERE ct.id IS NULL AND contract.status=0<br /> &lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 12:32, 17 февраля 2010 (UTC)<br /> <br /> == Дублированные тарифы ==<br /> <br /> Показывает сколько в каждом договоре каждых тарифов, по убыванию.<br /> Было сделано для поиска одинаковых тарифов в договорах. Правда, не учитывает даты (добавить несложно), но для поиска дубляжей сойдёт.<br /> Версия 4.6/5.0<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT contract_tariff.cid, contract_tariff.tpid, count(contract_tariff.id) as tariff_count<br /> FROM contract_tariff<br /> GROUP BY contract_tariff.cid, contract_tariff.tpid<br /> ORDER BY tariff_count DESC<br /> &lt;/source&gt;<br /> или то же самое, с дополнительной инфой:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT count(contract_tariff.id) as tariff_count, contract_tariff.tpid, contract.id, contract.title, contract.comment, tariff_plan.title<br /> FROM contract_tariff<br /> LEFT JOIN contract ON contract.id=contract_tariff.cid<br /> LEFT JOIN tariff_plan ON tariff_plan.id=contract_tariff.tpid<br /> GROUP BY contract_tariff.cid, contract_tariff.tpid<br /> ORDER BY tariff_count DESC<br /> &lt;/source&gt;<br /> вот с добавлением учёта дат:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT count(contract_tariff.id) as tariff_count, contract_tariff.tpid, contract_tariff.cid, contract.title, contract.comment, tariff_plan.title<br /> FROM contract_tariff<br /> LEFT JOIN contract ON contract.id=contract_tariff.cid<br /> LEFT JOIN tariff_plan ON tariff_plan.id=contract_tariff.tpid<br /> WHERE (contract_tariff.date1 IS NULL OR contract_tariff.date1&lt;=CURDATE()) AND (contract_tariff.date2 IS NULL OR contract_tariff.date2&gt;=CURDATE())<br /> GROUP BY contract_tariff.cid, contract_tariff.tpid<br /> ORDER BY tariff_count DESC<br /> &lt;/source&gt;<br /> <br /> вместо &lt;source lang=&quot;sql&quot;&gt;ORDER BY tariff_count DESC&lt;/source&gt; можно сделать &lt;source lang=&quot;sql&quot;&gt;HAVING tariff_count&gt;1&lt;/source&gt;<br /> <br /> --[[Участник:DimOn|dimOn]] 12:32, 17 февраля 2010 (UTC)<br /> <br /> == Использование тарифов (трафик по договорам) ==<br /> Нужна таблица<br /> Тариф | Количество активных договоров (тех, у кого трафик за месяц больше определённого значения)<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> # чистыми цифрами: тарифный план -&gt; его использований в договорах<br /> SELECT contract_tariff.tpid, count(contract_tariff.id)<br /> FROM contract_tariff<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> # джойним название<br /> SELECT contract_tariff.tpid, tariff_plan.title, count(contract_tariff.id) <br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON contract_tariff.tpid=tariff_plan.id<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> Разбираемся с трафиком:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> # связка cid =&gt; сумма трафика за месяц (+выборка тех, у кого трафик больше чего-либо)<br /> SELECT <br /> `detail`.cid, sum(`detail`.`amount`) as trafic<br /> FROM<br /> `session_detail_21_200810` AS `detail`<br /> GROUP BY `detail`.cid<br /> HAVING trafic &gt; 10<br /> &lt;/source&gt;<br /> <br /> Вот первая версия запроса, &quot;в лоб&quot;. Просто объединяем предыдущие и суём вторую выборку в подзапрос. Работает оооооочень медленно %(<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT contract_tariff.tpid, tariff_plan.title, count(contract_tariff.id) <br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON contract_tariff.tpid=tariff_plan.id<br /> WHERE contract_tariff.cid in (SELECT cid FROM `session_detail_21_200810` GROUP BY cid HAVING sum(`amount`) &gt; 10)<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> <br /> Правильный запрос - это через создание (временной) таблицы.<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> CREATE TABLE _good_cid (SELECT cid FROM `session_detail_21_200810` GROUP BY cid HAVING sum(`amount`) &gt; 10);<br /> <br /> SELECT contract_tariff.tpid, tariff_plan.title, count(contract_tariff.id) <br /> FROM contract_tariff<br /> LEFT JOIN tariff_plan ON contract_tariff.tpid=tariff_plan.id<br /> INNER JOIN _good_cid ON contract_tariff.cid=_good_cid.cid<br /> GROUP BY contract_tariff.tpid<br /> &lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 09:42, 4 марта 2010 (UTC)<br /> <br /> == Распределение трафика по тарифам ==<br /> Делает статистику по месяцам - сколько в каждый час трафика прошло, с разбивкой по привязанным тарифам. Несколько синтетично, но кому-то бывает полезно. Получается таблица строки - все тарифы, столбцы - часы.<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT<br /> tariff.id,<br /> tariff.title,<br /> HOUR(detail.dtime) AS hh,<br /> SUM(IF(HOUR(detail.dtime)=0, detail.amount, 0)) AS 0_amount,<br /> SUM(IF(HOUR(detail.dtime)=1, detail.amount, 0)) AS 1_amount,<br /> SUM(IF(HOUR(detail.dtime)=2, detail.amount, 0)) AS 2_amount,<br /> SUM(IF(HOUR(detail.dtime)=3, detail.amount, 0)) AS 3_amount,<br /> SUM(IF(HOUR(detail.dtime)=4, detail.amount, 0)) AS 4_amount,<br /> SUM(IF(HOUR(detail.dtime)=5, detail.amount, 0)) AS 5_amount,<br /> SUM(IF(HOUR(detail.dtime)=6, detail.amount, 0)) AS 6_amount,<br /> SUM(IF(HOUR(detail.dtime)=7, detail.amount, 0)) AS 7_amount,<br /> SUM(IF(HOUR(detail.dtime)=8, detail.amount, 0)) AS 8_amount,<br /> SUM(IF(HOUR(detail.dtime)=9, detail.amount, 0)) AS 9_amount,<br /> SUM(IF(HOUR(detail.dtime)=10, detail.amount, 0)) AS 10_amount,<br /> SUM(IF(HOUR(detail.dtime)=11, detail.amount, 0)) AS 11_amount,<br /> SUM(IF(HOUR(detail.dtime)=12, detail.amount, 0)) AS 12_amount,<br /> SUM(IF(HOUR(detail.dtime)=13, detail.amount, 0)) AS 13_amount,<br /> SUM(IF(HOUR(detail.dtime)=14, detail.amount, 0)) AS 14_amount,<br /> SUM(IF(HOUR(detail.dtime)=15, detail.amount, 0)) AS 15_amount,<br /> SUM(IF(HOUR(detail.dtime)=16, detail.amount, 0)) AS 16_amount,<br /> SUM(IF(HOUR(detail.dtime)=17, detail.amount, 0)) AS 17_amount,<br /> SUM(IF(HOUR(detail.dtime)=18, detail.amount, 0)) AS 18_amount,<br /> SUM(IF(HOUR(detail.dtime)=19, detail.amount, 0)) AS 19_amount,<br /> SUM(IF(HOUR(detail.dtime)=20, detail.amount, 0)) AS 20_amount,<br /> SUM(IF(HOUR(detail.dtime)=21, detail.amount, 0)) AS 21_amount,<br /> SUM(IF(HOUR(detail.dtime)=22, detail.amount, 0)) AS 22_amount,<br /> SUM(IF(HOUR(detail.dtime)=23, detail.amount, 0)) AS 23_amount<br /> FROM<br /> session_detail_21_200909 AS detail<br /> LEFT JOIN contract_tariff ON contract_tariff.cid=detail.cid AND contract_tariff.date1&lt;=detail.dtime AND (contract_tariff.date2 IS NULL OR detail.dtime&lt;=contract_tariff.date2) <br /> LEFT JOIN tariff_plan AS tariff ON contract_tariff.tpid=tariff.id<br /> GROUP BY tariff.id<br /> ORDER BY tariff.title<br /> &lt;/source&gt;<br /> Если надо разделять по входящему/исходящему (и/или по прочим услугам), то добавить между JOIN и GROUP BY условие<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> WHERE detail.sid = &lt;ид услуги нужной&gt;<br /> &lt;/source&gt;<br /> Если были битые ссылки на тарифы, то будет строка с нулём, куда припишется всё левое, если надо откинуть поле с нулём, прибавить (к WHERE, разумеется) условие:<br /> &lt;source lang=&quot;sql&quot;&gt;AND ( tariff.id is not null )&lt;/source&gt;<br /> --[[Участник:DimOn|dimOn]] 10:40, 10 марта 2010 (UTC)<br /> <br /> == Выбрать все договоры без установленного параметра ==<br /> Если pid параметра = 10, то:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> select contract.id from contract<br /> left join contract_parameter_type_1 on contract_parameter_type_1.cid=contract.id and contract_parameter_type_1.pid=10<br /> where contract_parameter_type_1.val IS NULL<br /> &lt;/source&gt;<br /> <br /> == Выбрать все информацию по тарифу( версия &lt;=5.1 ) ==<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM tariff_plan <br /> left join tariff_tree_link on tariff_tree_link.tpid= tariff_plan.id <br /> left join tariff_tree on tariff_tree.id = tariff_tree_link.tree_id<br /> left join module_tariff_tree on module_tariff_tree.tree_id = tariff_tree_link.tree_id<br /> left join mtree_node on mtree_node.mtree_id = module_tariff_tree.id<br /> where tariff_plan.id = XXX<br /> &lt;/source&gt;<br /> <br /> XXX - id тарифного плана<br /> <br /> <br /> == Выбрать все информацию по тарифу( версия &gt;= 5.2) ==<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM tariff_plan <br /> -- LEFT JOIN tariff_tree_link ON tariff_tree_link.tpid= tariff_plan.id <br /> LEFT JOIN tariff_tree ON tariff_tree.id = tariff_plan.tree_id<br /> LEFT JOIN module_tariff_tree ON module_tariff_tree.tree_id = tariff_plan.tree_id<br /> LEFT JOIN mtree_node ON mtree_node.mtree_id = module_tariff_tree.id<br /> WHERE tariff_plan.id = XXX <br /> &lt;/source&gt;<br /> <br /> XXX - id тарифного плана<br /> <br /> == Все тарифы, в которых есть узел модуля ==<br /> вариант предыдущего запроса<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM tariff_plan<br /> JOIN tariff_tree_link ON tariff_tree_link.tpid= tariff_plan.id<br /> JOIN module_tariff_tree ON module_tariff_tree.tree_id = tariff_tree_link.tree_id <br /> WHERE module_tariff_tree.mid=XXX<br /> ORDER BY tariff_plan.id<br /> &lt;/source&gt;<br /> <br /> == Работа с группами ==<br /> Установка группы с кодом 7 договору с кодом 455:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> UPDATE contract SET gr = gr | (1&lt;&lt;7) WHERE id=455<br /> &lt;/source&gt;<br /> <br /> Удаление группы с кодом 7 из договора с кодом 455:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> UPDATE contract SET gr = gr&amp;(~(1&lt;&lt;7)) WHERE id=455<br /> &lt;/source&gt;<br /> <br /> Поиск договоров с группой 7:<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> SELECT * FROM contract WHERE gr&amp;(1&lt;&lt;7) &gt; 0<br /> &lt;/source&gt;<br /> <br /> == Генерация паролей ==<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> UPDATE CONTRACT SET pswd=SUBSTRING(RAND(9), 3, 14)<br /> &lt;/source&gt;<br /> <br /> == Выбор должников для системы автоматического обзвона ==<br /> Стоит задача написать некий код, который бы выбирал номера телефона из контракта, и сумму задолженности, для передачи в систему обзвона должников.<br /> Условия отбора должников - Контракт, входящий остаток которого меньше нуля и по которому нет поступлений в текущем месяце, а так же в параметрах которого установлен флаг &quot;Включить в систему обзвона должников&quot;.<br /> Обсуждение сдесь: http://forum.bgbilling.ru/viewtopic.php?f=19&amp;t=5303<br /> <br /> &lt;source lang=&quot;sql&quot;&gt;<br /> в разработке<br /> &lt;/source&gt;<br /> <br /> == Удаление абонплат, привязанных к уже несуществующим договорам ==<br /> проверка<br /> &lt;source lang=&quot;sql&quot;&gt;<br /> DELETE service_object FROM npay_service_object_66 AS service_object LEFT JOIN contract ON service_object.cid=contract.id WHERE contract.id IS NULL;<br /> &lt;/source&gt;<br /> sql</div> Thu, 19 Apr 2012 06:21:50 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%BD%D1%8B%D0%B5_SQL-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* Версия 5.2 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> DELETE FROM contract_service WHERE cid= + id + public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> import bitel.billing.server.task.bean.*; <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;;<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> date2=</div> Thu, 19 Apr 2012 06:18:25 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* Версия 5.2 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> DELETE FROM contract_service WHERE cid= + id + public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;;<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> date2=</div> Thu, 19 Apr 2012 06:18:04 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> DELETE FROM contract_service WHERE cid= + id + public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> import bitel.billing.server.task.bean.*; <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;;<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:17:41 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* Версия 5.2 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> import bitel.billing.server.task.bean.*; <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;;<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> date2 + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp =<br /> <br /> + TimeUtils.format(date2,<br /> <br /> + TimeUtils.format(date2,</div> Thu, 19 Apr 2012 06:12:01 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* Версия 5.2 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;;<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> date2 + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp =<br /> <br /> + TimeUtils.format(date2,</div> Thu, 19 Apr 2012 06:06:46 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* Версия 5.2 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> //Кусок отвечающий за перерасчет абонплаты<br /> // месяц за который идёт перерасчёт<br /> dateTask = new GregorianCalendar();<br /> // набор услуг, 0- все услуги<br /> serviceSet = 0;<br /> //Комментарий задачи<br /> comment = &quot;&quot;;<br /> email = &quot;null&quot;'<br /> <br /> new RunTaskDataManager( con ).addTask( new Recalculator( NPAY_MID, dateTask, email, serviceSet, Integer.toString(cid), comment ) );<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> date2 + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp =</div> Thu, 19 Apr 2012 06:06:08 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* 5.2 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == Версия 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> Добавлен автоматический вызов перерасчета абонплаты после синхронизации услуг --[[Участник:SinTeZWh1te|SinTeZWh1te]] 10:03, 19 апреля 2012<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> date2 + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp =</div> Thu, 19 Apr 2012 06:03:24 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* 5.1 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == Версия 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> +sid +<br /> <br /> == 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:01:57 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;/* 5.0 */</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == Версия 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:01:35 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Описание скрипта ==<br /> Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:00:50 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Синхронизация услуг договора в соответствии с тарифными планами http://wiki.bitel.ru/index.php/%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 <p>SinTeZWh1te:&#32;</p> <hr /> <div>Скрипт добавляет/изменяет услуги и синхронизирует периоды действия услуг автоматически в соответствии с услугами используемыми в тарифных планах договора. Его можно повесить на событие Изменение/удаление тарифного плана, и не задумываться, какие услуги используется в тарифах. <br /> Алгоритм коротко таков: <br /> Скрипт находит все услуги используемые во всех тарифных планах договора, и запоминает их периоды действия, получаем наборы<br /> &lt;source lang=&quot;ini&quot;&gt;<br /> sid1 date1_tariff1_with_sid1 date2_tariff_with_sid1<br /> ...<br /> date1_tariffN_with_sid1 date2_tariffN_with_sid1<br /> ...<br /> sidN date1_tariff1_with_sidN date2_tariff_with_sidN<br /> ...<br /> date1_tariffN_with_sidN date2_tariffN_with_sidN<br /> &lt;/source&gt;<br /> из этих наборов периодов отбрасываем пересекающиеся, и в соответсвии с результатом обновляем существующие услуги договора. Удобно!<br /> <br /> upd 14.04.2010<br /> Добавлен метод <br /> notSynchronizeServices(sids) ;<br /> в котором указывается список услуг, через запятую, которую не надо синхронизровать.<br /> Добавлено добавление записи(в случае необходимости) для договора, в таблицу contract_module для модуля NPay (если имеются услуги NPay, которые нужно синхронизировать). Добавлено по причине того что, на момент написания скрипта, при отсутствии записи в contract_module для NPay абонплата списывалась в полном объеме без учета статусов.<br /> ----<br /> == 5.0 ==<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 8 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractID() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.notSynchronizeServices(&quot;11,21,41,42,44&quot;);//Указываем список сервисов, которые не хотим, чтобы синхронизировались<br /> sidman.setDeleteNonNeeded(1) ;//Удаляем не нужные сервисы из договора, за исключением сервисов, которые не синхронизируем.<br /> sidman.setNpayMid(NPAY_MID) ;//Указываем ИД модуля абонплат<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=8 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == 5.1 ==<br /> <br /> Пофиксино для версии 5.1<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, (SELECT t.title FROM tariff_plan AS t WHERE t.id=ct.tpid) as title,&quot; +<br /> &quot;ct.date1, ct.date2 FROM contract_tariff AS ct LEFT JOIN tariff_tree_link as ttl ON ct.tpid=ttl.tpid &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;<br /> <br /> == 5.2 ==<br /> <br /> Пофиксено для 5.2 --[[Участник:Skyb|Skyb]] 06:01, 14 февраля 2012 (UTC)<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import java.sql.*;<br /> import java.util.*;<br /> import java.math.* ;<br /> import bitel.billing.server.contract.bean.*;<br /> import bitel.billing.server.tariff.*;<br /> import bitel.billing.server.util.*;<br /> import bitel.billing.common.KernelConst; <br /> import bitel.billing.server.npay.bean.*;<br /> import bitel.billing.server.script.bean.event.*;<br /> import bitel.billing.server.npay.*;<br /> <br /> <br /> public void onEvent( event, setup, con, conSlave ) <br /> {<br /> //print( event ) ;<br /> int NPAY_MID = 4 ;<br /> SidsSynchroManager sidman = new SidsSynchroManager() ;<br /> int cid = event.getContractId() ;<br /> //sidman.setDebugMode(0) ;<br /> sidman.setDeleteNonNeeded(1) ;<br /> sidman.setNpayMid(NPAY_MID) ;<br /> sidman.notSynchronizeServices(&quot;9,7,11&quot;);<br /> sidman.synchronizeServices( cid, con ) ;<br /> <br /> }<br /> <br /> <br /> <br /> //Класс синхронизации услуг<br /> public class SidsSynchroManager {<br /> <br /> public SidsSynchroManager()<br /> {<br /> vSidsData = new Vector() ;<br /> vNpaySidsData = new Vector() ;<br /> GregorianCalendar cal = new GregorianCalendar() ;<br /> cal.set(1970, 0, 1 ) ; <br /> _DATE1_NULL = cal.getTime() ;<br /> cal.set(2020, 0, 1 ) ; <br /> _DATE2_NULL = cal.getTime() ;<br /> }<br /> <br /> public void setNpayMid( int npayMid)<br /> {<br /> NPAY_MID = npayMid ;<br /> }<br /> public void setDebugMode(int debug)<br /> {<br /> _DEBUG = debug ;<br /> }<br /> //Не синхронизировать список услуг. через запятую.<br /> public void notSynchronizeServices( String sids ) <br /> {<br /> noSynchroList = sids ;<br /> }<br /> public void setDeleteNonNeeded( int dnn)//0 - Не удалять не нужные сервисы, 1 - удалять<br /> {<br /> deleteNonNeeded = dnn ;<br /> }<br /> //Точка входа. Синхронизирует сервисы договора<br /> public void synchronizeServices( int cid, Connection con )<br /> {<br /> vSidsData.clear() ;<br /> vNpaySidsData.clear() ;<br /> //Выбираем глобальные тарифы, и запоминаем периоды действия их услуг<br /> String SQL = &quot;SELECT tree_id, t.title, ct.date1, ct.date2 &quot; +<br /> &quot;FROM contract_tariff AS ct LEFT JOIN tariff_plan as t ON ct.tpid=t.id &quot; +<br /> &quot;WHERE ct.cid=&quot; + cid ;<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;ct.date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;ct.date2&quot;) ;<br /> if ( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con) ;//Сохраняем услуги в набор<br /> }<br /> //Выбираем персональные тарифы, и запоминаем периоды действия их услуг<br /> SQL = &quot;SELECT tree_id, title, date1, date2 FROM contract_tree_link WHERE cid=&quot; + cid ;<br /> ps = con.prepareStatement( SQL );<br /> rs = ps.executeQuery();<br /> if ( _DEBUG == 1 ){<br /> print(&quot;personals&quot;) ;<br /> }<br /> while ( rs.next() )<br /> {<br /> int tree_id = rs.getInt(&quot;tree_id&quot;) ;<br /> String title = rs.getString(&quot;title&quot;) ;<br /> Date date1 = rs.getDate(&quot;date1&quot;) ;<br /> Date date2 = rs.getDate(&quot;date2&quot;) ;<br /> if( _DEBUG == 1 ) {<br /> print (&quot;tree_id=&quot; + tree_id + &quot; title=&quot; + title + &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> }<br /> findServicesForTariff( tree_id, 0, date1, date2, con ) ;<br /> }<br /> <br /> <br /> //Для каждой услуги синхронизируем периоды действия, отбрасывая пересекающиеся периоды<br /> calcActualServicePeriods( vSidsData ) ;<br /> //Тоже самое для услуг Абонплат.<br /> calcActualServicePeriods( vNpaySidsData ) ;<br /> <br /> //Выводим в вывод, список услуг, так, как они будут заведены. Здесь не могут быть пересекающихся периодов для одной услуги.<br /> print( &quot;Services must be synchronized with folowing date periods&quot;) ;<br /> printInternalDataForContract( cid ) ;<br /> <br /> //Обновляем услуги договора<br /> updateSynchronizedServices( cid, 0, con ) ;<br /> //Обновляем услуги абонплат договора<br /> updateSynchronizedServices( cid, NPAY_MID, con ) ;<br /> }<br /> <br /> public void printInternalDataForContract( int cid )<br /> {<br /> print(&quot;cid=&quot;+cid) ;<br /> print(&quot;SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> vSidsData.get(i).printData() ;<br /> }<br /> print(&quot;NPAY SERVICES:&quot;) ;<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> vNpaySidsData.get(i).printData() ;<br /> }<br /> <br /> }<br /> <br /> private void updateSynchronizedServices( int cid, int nPayMid, Connection con )<br /> {<br /> String SQLdelNonNeeded = &quot;&quot; ;<br /> String SQLsel = &quot;&quot; ;<br /> String SQLupd = &quot;&quot; ;<br /> String SQLins = &quot;&quot; ;<br /> String SQLdel = &quot;&quot; ;<br /> Vector vSids = vSidsData ;<br /> String dateNow = TimeUtils.format(new GregorianCalendar(), &quot;yyyy-MM-dd hh:mm:ss&quot;) ;<br /> if ( nPayMid == 0 ){<br /> SQLsel = &quot;SELECT id, date1, date2 FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE contract_service SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO contract_service (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM contract_service WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vSidsData) ;<br /> if ( sidslist == &quot;&quot; ) { sidslist = &quot;-1&quot; ;}<br /> SQLdelNonNeeded = &quot;DELETE FROM contract_service WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + <br /> sidslist +&quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> else{<br /> vSids = vNpaySidsData ;<br /> SQLsel = &quot;SELECT id, date1, date2 FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid=? ORDER BY date1, date2&quot; ;<br /> SQLupd = &quot;UPDATE npay_service_object_&quot; + nPayMid + &quot; SET date1=?, date2=?, comment='Service synchronize(update from &quot; + <br /> dateNow + &quot;)' WHERE id=?&quot; ;<br /> SQLins = &quot;INSERT INTO npay_service_object_&quot; + nPayMid + &quot; (cid, sid, date1, date2, comment ) VALUES ( &quot; + <br /> cid + &quot;, ? , ? , ?, 'Service synchronize(insert from &quot; + dateNow + &quot;)')&quot; ;<br /> SQLdel = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE id=?&quot; ; <br /> String sidslist = getServiceList(vNpaySidsData) ;<br /> if ( sidslist == &quot;&quot; ) {<br /> sidslist = &quot;-1&quot; ;<br /> } else { //Список услуг абонплат для синхронизации не пуст. Добавляем в таблицу contract_module запись при необходимости<br /> SQLtmp = &quot;SELECT mid FROM contract_module WHERE cid=&quot; + cid + &quot; AND mid=&quot; + NPAY_MID ;<br /> PreparedStatement ps = con.prepareStatement( SQLtmp );<br /> rs = ps.executeQuery() ;<br /> if( !rs.next() )<br /> {<br /> SQLtmp = &quot;INSERT INTO contract_module (cid,mid) VALUES (&quot; + cid + &quot;,&quot; + NPAY_MID + &quot;)&quot; ;<br /> ps = con.prepareStatement( SQLtmp );<br /> ps.executeUpdate() ;<br /> }<br /> }<br /> <br /> SQLdelNonNeeded = &quot;DELETE FROM npay_service_object_&quot; + nPayMid + &quot; WHERE cid=&quot; + cid + &quot; AND sid NOT IN (&quot; + sidslist + &quot;) AND sid NOT IN (&quot; + noSynchroList + &quot;)&quot; ;<br /> }<br /> <br /> <br /> <br /> if ( deleteNonNeeded == 1 )<br /> {<br /> <br /> print( SQLdelNonNeeded ) ;<br /> PreparedStatement psDelOther = con.prepareStatement( SQLdelNonNeeded ) ;<br /> psDelOther.executeUpdate( SQLdelNonNeeded ) ;<br /> }<br /> PreparedStatement ps = con.prepareStatement( SQLsel );<br /> PreparedStatement psUpd = con.prepareStatement( SQLupd );<br /> PreparedStatement psIns = con.prepareStatement( SQLins );<br /> PreparedStatement psDel = con.prepareStatement( SQLdel );<br /> <br /> ResultSet rs ;<br /> SidsData sd ;<br /> Date date1, date2 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> int sid = sd.sid ;<br /> ps.setInt(1, sid) ;<br /> rs = ps.executeQuery() ;<br /> j = 0 ; <br /> while( rs.next() )<br /> {<br /> int id = rs.getInt(&quot;id&quot;) ;<br /> date1 = rs.getDate(&quot;date1&quot;) ;<br /> date2 = rs.getDate(&quot;date2&quot;) ;<br /> //Чтобы при сравнении дат equals не давал exeption, подменяем значения null<br /> //print( &quot;date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> if ( date1 == null ){<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ){<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> //Лишняя услуга, удаляем<br /> if ( j &gt;= sd.vDate1.size() )<br /> {<br /> psDel.setInt( 1, id ) ;<br /> psDel.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Delete service with id=&quot; + id + &quot; for service=&quot;+sid + <br /> &quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psDel=&quot; + psDel ) ;<br /> }<br /> continue ;<br /> }<br /> <br /> <br /> if ( !date1.equals(sd.vDate1.get(j)) || !date2.equals(sd.vDate2.get(j)) )<br /> {<br /> //Возвращаем значения null при необходимости для обновления инфы в БД<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psUpd.setInt( 3, id ) ;<br /> psUpd.setDate( 1, sd.vDate1.get(j) ) ;<br /> psUpd.setDate( 2, sd.vDate2.get(j) ) ;<br /> psUpd.executeUpdate() ;<br /> if (_DEBUG==1){<br /> print( &quot;Update service with id=&quot; + id + &quot; for service=&quot;+sid + &quot; previous date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psUpd=&quot; + psUpd ) ;<br /> }<br /> }<br /> j++ ;<br /> }//end while<br /> <br /> for( ; j &lt; sd.vDate1.size(); j++)<br /> {<br /> if ( sd.vDate1.get(j).equals( _DATE1_NULL) ){<br /> sd.vDate1.set( j, null ) ;<br /> }<br /> if ( sd.vDate2.get(j).equals( _DATE2_NULL) ){<br /> sd.vDate2.set( j, null ) ;<br /> }<br /> psIns.setInt(1, sid ) ;<br /> psIns.setDate( 2, sd.vDate1.get(j) ) ;<br /> psIns.setDate( 3, sd.vDate2.get(j) ) ;<br /> if (_DEBUG==1){<br /> print( &quot;Insert new service=&quot;+sid + &quot; date1=&quot; + <br /> TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;)) ;<br /> print( &quot;psIns&quot; + psIns ) ;<br /> }<br /> psIns.executeUpdate() ;<br /> }<br /> <br /> }<br /> <br /> }<br /> <br /> private String getServiceList(Vector vSids)<br /> {<br /> String sids = &quot;&quot;;<br /> int i ;<br /> for( i = 0; i&lt;vSids.size()-1; i++)<br /> {<br /> sids += &quot;&quot; + vSids.get(i).sid + &quot;,&quot; ;<br /> }<br /> if ( i &lt; vSids.size()) {<br /> sids += &quot;&quot; + vSids.get(i).sid ;<br /> }<br /> return sids ;<br /> }<br /> <br /> private calcActualServicePeriods( Vector vSids )<br /> {<br /> prepareInternalData() ;<br /> SidsData sd ;<br /> Vector vDate1 = new Vector() ;<br /> Vector vDate2 = new Vector() ;<br /> Date date1 ;<br /> Date date2 ;<br /> GregorianCalendar date1cal = new GregorianCalendar() ; //Для хранения date1+1 день<br /> k = 0 ;<br /> for( int i = 0; i&lt;vSids.size(); i++)<br /> {<br /> sd = vSids.get(i) ;<br /> vDate1.clear() ;<br /> vDate2.clear() ;<br /> for ( j = 0 ; j &lt; sd.vDate1.size() ; )//Отсеиваем ненужные периоды<br /> {<br /> date1 = sd.vDate1.get(j) ;<br /> date2 = sd.vDate2.get(j) ;<br /> if ( date1.compareTo( date2) &gt; 0 )<br /> {<br /> print(&quot;Fatal error, date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; &gt; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ;<br /> print(&quot;Services was not synchronized...&quot;) ;<br /> return ;<br /> }<br /> for( j++ ; j&lt;sd.vDate1.size(); j++)<br /> {<br /> date1cal.setTime( sd.vDate1.get(j) ) ;<br /> date1cal.roll(Calendar.DAY_OF_YEAR,-1) ;<br /> if ( date2.compareTo(date1cal.getTime()) &lt; 0 ) // Нашли нужный date2 для date1 ;<br /> {<br /> break ;<br /> }<br /> else<br /> {<br /> date2 = sd.vDate2.get(j) ;<br /> }<br /> }<br /> vDate1.add(date1) ;<br /> vDate2.add(date2) ;<br /> }<br /> <br /> sd.vDate1.clear() ;<br /> sd.vDate2.clear() ;<br /> sd.vDate1 = vDate1.clone() ;<br /> sd.vDate2 = vDate2.clone() ;<br /> <br /> }<br /> }<br /> <br /> private prepareInternalData()//Подготовливает внутренние данные для основного алгоритма. Сортирует массивы date услуг<br /> {<br /> SidsData sd ;<br /> for( int i = 0; i&lt;vSidsData.size(); i++)<br /> {<br /> sd = vSidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> }<br /> for( int i = 0; i&lt;vNpaySidsData.size(); i++)<br /> {<br /> sd = vNpaySidsData.get(i) ;<br /> Collections.sort(sd.vDate1 ) ;<br /> Collections.sort(sd.vDate2 ) ;<br /> <br /> }<br /> <br /> }<br /> <br /> private void addSid( int sid, Date date1, Date date2, int npayService )<br /> {<br /> String[] noSids = noSynchroList.split(&quot;,&quot;) ;<br /> for ( int i = 0 ; i&lt;noSids.length; i++ )<br /> {<br /> if ( Integer.parseInt( noSids[i].trim() ) == sid ) { return ;}<br /> }<br /> //Заменяем нулевые значения дат значениями _DATE1_NULL и DATE2_NULL соответсвенно<br /> if ( date1 == null ) {<br /> date1 = _DATE1_NULL.clone() ;<br /> }<br /> if ( date2 == null ) {<br /> date2 = _DATE2_NULL.clone() ;<br /> }<br /> <br /> Vector vSids = vSidsData;<br /> if ( npayService != 0 )<br /> {<br /> vSids = vNpaySidsData ;<br /> }<br /> int f = 0 ;<br /> SidsData sd ;<br /> for ( int i=0; i &lt; vSids.size(); i++ )<br /> {<br /> sd = vSids.get(i) ;<br /> if (sd.sid == sid)<br /> {<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> f = 1 ; break ;<br /> }<br /> }<br /> if ( f == 0 )<br /> {<br /> sd = new SidsData( sid ) ;<br /> sd.vDate1.add(date1) ;<br /> sd.vDate2.add(date2) ;<br /> vSids.add( sd ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff( int tree_id, int mid /*если не 0, то выборка из родительского тарифа*/, <br /> Date date1, Date date2, Connection con) <br /> {<br /> String SQL = &quot;SELECT id, mid, parent_tree FROM module_tariff_tree WHERE tree_id=&quot; + tree_id ;<br /> if ( mid != 0 )<br /> {<br /> SQL += &quot; AND mid=&quot; + mid ;<br /> }<br /> //print(SQL) ;<br /> PreparedStatement ps = con.prepareStatement( SQL );<br /> ResultSet rs = ps.executeQuery() ;<br /> <br /> while ( rs.next() )<br /> {<br /> int mtreeid = rs.getInt(&quot;id&quot;) ;<br /> int mid = rs.getInt(&quot;mid&quot;) ;<br /> int parent_tree = rs.getInt(&quot;parent_tree&quot;) ;<br /> if (parent_tree != 0 )<br /> {<br /> findServicesForTariff( parent_tree, mid, date1, date2, con ) ;<br /> continue ;<br /> }<br /> findServicesForTariff2( mtreeid, mid, date1, date2, con ) ;<br /> }<br /> }<br /> <br /> private void findServicesForTariff2( int mtreeid, int mid, Date date1, Date date2, Connection con )<br /> {<br /> SQL = &quot;SELECT type, data &quot; + <br /> &quot;FROM mtree_node &quot; +<br /> &quot;WHERE mtree_id=&quot; + mtreeid + &quot; AND type IN ('service', 'multi_service', 'month_mode', 'day_mode')&quot; ;<br /> PreparedStatement ps = con.prepareStatement( SQL ) ;<br /> ResultSet rs = ps.executeQuery() ;<br /> int sid = 0;<br /> while ( rs.next() )<br /> {<br /> String type = rs.getString(&quot;type&quot;) ;<br /> String data = rs.getString(&quot;data&quot;) ;<br /> //print ( &quot;type=&quot; + type + &quot; data=&quot; + data) ;<br /> if (type.equals(&quot;service&quot;) )<br /> {<br /> sid = Integer.parseInt( data ) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> <br /> //print ( &quot;sid=&quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;multi_service&quot;) )<br /> {<br /> String[] ss = data.split(&quot;&amp;&quot;) ;<br /> String[] sids = ss[1].split(&quot;,&quot;) ;<br /> //print ( &quot;sids=&quot; + ss[1] ) ;<br /> for ( int i=0; i &lt; sids.length; i++ )<br /> {<br /> sid=Integer.parseInt(sids[i]) ;<br /> addSid( sid, date1, date2, 0 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> //print( &quot;sid = &quot; + sid ) ;<br /> }<br /> }<br /> else if( type.equals(&quot;month_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;month_mode sid = &quot; + sid ) ;<br /> }<br /> else if( type.equals(&quot;day_mode&quot;) )<br /> {<br /> String[] ss = data.split(&quot;%&quot;) ;<br /> for ( int i = 0; i &lt; ss.length ; i++ )<br /> {<br /> String[] sids=ss[i].split(&quot;&amp;&quot;) ;<br /> if ( sids[0].equals(&quot;sid&quot;) )<br /> {<br /> sid = Integer.parseInt(sids[1]) ;<br /> addSid( sid, date1, date2, 1 ) ; //Добавляем найденную услугу в набор найденных услуг<br /> break ;<br /> }<br /> }<br /> //print( &quot;day_mode sid = &quot; + sid ) ;<br /> }<br /> <br /> }//end while<br /> }<br /> <br /> <br /> //внутренниц класс для хранения услуги и множества дат date1 и date2 <br /> private class SidsData{<br /> public int sid ;<br /> public Vector vDate1 ;<br /> public Vector vDate2 ;<br /> <br /> public SidsData()<br /> {<br /> sid = 0 ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> <br /> public SidsData( int s )<br /> {<br /> sid=s ;<br /> vDate1 = new Vector() ;<br /> vDate2 = new Vector() ;<br /> }<br /> public printData()<br /> {<br /> print (&quot;sid=&quot; + sid) ;<br /> for( i=0; i&lt;vDate1.size(); i++ )<br /> {<br /> Date date1 = vDate1.get(i) ;<br /> Date date2 = vDate2.get(i) ;<br /> if ( date1.equals( _DATE1_NULL) ){<br /> date1 = null ;<br /> }<br /> if ( date2.equals( _DATE2_NULL) ){<br /> date2 = null ;<br /> }<br /> <br /> print (&quot; date1=&quot; + TimeUtils.format(date1, &quot;yyyy-MM-dd&quot;) + &quot; date2=&quot; <br /> + TimeUtils.format(date2, &quot;yyyy-MM-dd&quot;) ) ; <br /> }<br /> }<br /> }<br /> <br /> private int NPAY_MID=4 ;<br /> private int _DEBUG=0 ;<br /> private int deleteNonNeeded = 0 ;<br /> static private Date _DATE1_NULL ;<br /> static private Date _DATE2_NULL ;<br /> private Vector vSidsData ;<br /> private Vector vNpaySidsData ;<br /> private String noSynchroList = &quot;1000000&quot; ;//не синхронизировать услуги.<br /> }<br /> &lt;/source&gt;</div> Thu, 19 Apr 2012 06:00:16 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A1%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%83%D1%81%D0%BB%D1%83%D0%B3_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%B0_%D0%B2_%D1%81%D0%BE%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B8%D0%B8_%D1%81_%D1%82%D0%B0%D1%80%D0%B8%D1%84%D0%BD%D1%8B%D0%BC%D0%B8_%D0%BF%D0%BB%D0%B0%D0%BD%D0%B0%D0%BC%D0%B8 Запрет на вход в личный кабинет с закрытых договоров http://wiki.bitel.ru/index.php/%D0%97%D0%B0%D0%BF%D1%80%D0%B5%D1%82_%D0%BD%D0%B0_%D0%B2%D1%85%D0%BE%D0%B4_%D0%B2_%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D0%BA%D0%B0%D0%B1%D0%B8%D0%BD%D0%B5%D1%82_%D1%81_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D1%85_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 <p>SinTeZWh1te:&#32;</p> <hr /> <div>При переоформлении договоров иногда возникает необходимость выдать клиенту точно такой-же логин, как у него и был. В случае настройки сервера для авторизации в личном кабинете по текстовому параметру сервер по умолчанию будет всегда пытаться авторизовать клиента по договору, который был создан раньше других. Чтобы избежать такого поведения можно использовать самописный класс авторизации, который будет воплощать стандартный класс авторизации. <br /> <br /> В настройках сервера необходимо указать: web.auth.class=&lt;ваш класс&gt;<br /> Вот пример класса, который будет пытаться авторизовать клиента с указанным логином в первый договор, дата действия которого не меньше сегодняшнего числа.<br /> &lt;source lang=&quot;java&quot;&gt;package ru.itax.web;<br /> <br /> import java.sql.Connection;<br /> import java.sql.PreparedStatement;<br /> import java.sql.ResultSet;<br /> import java.util.Date;<br /> <br /> import ru.bitel.bgbilling.server.util.Setup;<br /> <br /> import bitel.billing.common.TimeUtils;<br /> import bitel.billing.server.ModuleUser;<br /> import bitel.billing.server.contract.bean.Contract;<br /> import bitel.billing.server.contract.bean.ContractManager;<br /> import bitel.billing.server.contract.bean.ContractParameterManager;<br /> <br /> public class WebLogin implements bitel.billing.server.ModuleAuth {<br /> <br /> @Override<br /> public ModuleUser findModuleUserByLogin( String login,<br /> int moduleId,<br /> int authMode,<br /> Connection con )<br /> {<br /> ModuleUser moduleUser = null;<br /> <br /> if ( login != null &amp;&amp; login.trim().length() &gt; 0 &amp;&amp; moduleId &gt; -1 )<br /> {<br /> try<br /> {<br /> String query = null;<br /> if ( authMode == 1 )<br /> {<br /> query = &quot;SELECT id, pswd FROM contract WHERE title=? LIMIT 1&quot;; <br /> }<br /> else if ( authMode == 2 )<br /> {<br /> Integer pid = Setup.getSetup().getInt( &quot;web.auth.contract.text.parameter&quot;, 0 );<br /> if ( pid &gt; 0 )<br /> { <br /> query = &quot;SELECT id, pswd FROM contract &quot; +<br /> &quot; LEFT JOIN &quot; + ContractParameterManager.CONTRACT_PARAMETER_TYPE_STRING + &quot; as param &quot; +<br /> &quot; ON param.cid = contract.id &quot; +<br /> &quot; AND param.pid = &quot; + pid +<br /> &quot; WHERE param.val=? &quot;; <br /> }<br /> }<br /> <br /> if (query != null )<br /> {<br /> ResultSet rs = null;<br /> PreparedStatement ps = null;<br /> ContractManager cm=new ContractManager(con);<br /> ps = con.prepareStatement( query );<br /> ps.setString( 1, login );<br /> rs = ps.executeQuery();<br /> while ( rs.next() )<br /> {<br /> //получаем договор и проверяем не позже ли сегодняшнего числа дата его закрытия. Если да - авторизуем. <br /> Contract contract=cm.getContractById(rs.getInt(1));<br /> if(!TimeUtils.dateBefore(contract.getDateTo(), new Date()))<br /> {<br /> moduleUser = new ModuleUser();<br /> moduleUser.setLogin( login );<br /> moduleUser.setPassword( rs.getString( 2 ) );<br /> moduleUser.setContractId( rs.getInt( 1 ) );<br /> moduleUser.setContractTitle( login ); <br /> }<br /> <br /> }<br /> rs.close();<br /> ps.close();<br /> }<br /> <br /> }<br /> catch( Exception e )<br /> {<br /> e.printStackTrace();<br /> }<br /> }<br /> return moduleUser;<br /> }<br /> <br /> }<br /> &lt;/source&gt;<br /> <br /> Скрипт необходимо скомпилировать, заархивировать в jar архив и положить в папку lib сервера. Сервер перезапустить.</div> Thu, 15 Mar 2012 09:59:52 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%97%D0%B0%D0%BF%D1%80%D0%B5%D1%82_%D0%BD%D0%B0_%D0%B2%D1%85%D0%BE%D0%B4_%D0%B2_%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D0%BA%D0%B0%D0%B1%D0%B8%D0%BD%D0%B5%D1%82_%D1%81_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D1%8B%D1%85_%D0%B4%D0%BE%D0%B3%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D0%B2 Нормализация параметра Acct-Session-Id у маршрутизатора Cisco http://wiki.bitel.ru/index.php/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D0%B0_Acct-Session-Id_%D1%83_%D0%BC%D0%B0%D1%80%D1%88%D1%80%D1%83%D1%82%D0%B8%D0%B7%D0%B0%D1%82%D0%BE%D1%80%D0%B0_Cisco <p>SinTeZWh1te:&#32;</p> <hr /> <div>Столкнулся с такой проблемой:&lt;br&gt;<br /> Цыска не поддерживает PoD, а Биллинг почему то не сбрасывает клиентские сессии ПППоЕ по SNMP.&lt;br&gt;<br /> После детальных разборов стало ясно что цыска шлёт атрибут Acct-Session-Id=000000000000135B в таком формате, хотя на самой Cisco идентификатор сессиии был 135B. Попытался решить проблему поставив в конфигурации НАСа session.mode=hex12 (http://bgbilling.ru/v5.0/doc/ch03s08.html) однако идентификатор сессии на Cisco оказался плавающим и может составлять не 4 знака, а 5 или даже 6! Поэтому пришлось написать вот такой скрипт предобработки для радиус пакета, за что отдельное спасибо Амиру.&lt;br&gt;<br /> &lt;source lang=&quot;java&quot;&gt;<br /> import bitel.billing.server.radius.*;<br /> <br /> acctSessionId = request.getStringAttribute(RadiusStandartAttributes.Acct_Session_Id);<br /> if( acctSessionId != null &amp;&amp; acctSessionId.startsWith( &quot;0&quot; ) )<br /> {<br /> request.setStringAttribute( RadiusStandartAttributes.Acct_Session_Id, acctSessionId.replaceFirst( &quot;^[0]++&quot;, &quot;&quot; ) );<br /> }<br /> &lt;/source&gt;</div> Mon, 13 Feb 2012 05:47:05 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D0%B0_Acct-Session-Id_%D1%83_%D0%BC%D0%B0%D1%80%D1%88%D1%80%D1%83%D1%82%D0%B8%D0%B7%D0%B0%D1%82%D0%BE%D1%80%D0%B0_Cisco Включение должников по приходу платежа http://wiki.bitel.ru/index.php/%D0%92%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%BE%D0%BB%D0%B6%D0%BD%D0%B8%D0%BA%D0%BE%D0%B2_%D0%BF%D0%BE_%D0%BF%D1%80%D0%B8%D1%85%D0%BE%D0%B4%D1%83_%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%B6%D0%B0 <p>SinTeZWh1te:&#32;</p> <hr /> <div>&lt;p&gt;Работает в 4.6, 5.0&lt;/p&gt;<br /> &lt;p&gt;Усовершенствованная логика включения клиентов по приходу платежа:<br /> &lt;ul&gt;<br /> &lt;li/&gt;Проверяется сальдо в зависимости от числа месяца : до дедлайна закрываем глаза на неоплату предыдущего месяца<br /> &lt;li/&gt;Статус &quot;приостановлен&quot;, установленный на будущий период, не перетирается.<br /> &lt;/ul&gt;<br /> &lt;/p&gt;<br /> <br /> &lt;source lang=&quot;java&quot;&gt;<br /> import bitel.billing.server.contract.bean.*;<br /> import java.util.*;<br /> import bitel.billing.server.util.*;<br /> import java.math.BigDecimal;<br /> import bitel.billing.common.KernelConst;<br /> <br /> alarm_email = &quot;&quot;;<br /> <br /> int cid = event.getContractID();<br /> Calendar now = Calendar.getInstance();<br /> p = event.getPayment();<br /> <br /> cm = new ContractManager( con );<br /> cstm = new ContractStatusManager( con );<br /> bu = new BalanceUtils( con );<br /> c = cm.getContractByID( event.getContractID() );<br /> <br /> print(&quot;Сумма платежа&quot; + p.getSumma()+&quot;\n&quot;);<br /> print(&quot;Текущий статус: &quot; + c.getStatus()+&quot;\n&quot;);<br /> <br /> // Если мы - субдоговор с зависимым балансом - ничего не делаем.<br /> // note: При приходе платежа на субдоговор не генерируется евент прихода платежа для основного, поэтому основной не откроется, хотя должен. Но мы не будем обрабатывать подобные ситуации, т.к. платеж на субдоговор - это ненормальная ситуация для нашей бизнес-логики.<br /> if (c.getSuperId()&gt;0 &amp;&amp; c.getSubMode()==0){<br /> print(&quot;Договор является субдоговором с зависимым балансом =&gt; ничего не делаем&quot;);<br /> //можно выслать email:<br /> //m = c.getTitle() + &quot; &quot; + c.getComment() + &quot;\n&quot;;<br /> //m = m+ &quot;Поступил платеж на зависимый субдоговор: &quot;+p.getSumma()+ &quot; руб от &quot;+TimeUtils.format(p.getPaymentDate(),&quot;dd.MM.yyyy&quot;)+&quot;\n&quot;;<br /> //m = m+ p.getComment()+ &quot;\n&quot;;<br /> //subj = &quot;Платеж на зависимый субдоговор &quot;+c.getTitle()+&quot; &quot;+p.getSumma()+&quot;р &quot;+ c.getComment();<br /> //MailMsg msg = new MailMsg(setup);<br /> //msg.sendMessage(alarm_email, subj, m);<br /> //print(&quot;Письмо отправлено&quot;);<br /> return;<br /> }<br /> <br /> //Если баланс больше или равен лимиту, то выполняем далее, иначе - ничего не делаем<br /> balance_limit = c.getBalanceLimit().floatValue();<br /> current_balance = bu.getBalance(new Date(), c).floatValue();<br /> <br /> print(&quot;Баланс: &quot;+current_balance);<br /> if(current_balance &lt; balance_limit){<br /> print(&quot;Баланс меньше лимита. Пропускаем договор\n&quot;);<br /> return;<br /> }else{<br /> print(&quot;Баланс ОК\n&quot;);<br /> }<br /> <br /> //Проверка сальдо для кредитных договоров:<br /> //Если в текущем месяце при разблокировании смотреть на :<br /> //1. Лимит - остаток должен быть больше лимита<br /> //2. до 26 проверять чтобы оплата была &gt;= 95%*остаток на 1-е число предыдущего месяца, после 26 числа оплата должна быть &gt;= 95%*остаток на 1-е число текущего месяца<br /> if(c.getBalanceMode()==Contract.CREDIT_BALANCE_MODE){<br /> float saldo = 0;<br /> float debt = 0;<br /> if((new GregorianCalendar()).get(Calendar.DAY_OF_MONTH)&lt;26){<br /> Calendar last_month = now.clone();<br /> last_month.add(Calendar.MONTH,-1);<br /> saldo = bu.getSaldo(last_month.getTime(), c.getID()).floatValue()+ bu.getSaldo(now.getTime(), c.getID()).floatValue() - bu.getBalanceSumma1(now.getTime(), c.getID()).floatValue();<br /> debt = bu.getBalanceSumma1(last_month.getTime(), c.getID()).floatValue();<br /> print(&quot;Сальдо за предыдущий месяц + приход в текущем: &quot; + saldo+&quot;\n&quot;);<br /> print(&quot;Входящий остаток в предыдущем месяце: &quot; + debt+&quot;\n&quot;);<br /> }else{<br /> saldo = bu.getSaldo(now.getTime(), c.getID()).floatValue();<br /> debt = bu.getBalanceSumma1(now.getTime(), c.getID()).floatValue();<br /> print(&quot;Сальдо за текущий месяц: &quot; + saldo+&quot;\n&quot;);<br /> print(&quot;Входящий остаток в текущем месяце: &quot; + debt+&quot;\n&quot;);<br /> }<br /> //<br /> if(saldo&lt;0.05*debt){<br /> print(&quot;Сальдо &lt; 0.05*(вх. остаток), долг не погашен - не открываем: \n&quot;);<br /> print(saldo + &quot; &lt; &quot; + &quot;0.05*&quot;+debt + &quot;\n&quot;);<br /> return;<br /> }<br /> }<br /> <br /> //Все тесты прошли - можно открывать клиента:<br /> //----------------------------------------------------------------------//<br /> //Если текущий статус Активен и далее нет никаких статусов в будущем пропускаем скрипт<br /> print(&quot;Можно открывать!\n&quot;);<br /> List statusList = cstm.getStatusList(cid, now);<br /> if(statusList.size() == 0){<br /> print(&quot;Список изменений статусов пуст, ничего не делаем - видимо договор и так активен\n&quot;);<br /> return;<br /> }<br /> lastStatus = ((ContractStatus)statusList.get(0)).getStatus();<br /> if(statusList.size() == 1 &amp;&amp; lastStatus == 0){<br /> print(&quot;Договор и так активен\n&quot;);<br /> return;<br /> }<br /> // Если последний и единственный на текущее время статус договора - &quot;приостановить&quot;.<br /> // пропускаем выполнение.<br /> if(statusList.size() == 1 &amp;&amp; lastStatus == 4){<br /> print(&quot;Договору не нужен статус = АКТИВЕН. Последний статус договора = Приостановить.\n&quot;);<br /> return;<br /> }<br /> //----------------------------------------------------------------------//<br /> //Строим список будущих статусов договоора.<br /> //Тут будем менять текущий и будущие статусы на активен, а период оставляем тот же.<br /> //Не будем изменять статус в этом листе, если статус=приостановлен<br /> List newstatusList = new ArrayList();<br /> for (Iterator i = statusList.iterator(); i.hasNext();) {<br /> ContractStatus s = (ContractStatus) i.next();<br /> cStatus=s.getStatus();<br /> // Если будущйи статус = ОТКЛЮЧЕН или Закрыт<br /> if( cStatus == 2 || cStatus == 3){<br /> s.setStatus(0);<br /> if(s.getDate1().before(now)){s.setDate1(now);}<br /> s.setComment(&quot;Статус изменен скриптом 'Изменение статуса договора по приходу платежа'&quot;);<br /> newstatusList.add(s);<br /> }<br /> print(&quot;Статус: &quot;+cStatus+&quot; Будущий статус: &quot;+s.getStatus()+&quot;\nБаланс: &quot;+current_balance+&quot;\nBalMode: &quot;+c.getBalanceMode()+&quot;\n&quot;);<br /> }<br /> // Меняем статусы в соответствии с новым списком статусов<br /> for (Iterator t = newstatusList.iterator(); t.hasNext();){<br /> ContractStatus s2 = (ContractStatus) t.next(); <br /> cstm.changeStatus(s2,0,true);<br /> }<br /> &lt;/source&gt;<br /> <br /> <br /> ----<br /> <br /> В версии 5.1 изменили метод '''getStatusList'''.<br /> Теперь его необходимо использовать без указания даты.<br /> В вышенаписанном скрипте необходимо изменить строку <br /> &lt;source lang=&quot;java&quot;&gt;List statusList = cstm.getStatusList(cid, now);&lt;/source&gt;<br /> на<br /> &lt;source lang=&quot;java&quot;&gt;List statusList = cstm.getStatusList(cid);&lt;/source&gt;</div> Mon, 17 Oct 2011 08:38:43 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%92%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B4%D0%BE%D0%BB%D0%B6%D0%BD%D0%B8%D0%BA%D0%BE%D0%B2_%D0%BF%D0%BE_%D0%BF%D1%80%D0%B8%D1%85%D0%BE%D0%B4%D1%83_%D0%BF%D0%BB%D0%B0%D1%82%D0%B5%D0%B6%D0%B0 Разграничение прав действий http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Разграничение прав действий ==<br /> <br /> Например:<br /> Хотим выделить действия &quot;Начисление по всем договорам по VPN&quot; и &quot;Начисление по одному договору VPN&quot;.<br /> Находим соответствующие запросы:<br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> contracts=26019&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> <br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> &lt;/pre&gt;<br /> В dialup.xml находим соответствующее действие:<br /> &lt;pre&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions&quot; title=&quot;Начисление&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> Параметр contract будет меняться поэтому используется REGEXP ( префикс R: )<br /> &lt;pre&gt;module=dialup;action=RecalculateSessions;contract=R:\d+&quot;&lt;/pre&gt;<br /> <br /> В результате имеем dialup.xml<br /> &lt;pre&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=dialup;action=RecalculateSessions;contracts=R:\d+&quot; title=&quot;Начисление по конкретному договору&quot;/&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions;&quot; title=&quot;Начисление по всем договорам&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> == Права доступа к выбранным параметрам объектов заданного типа ==<br /> <br /> Необходимо разграничить доступ к редактированию и удалению текстовых и списковых параметров объектов заданного типа (в нашем примере, &quot;ЛВС у клиента&quot;), а также к изменению справочников для этих списковых параметров.<br /> <br /> Запускаем клиент биллинга в отладочном режиме, открываем договор, пробуем создать объект типа &quot;ЛВС у клиента&quot; и пробуем редактировать его текстовые и списковые параметры, клонировать его, переместить в другой договор и удалить. Затем переходим в &quot;Справочники/Объекты/Значения списков&quot; и пробуем добавлять, редактировать, удалять значения необходимых списковых параметров.<br /> <br /> Из отладочного журнала клиента биллинга получаем соответствующие запросы:<br /> <br /> &lt;pre&gt;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=25&amp;action=ListParamValueGet&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;module=contract.object&amp;action=ObjectUpdate&amp;type=5&amp;cid=14458&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=26&amp;value=&amp;action=TextParamValueUpdate&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;title=123&amp;module=contract.object&amp;param_id=27&amp;action=ListValueUpdate&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=4050&amp;module=contract.object&amp;action=ListValueDelete&amp;<br /> &lt;/pre&gt;<br /> <br /> Вставляем свои действия в kernel.xml перед &quot;более общими&quot; действиями:<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;group title=&quot;Объекты&quot;&gt;<br /> &lt;action id=&quot;219&quot; mask=&quot;module=contract.object;action=ObjectTable&quot; title=&quot;Про<br /> смотр объектов договора&quot;/&gt;<br /> <br /> &lt;action id=&quot;220&quot; mask=&quot;module=contract.object;action=ObjectParamTable&quot; title<br /> =&quot;Просмотр значений параметров объекта&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=contract.object;action=ObjectUpdate;type=5&quot; title=&quot;Изменение периода и названия объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;221&quot; mask=&quot;module=contract.object;action=ObjectUpdate&quot; title=&quot;Изменение периода и названия объекта&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=contract.object;action=ObjectDelete;type=5&quot; title=&quot;Удаление объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;222&quot; mask=&quot;module=contract.object;action=ObjectDelete&quot; title=&quot;Удаление объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10002&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=26&quot; title=&quot;Изменение в объекте текстового параметра 'Имя сети (SSID)'&quot;/&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=28&quot; title=&quot;Изменение в объекте текстового параметра 'Ключ шифрации'&quot;/&gt;<br /> &lt;action id=&quot;10004&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=29&quot; title=&quot;Изменение в объекте текстового параметра 'Логин/пароль для управления устройством'&quot;/&gt;<br /> &lt;action id=&quot;10005&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=30&quot; title=&quot;Изменение в объекте текстового параметра 'Серийный номер'&quot;/&gt;<br /> &lt;action id=&quot;10006&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=31&quot; title=&quot;Изменение в объекте текстового параметра 'MAC-адрес'&quot;/&gt;<br /> &lt;action id=&quot;223&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate&quot; title=&quot;Изменение текстового параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;224&quot; mask=&quot;module=contract.object;action=DateParamValueUpdate&quot; title=&quot;Изменение дата параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;225&quot; mask=&quot;module=contract.object;action=AddressParamValueUpdate&quot; title=&quot;Изменение адресного параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;10007&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=24&quot; title=&quot;Изменение в объекте спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10008&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=25&quot; title=&quot;Изменение в объекте спискового параметра 'Тип подключения'&quot;/&gt;<br /> &lt;action id=&quot;10009&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=27&quot; title=&quot;Изменение в объекте спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;226&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate&quot; title=&quot;Изменение спискового параметра объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10010&quot; mask=&quot;module=contract.object;action=ObjectClone;type=5&quot; title=&quot;Клонирование объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;265&quot; mask=&quot;module=contract.object;action=ObjectClone&quot; title=&quot;Клонирование объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10011&quot; mask=&quot;module=contract.object;action=MoveObject;type=5&quot; title=&quot;Перемещение объекта 'ЛВС у клиента' в другой договор&quot;/&gt;<br /> &lt;action id=&quot;252&quot; mask=&quot;module=contract.object;action=MoveObject&quot; title=&quot;Перемещение объекта в другой договор&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;group title=&quot;Значения списковых параметров&quot;&gt;<br /> &lt;action id=&quot;238&quot; mask=&quot;module=contract.object;action=ListValueList&quot; title=&quot;Просмотр значений спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10012&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=24&quot; title=&quot;Удаление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10013&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=25&quot; title=&quot;Удаление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10014&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=27&quot; title=&quot;Удаление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;239&quot; mask=&quot;module=contract.object;action=ListValueDelete&quot; title=&quot;Удаление значения спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10015&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=24&quot; title=&quot;Обновление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10016&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=25&quot; title=&quot;Обновление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10017&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=27&quot; title=&quot;Обновление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;240&quot; mask=&quot;module=contract.object;action=ListValueUpdate&quot; title=&quot;Изменение значения спискового параметра&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> <br /> == Редактирование статического IP-адреса (фиксированного Framed-IP-Address) в модуле DialUp/VPN ==<br /> <br /> Для задания статического IP-адреса используется соответствующая вкладка в свойствах логина клиента. Попробуем зайти на эту вкладку и выполнить разные манипуляции с IP-адресом.<br /> После каждой манипуляции нужно нажимать на &quot;Ок&quot; как внизу самой вкладки &quot;IP-адрес&quot;, так и внизу родительской вкладки &quot;Логины&quot;, иначе изменения не сохраняются на сервере биллинга. Следует также заметить, что информация о каждой вкладке (&quot;Общие&quot;, &quot;IP-адрес&quot;, &quot;Атрибуты RADIUS&quot; и т.д.) будет сохраняться с помощью отдельного запроса к серверу биллинга.<br /> <br /> Нас интересуют только запросы, относящиеся к вкладке &quot;IP-адрес&quot;. Найдем их в отладочном журнале клиента:<br /> <br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.4%3Adefault%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.5%3Alocal%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> &lt;/pre&gt;<br /> <br /> Таким образом, любое изменение, в т.ч. и удаление статического IP-адреса, осуществляется с помощью действия IPAddressUpdate. Его и добавим в dialup.xml (к уже добавленным туда действиям по изменению RADIUS-атрибутов):<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;action id=&quot;24&quot; mask=&quot;module=dialup;action=UpdatePassword&quot; title=&quot;Изменение пароля логина&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo;rp_mode=1&quot; title=&quot;Установка режима RADIUS-атрибутов 'только локальный'&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo&quot; title=&quot;Изменение RADIUS атрибутов&quot;/&gt;<br /> &lt;action id=&quot;10002&quot; mask=&quot;module=dialup;action=IPAddressUpdate&quot; title=&quot;Изменение IP-адреса&quot;/&gt;<br /> &lt;action id=&quot;30&quot; mask=&quot;module=call;action=MoveLogin&quot; title=&quot;Перемещение логина в другой договор&quot;/&gt;<br /> &lt;action id=&quot;31&quot; mask=&quot;module=call;action=DeleteLogin&quot; title=&quot;Удаление логина&quot;/&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> == Разграничение прав генерации отчетов в модуле Reports ==<br /> {{Актуальность Версии|версия=5.1}}<br /> Для разграничения доступа генерации отчетов необходимо в файл '''./actions/reports.xml''' внести следующие изменения<br /> <br /> ''приведен уже готовый файл с разбивкой по отчетам основного модуля''<br /> <br /> &lt;pre&gt;<br /> &lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1251&quot;?&gt;<br /> &lt;actions&gt;<br /> &lt;group title=&quot;Администрирование&quot;&gt;<br /> &lt;group title=&quot;Конфигурация модуля&quot;&gt;<br /> &lt;action id=&quot;1&quot; mask=&quot;module=service;action=ModuleInfo&quot; title=&quot;Просмотр конфигураций&quot;/&gt;<br /> &lt;action id=&quot;2&quot; mask=&quot;module=service;action=GetModuleConfig&quot; title=&quot;Просмотр конфигурации&quot;/&gt;<br /> &lt;action id=&quot;3&quot; mask=&quot;module=service;action=UpdateModuleConfig&quot; title=&quot;Обновление конфигурации&quot;/&gt; <br /> &lt;action id=&quot;4&quot; mask=&quot;module=service;action=SetModuleConfig&quot; title=&quot;Установка конфигурации&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;group title=&quot;Отчеты&quot;&gt;<br /> &lt;action id=&quot;5&quot; mask=&quot;module=reports;report_id=kernel_contract_reward&quot; title=&quot;Агентский отчет&quot;/&gt;<br /> &lt;action id=&quot;6&quot; mask=&quot;module=reports;report_id=kernel_contract_account_detail&quot; title=&quot;Детализированный отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;7&quot; mask=&quot;module=reports;report_id=kernel_contract_tariff_account&quot; title=&quot;Наработка по тарифам&quot;/&gt;<br /> &lt;action id=&quot;8&quot; mask=&quot;module=reports;report_id=kernel_contract_contract&quot; title=&quot;Отчет по договорам&quot;/&gt;<br /> &lt;action id=&quot;9&quot; mask=&quot;module=reports;report_id=kernel_contract_account&quot; title=&quot;Отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;10&quot; mask=&quot;module=reports;report_id=kernel_contract_payment&quot; title=&quot;Отчет по платежам&quot;/&gt;<br /> &lt;action id=&quot;11&quot; mask=&quot;module=reports;report_id=kernel_contract_charge&quot; title=&quot;Отчет по расходам&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;action id=&quot;12&quot; mask=&quot;module=reports;action=Report&quot; title=&quot;Генерация отчета&quot;/&gt;<br /> &lt;/group&gt; <br /> &lt;/actions&gt;<br /> &lt;/pre&gt;<br /> ''Чтобы избежать перетирания файла при обновлении необходимо в этой же папке создать файл'' '''reports.xml.orig'''<br /> <br /> Выглядеть в администрировании это будет следующим образом &lt;br/&gt;<br /> [[Файл:Admreports.png]]<br /> <br /> Для добавления ограничения по другим отчетам необходимо добавлять строку<br /> &lt;pre&gt;<br /> &lt;action id=&quot;&lt;%порядковый_номер%&gt;&quot; mask=&quot;module=reports;report_id=%название_отчета%&quot; title=&quot;%имя_отображаемое_в_администрировании%&quot;/&gt;<br /> &lt;/pre&gt;<br /> ''название отчета можно взять из журнала запросов'' '''report_id =&gt; kernel_contract_charge'''</div> Thu, 17 Feb 2011 07:49:29 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 Разграничение прав действий http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Разграничение прав действий ==<br /> <br /> Например:<br /> Хотим выделить действия &quot;Начисление по всем договорам по VPN&quot; и &quot;Начисление по одному договору VPN&quot;.<br /> Находим соответствующие запросы:<br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> contracts=26019&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> <br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> &lt;/pre&gt;<br /> В dialup.xml находим соответствующее действие:<br /> &lt;pre&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions&quot; title=&quot;Начисление&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> Параметр contract будет меняться поэтому используется REGEXP ( префикс R: )<br /> &lt;pre&gt;module=dialup;action=RecalculateSessions;contract=R:\d+&quot;&lt;/pre&gt;<br /> <br /> В результате имеем dialup.xml<br /> &lt;pre&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=dialup;action=RecalculateSessions;contracts=R:\d+&quot; title=&quot;Начисление по конкретному договору&quot;/&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions;&quot; title=&quot;Начисление по всем договорам&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> == Права доступа к выбранным параметрам объектов заданного типа ==<br /> <br /> Необходимо разграничить доступ к редактированию и удалению текстовых и списковых параметров объектов заданного типа (в нашем примере, &quot;ЛВС у клиента&quot;), а также к изменению справочников для этих списковых параметров.<br /> <br /> Запускаем клиент биллинга в отладочном режиме, открываем договор, пробуем создать объект типа &quot;ЛВС у клиента&quot; и пробуем редактировать его текстовые и списковые параметры, клонировать его, переместить в другой договор и удалить. Затем переходим в &quot;Справочники/Объекты/Значения списков&quot; и пробуем добавлять, редактировать, удалять значения необходимых списковых параметров.<br /> <br /> Из отладочного журнала клиента биллинга получаем соответствующие запросы:<br /> <br /> &lt;pre&gt;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=25&amp;action=ListParamValueGet&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;module=contract.object&amp;action=ObjectUpdate&amp;type=5&amp;cid=14458&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=26&amp;value=&amp;action=TextParamValueUpdate&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;title=123&amp;module=contract.object&amp;param_id=27&amp;action=ListValueUpdate&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=4050&amp;module=contract.object&amp;action=ListValueDelete&amp;<br /> &lt;/pre&gt;<br /> <br /> Вставляем свои действия в kernel.xml перед &quot;более общими&quot; действиями:<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;group title=&quot;Объекты&quot;&gt;<br /> &lt;action id=&quot;219&quot; mask=&quot;module=contract.object;action=ObjectTable&quot; title=&quot;Про<br /> смотр объектов договора&quot;/&gt;<br /> <br /> &lt;action id=&quot;220&quot; mask=&quot;module=contract.object;action=ObjectParamTable&quot; title<br /> =&quot;Просмотр значений параметров объекта&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=contract.object;action=ObjectUpdate;type=5&quot; title=&quot;Изменение периода и названия объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;221&quot; mask=&quot;module=contract.object;action=ObjectUpdate&quot; title=&quot;Изменение периода и названия объекта&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=contract.object;action=ObjectDelete;type=5&quot; title=&quot;Удаление объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;222&quot; mask=&quot;module=contract.object;action=ObjectDelete&quot; title=&quot;Удаление объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10002&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=26&quot; title=&quot;Изменение в объекте текстового параметра 'Имя сети (SSID)'&quot;/&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=28&quot; title=&quot;Изменение в объекте текстового параметра 'Ключ шифрации'&quot;/&gt;<br /> &lt;action id=&quot;10004&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=29&quot; title=&quot;Изменение в объекте текстового параметра 'Логин/пароль для управления устройством'&quot;/&gt;<br /> &lt;action id=&quot;10005&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=30&quot; title=&quot;Изменение в объекте текстового параметра 'Серийный номер'&quot;/&gt;<br /> &lt;action id=&quot;10006&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=31&quot; title=&quot;Изменение в объекте текстового параметра 'MAC-адрес'&quot;/&gt;<br /> &lt;action id=&quot;223&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate&quot; title=&quot;Изменение текстового параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;224&quot; mask=&quot;module=contract.object;action=DateParamValueUpdate&quot; title=&quot;Изменение дата параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;225&quot; mask=&quot;module=contract.object;action=AddressParamValueUpdate&quot; title=&quot;Изменение адресного параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;10007&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=24&quot; title=&quot;Изменение в объекте спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10008&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=25&quot; title=&quot;Изменение в объекте спискового параметра 'Тип подключения'&quot;/&gt;<br /> &lt;action id=&quot;10009&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=27&quot; title=&quot;Изменение в объекте спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;226&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate&quot; title=&quot;Изменение спискового параметра объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10010&quot; mask=&quot;module=contract.object;action=ObjectClone;type=5&quot; title=&quot;Клонирование объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;265&quot; mask=&quot;module=contract.object;action=ObjectClone&quot; title=&quot;Клонирование объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10011&quot; mask=&quot;module=contract.object;action=MoveObject;type=5&quot; title=&quot;Перемещение объекта 'ЛВС у клиента' в другой договор&quot;/&gt;<br /> &lt;action id=&quot;252&quot; mask=&quot;module=contract.object;action=MoveObject&quot; title=&quot;Перемещение объекта в другой договор&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;group title=&quot;Значения списковых параметров&quot;&gt;<br /> &lt;action id=&quot;238&quot; mask=&quot;module=contract.object;action=ListValueList&quot; title=&quot;Просмотр значений спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10012&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=24&quot; title=&quot;Удаление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10013&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=25&quot; title=&quot;Удаление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10014&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=27&quot; title=&quot;Удаление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;239&quot; mask=&quot;module=contract.object;action=ListValueDelete&quot; title=&quot;Удаление значения спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10015&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=24&quot; title=&quot;Обновление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10016&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=25&quot; title=&quot;Обновление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10017&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=27&quot; title=&quot;Обновление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;240&quot; mask=&quot;module=contract.object;action=ListValueUpdate&quot; title=&quot;Изменение значения спискового параметра&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> <br /> == Редактирование статического IP-адреса (фиксированного Framed-IP-Address) в модуле DialUp/VPN ==<br /> <br /> Для задания статического IP-адреса используется соответствующая вкладка в свойствах логина клиента. Попробуем зайти на эту вкладку и выполнить разные манипуляции с IP-адресом.<br /> После каждой манипуляции нужно нажимать на &quot;Ок&quot; как внизу самой вкладки &quot;IP-адрес&quot;, так и внизу родительской вкладки &quot;Логины&quot;, иначе изменения не сохраняются на сервере биллинга. Следует также заметить, что информация о каждой вкладке (&quot;Общие&quot;, &quot;IP-адрес&quot;, &quot;Атрибуты RADIUS&quot; и т.д.) будет сохраняться с помощью отдельного запроса к серверу биллинга.<br /> <br /> Нас интересуют только запросы, относящиеся к вкладке &quot;IP-адрес&quot;. Найдем их в отладочном журнале клиента:<br /> <br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.4%3Adefault%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.5%3Alocal%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> &lt;/pre&gt;<br /> <br /> Таким образом, любое изменение, в т.ч. и удаление статического IP-адреса, осуществляется с помощью действия IPAddressUpdate. Его и добавим в dialup.xml (к уже добавленным туда действиям по изменению RADIUS-атрибутов):<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;action id=&quot;24&quot; mask=&quot;module=dialup;action=UpdatePassword&quot; title=&quot;Изменение пароля логина&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo;rp_mode=1&quot; title=&quot;Установка режима RADIUS-атрибутов 'только локальный'&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo&quot; title=&quot;Изменение RADIUS атрибутов&quot;/&gt;<br /> &lt;action id=&quot;10002&quot; mask=&quot;module=dialup;action=IPAddressUpdate&quot; title=&quot;Изменение IP-адреса&quot;/&gt;<br /> &lt;action id=&quot;30&quot; mask=&quot;module=call;action=MoveLogin&quot; title=&quot;Перемещение логина в другой договор&quot;/&gt;<br /> &lt;action id=&quot;31&quot; mask=&quot;module=call;action=DeleteLogin&quot; title=&quot;Удаление логина&quot;/&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> == Разграничение прав генерации отчетов в модуле Reports ==<br /> {{Актуальность Версии|версия=5.1}}<br /> Для разграничения доступа генерации отчетов необходимо в файл '''./actions/reports.xml''' внести следующие изменения<br /> <br /> ''приведен уже готовый файл с разбивкой по отчетам основного модуля''<br /> <br /> &lt;pre&gt;<br /> &lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1251&quot;?&gt;<br /> &lt;actions&gt;<br /> &lt;group title=&quot;Администрирование&quot;&gt;<br /> &lt;group title=&quot;Конфигурация модуля&quot;&gt;<br /> &lt;action id=&quot;1&quot; mask=&quot;module=service;action=ModuleInfo&quot; title=&quot;Просмотр конфигураций&quot;/&gt;<br /> &lt;action id=&quot;2&quot; mask=&quot;module=service;action=GetModuleConfig&quot; title=&quot;Просмотр конфигурации&quot;/&gt;<br /> &lt;action id=&quot;3&quot; mask=&quot;module=service;action=UpdateModuleConfig&quot; title=&quot;Обновление конфигурации&quot;/&gt; <br /> &lt;action id=&quot;4&quot; mask=&quot;module=service;action=SetModuleConfig&quot; title=&quot;Установка конфигурации&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;group title=&quot;Отчеты&quot;&gt;<br /> &lt;action id=&quot;5&quot; mask=&quot;module=reports;report_id=kernel_contract_reward&quot; title=&quot;Агентский отчет&quot;/&gt;<br /> &lt;action id=&quot;6&quot; mask=&quot;module=reports;report_id=kernel_contract_account_detail&quot; title=&quot;Детализированный отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;7&quot; mask=&quot;module=reports;report_id=kernel_contract_tariff_account&quot; title=&quot;Наработка по тарифам&quot;/&gt;<br /> &lt;action id=&quot;8&quot; mask=&quot;module=reports;report_id=kernel_contract_contract&quot; title=&quot;Отчет по договорам&quot;/&gt;<br /> &lt;action id=&quot;9&quot; mask=&quot;module=reports;report_id=kernel_contract_account&quot; title=&quot;Отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;10&quot; mask=&quot;module=reports;report_id=kernel_contract_payment&quot; title=&quot;Отчет по платежам&quot;/&gt;<br /> &lt;action id=&quot;11&quot; mask=&quot;module=reports;report_id=kernel_contract_charge&quot; title=&quot;Отчет по расходам&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;action id=&quot;12&quot; mask=&quot;module=reports;action=Report&quot; title=&quot;Генерация отчета&quot;/&gt;<br /> &lt;/group&gt; <br /> &lt;/actions&gt;<br /> &lt;/pre&gt;<br /> Выглядеть в администрировании это будет следующим образом &lt;br/&gt;<br /> [[Файл:Admreports.png]]<br /> <br /> Для добавления ограничения по другим отчетам необходимо добавлять строку<br /> &lt;pre&gt;<br /> &lt;action id=&quot;&lt;%порядковый_номер%&gt;&quot; mask=&quot;module=reports;report_id=%название_отчета%&quot; title=&quot;%имя_отображаемое_в_администрировании%&quot;/&gt;<br /> &lt;/pre&gt;<br /> ''название отчета можно взять из журнала запросов'' '''report_id =&gt; kernel_contract_charge'''</div> Thu, 17 Feb 2011 07:31:49 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 Разграничение прав действий http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Разграничение прав действий ==<br /> <br /> Например:<br /> Хотим выделить действия &quot;Начисление по всем договорам по VPN&quot; и &quot;Начисление по одному договору VPN&quot;.<br /> Находим соответствующие запросы:<br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> contracts=26019&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> <br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> &lt;/pre&gt;<br /> В dialup.xml находим соответствующее действие:<br /> &lt;pre&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions&quot; title=&quot;Начисление&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> Параметр contract будет меняться поэтому используется REGEXP ( префикс R: )<br /> &lt;pre&gt;module=dialup;action=RecalculateSessions;contract=R:\d+&quot;&lt;/pre&gt;<br /> <br /> В результате имеем dialup.xml<br /> &lt;pre&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=dialup;action=RecalculateSessions;contracts=R:\d+&quot; title=&quot;Начисление по конкретному договору&quot;/&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions;&quot; title=&quot;Начисление по всем договорам&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> == Права доступа к выбранным параметрам объектов заданного типа ==<br /> <br /> Необходимо разграничить доступ к редактированию и удалению текстовых и списковых параметров объектов заданного типа (в нашем примере, &quot;ЛВС у клиента&quot;), а также к изменению справочников для этих списковых параметров.<br /> <br /> Запускаем клиент биллинга в отладочном режиме, открываем договор, пробуем создать объект типа &quot;ЛВС у клиента&quot; и пробуем редактировать его текстовые и списковые параметры, клонировать его, переместить в другой договор и удалить. Затем переходим в &quot;Справочники/Объекты/Значения списков&quot; и пробуем добавлять, редактировать, удалять значения необходимых списковых параметров.<br /> <br /> Из отладочного журнала клиента биллинга получаем соответствующие запросы:<br /> <br /> &lt;pre&gt;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=25&amp;action=ListParamValueGet&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;module=contract.object&amp;action=ObjectUpdate&amp;type=5&amp;cid=14458&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=26&amp;value=&amp;action=TextParamValueUpdate&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;title=123&amp;module=contract.object&amp;param_id=27&amp;action=ListValueUpdate&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=4050&amp;module=contract.object&amp;action=ListValueDelete&amp;<br /> &lt;/pre&gt;<br /> <br /> Вставляем свои действия в kernel.xml перед &quot;более общими&quot; действиями:<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;group title=&quot;Объекты&quot;&gt;<br /> &lt;action id=&quot;219&quot; mask=&quot;module=contract.object;action=ObjectTable&quot; title=&quot;Про<br /> смотр объектов договора&quot;/&gt;<br /> <br /> &lt;action id=&quot;220&quot; mask=&quot;module=contract.object;action=ObjectParamTable&quot; title<br /> =&quot;Просмотр значений параметров объекта&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=contract.object;action=ObjectUpdate;type=5&quot; title=&quot;Изменение периода и названия объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;221&quot; mask=&quot;module=contract.object;action=ObjectUpdate&quot; title=&quot;Изменение периода и названия объекта&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=contract.object;action=ObjectDelete;type=5&quot; title=&quot;Удаление объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;222&quot; mask=&quot;module=contract.object;action=ObjectDelete&quot; title=&quot;Удаление объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10002&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=26&quot; title=&quot;Изменение в объекте текстового параметра 'Имя сети (SSID)'&quot;/&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=28&quot; title=&quot;Изменение в объекте текстового параметра 'Ключ шифрации'&quot;/&gt;<br /> &lt;action id=&quot;10004&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=29&quot; title=&quot;Изменение в объекте текстового параметра 'Логин/пароль для управления устройством'&quot;/&gt;<br /> &lt;action id=&quot;10005&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=30&quot; title=&quot;Изменение в объекте текстового параметра 'Серийный номер'&quot;/&gt;<br /> &lt;action id=&quot;10006&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=31&quot; title=&quot;Изменение в объекте текстового параметра 'MAC-адрес'&quot;/&gt;<br /> &lt;action id=&quot;223&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate&quot; title=&quot;Изменение текстового параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;224&quot; mask=&quot;module=contract.object;action=DateParamValueUpdate&quot; title=&quot;Изменение дата параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;225&quot; mask=&quot;module=contract.object;action=AddressParamValueUpdate&quot; title=&quot;Изменение адресного параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;10007&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=24&quot; title=&quot;Изменение в объекте спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10008&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=25&quot; title=&quot;Изменение в объекте спискового параметра 'Тип подключения'&quot;/&gt;<br /> &lt;action id=&quot;10009&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=27&quot; title=&quot;Изменение в объекте спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;226&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate&quot; title=&quot;Изменение спискового параметра объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10010&quot; mask=&quot;module=contract.object;action=ObjectClone;type=5&quot; title=&quot;Клонирование объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;265&quot; mask=&quot;module=contract.object;action=ObjectClone&quot; title=&quot;Клонирование объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10011&quot; mask=&quot;module=contract.object;action=MoveObject;type=5&quot; title=&quot;Перемещение объекта 'ЛВС у клиента' в другой договор&quot;/&gt;<br /> &lt;action id=&quot;252&quot; mask=&quot;module=contract.object;action=MoveObject&quot; title=&quot;Перемещение объекта в другой договор&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;group title=&quot;Значения списковых параметров&quot;&gt;<br /> &lt;action id=&quot;238&quot; mask=&quot;module=contract.object;action=ListValueList&quot; title=&quot;Просмотр значений спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10012&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=24&quot; title=&quot;Удаление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10013&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=25&quot; title=&quot;Удаление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10014&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=27&quot; title=&quot;Удаление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;239&quot; mask=&quot;module=contract.object;action=ListValueDelete&quot; title=&quot;Удаление значения спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10015&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=24&quot; title=&quot;Обновление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10016&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=25&quot; title=&quot;Обновление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10017&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=27&quot; title=&quot;Обновление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;240&quot; mask=&quot;module=contract.object;action=ListValueUpdate&quot; title=&quot;Изменение значения спискового параметра&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> <br /> == Редактирование статического IP-адреса (фиксированного Framed-IP-Address) в модуле DialUp/VPN ==<br /> <br /> Для задания статического IP-адреса используется соответствующая вкладка в свойствах логина клиента. Попробуем зайти на эту вкладку и выполнить разные манипуляции с IP-адресом.<br /> После каждой манипуляции нужно нажимать на &quot;Ок&quot; как внизу самой вкладки &quot;IP-адрес&quot;, так и внизу родительской вкладки &quot;Логины&quot;, иначе изменения не сохраняются на сервере биллинга. Следует также заметить, что информация о каждой вкладке (&quot;Общие&quot;, &quot;IP-адрес&quot;, &quot;Атрибуты RADIUS&quot; и т.д.) будет сохраняться с помощью отдельного запроса к серверу биллинга.<br /> <br /> Нас интересуют только запросы, относящиеся к вкладке &quot;IP-адрес&quot;. Найдем их в отладочном журнале клиента:<br /> <br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.4%3Adefault%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.5%3Alocal%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> &lt;/pre&gt;<br /> <br /> Таким образом, любое изменение, в т.ч. и удаление статического IP-адреса, осуществляется с помощью действия IPAddressUpdate. Его и добавим в dialup.xml (к уже добавленным туда действиям по изменению RADIUS-атрибутов):<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;action id=&quot;24&quot; mask=&quot;module=dialup;action=UpdatePassword&quot; title=&quot;Изменение пароля логина&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo;rp_mode=1&quot; title=&quot;Установка режима RADIUS-атрибутов 'только локальный'&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo&quot; title=&quot;Изменение RADIUS атрибутов&quot;/&gt;<br /> &lt;action id=&quot;10002&quot; mask=&quot;module=dialup;action=IPAddressUpdate&quot; title=&quot;Изменение IP-адреса&quot;/&gt;<br /> &lt;action id=&quot;30&quot; mask=&quot;module=call;action=MoveLogin&quot; title=&quot;Перемещение логина в другой договор&quot;/&gt;<br /> &lt;action id=&quot;31&quot; mask=&quot;module=call;action=DeleteLogin&quot; title=&quot;Удаление логина&quot;/&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> == Модуль Reports ==<br /> {{Актуальность Версии|версия=5.1}}<br /> Для разграничения доступа генерации отчетов необходимо в файл '''./actions/reports.xml''' внести следующие изменения<br /> <br /> ''приведен уже готовый файл с разбивкой по отчетам основного модуля''<br /> <br /> &lt;pre&gt;<br /> &lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1251&quot;?&gt;<br /> &lt;actions&gt;<br /> &lt;group title=&quot;Администрирование&quot;&gt;<br /> &lt;group title=&quot;Конфигурация модуля&quot;&gt;<br /> &lt;action id=&quot;1&quot; mask=&quot;module=service;action=ModuleInfo&quot; title=&quot;Просмотр конфигураций&quot;/&gt;<br /> &lt;action id=&quot;2&quot; mask=&quot;module=service;action=GetModuleConfig&quot; title=&quot;Просмотр конфигурации&quot;/&gt;<br /> &lt;action id=&quot;3&quot; mask=&quot;module=service;action=UpdateModuleConfig&quot; title=&quot;Обновление конфигурации&quot;/&gt; <br /> &lt;action id=&quot;4&quot; mask=&quot;module=service;action=SetModuleConfig&quot; title=&quot;Установка конфигурации&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;group title=&quot;Отчеты&quot;&gt;<br /> &lt;action id=&quot;5&quot; mask=&quot;module=reports;report_id=kernel_contract_reward&quot; title=&quot;Агентский отчет&quot;/&gt;<br /> &lt;action id=&quot;6&quot; mask=&quot;module=reports;report_id=kernel_contract_account_detail&quot; title=&quot;Детализированный отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;7&quot; mask=&quot;module=reports;report_id=kernel_contract_tariff_account&quot; title=&quot;Наработка по тарифам&quot;/&gt;<br /> &lt;action id=&quot;8&quot; mask=&quot;module=reports;report_id=kernel_contract_contract&quot; title=&quot;Отчет по договорам&quot;/&gt;<br /> &lt;action id=&quot;9&quot; mask=&quot;module=reports;report_id=kernel_contract_account&quot; title=&quot;Отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;10&quot; mask=&quot;module=reports;report_id=kernel_contract_payment&quot; title=&quot;Отчет по платежам&quot;/&gt;<br /> &lt;action id=&quot;11&quot; mask=&quot;module=reports;report_id=kernel_contract_charge&quot; title=&quot;Отчет по расходам&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;action id=&quot;12&quot; mask=&quot;module=reports;action=Report&quot; title=&quot;Генерация отчета&quot;/&gt;<br /> &lt;/group&gt; <br /> &lt;/actions&gt;<br /> &lt;/pre&gt;<br /> Выглядеть в администрировании это будет следующим образом &lt;br/&gt;<br /> [[Файл:Admreports.png]]<br /> <br /> Для добавления ограничения по другим отчетам необходимо добавлять строку<br /> &lt;pre&gt;<br /> &lt;action id=&quot;&lt;%порядковый_номер%&gt;&quot; mask=&quot;module=reports;report_id=%название_отчета%&quot; title=&quot;%имя_отображаемое_в_администрировании%&quot;/&gt;<br /> &lt;/pre&gt;<br /> ''название отчета можно взять из журнала запросов'' '''report_id =&gt; kernel_contract_charge'''</div> Thu, 17 Feb 2011 07:12:05 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 Разграничение прав действий http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Разграничение прав действий ==<br /> <br /> Например:<br /> Хотим выделить действия &quot;Начисление по всем договорам по VPN&quot; и &quot;Начисление по одному договору VPN&quot;.<br /> Находим соответствующие запросы:<br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> contracts=26019&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> <br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> &lt;/pre&gt;<br /> В dialup.xml находим соответствующее действие:<br /> &lt;pre&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions&quot; title=&quot;Начисление&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> Параметр contract будет меняться поэтому используется REGEXP ( префикс R: )<br /> &lt;pre&gt;module=dialup;action=RecalculateSessions;contract=R:\d+&quot;&lt;/pre&gt;<br /> <br /> В результате имеем dialup.xml<br /> &lt;pre&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=dialup;action=RecalculateSessions;contracts=R:\d+&quot; title=&quot;Начисление по конкретному договору&quot;/&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions;&quot; title=&quot;Начисление по всем договорам&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> == Права доступа к выбранным параметрам объектов заданного типа ==<br /> <br /> Необходимо разграничить доступ к редактированию и удалению текстовых и списковых параметров объектов заданного типа (в нашем примере, &quot;ЛВС у клиента&quot;), а также к изменению справочников для этих списковых параметров.<br /> <br /> Запускаем клиент биллинга в отладочном режиме, открываем договор, пробуем создать объект типа &quot;ЛВС у клиента&quot; и пробуем редактировать его текстовые и списковые параметры, клонировать его, переместить в другой договор и удалить. Затем переходим в &quot;Справочники/Объекты/Значения списков&quot; и пробуем добавлять, редактировать, удалять значения необходимых списковых параметров.<br /> <br /> Из отладочного журнала клиента биллинга получаем соответствующие запросы:<br /> <br /> &lt;pre&gt;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=25&amp;action=ListParamValueGet&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;module=contract.object&amp;action=ObjectUpdate&amp;type=5&amp;cid=14458&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=26&amp;value=&amp;action=TextParamValueUpdate&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;title=123&amp;module=contract.object&amp;param_id=27&amp;action=ListValueUpdate&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=4050&amp;module=contract.object&amp;action=ListValueDelete&amp;<br /> &lt;/pre&gt;<br /> <br /> Вставляем свои действия в kernel.xml перед &quot;более общими&quot; действиями:<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;group title=&quot;Объекты&quot;&gt;<br /> &lt;action id=&quot;219&quot; mask=&quot;module=contract.object;action=ObjectTable&quot; title=&quot;Про<br /> смотр объектов договора&quot;/&gt;<br /> <br /> &lt;action id=&quot;220&quot; mask=&quot;module=contract.object;action=ObjectParamTable&quot; title<br /> =&quot;Просмотр значений параметров объекта&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=contract.object;action=ObjectUpdate;type=5&quot; title=&quot;Изменение периода и названия объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;221&quot; mask=&quot;module=contract.object;action=ObjectUpdate&quot; title=&quot;Изменение периода и названия объекта&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=contract.object;action=ObjectDelete;type=5&quot; title=&quot;Удаление объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;222&quot; mask=&quot;module=contract.object;action=ObjectDelete&quot; title=&quot;Удаление объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10002&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=26&quot; title=&quot;Изменение в объекте текстового параметра 'Имя сети (SSID)'&quot;/&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=28&quot; title=&quot;Изменение в объекте текстового параметра 'Ключ шифрации'&quot;/&gt;<br /> &lt;action id=&quot;10004&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=29&quot; title=&quot;Изменение в объекте текстового параметра 'Логин/пароль для управления устройством'&quot;/&gt;<br /> &lt;action id=&quot;10005&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=30&quot; title=&quot;Изменение в объекте текстового параметра 'Серийный номер'&quot;/&gt;<br /> &lt;action id=&quot;10006&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=31&quot; title=&quot;Изменение в объекте текстового параметра 'MAC-адрес'&quot;/&gt;<br /> &lt;action id=&quot;223&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate&quot; title=&quot;Изменение текстового параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;224&quot; mask=&quot;module=contract.object;action=DateParamValueUpdate&quot; title=&quot;Изменение дата параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;225&quot; mask=&quot;module=contract.object;action=AddressParamValueUpdate&quot; title=&quot;Изменение адресного параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;10007&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=24&quot; title=&quot;Изменение в объекте спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10008&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=25&quot; title=&quot;Изменение в объекте спискового параметра 'Тип подключения'&quot;/&gt;<br /> &lt;action id=&quot;10009&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=27&quot; title=&quot;Изменение в объекте спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;226&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate&quot; title=&quot;Изменение спискового параметра объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10010&quot; mask=&quot;module=contract.object;action=ObjectClone;type=5&quot; title=&quot;Клонирование объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;265&quot; mask=&quot;module=contract.object;action=ObjectClone&quot; title=&quot;Клонирование объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10011&quot; mask=&quot;module=contract.object;action=MoveObject;type=5&quot; title=&quot;Перемещение объекта 'ЛВС у клиента' в другой договор&quot;/&gt;<br /> &lt;action id=&quot;252&quot; mask=&quot;module=contract.object;action=MoveObject&quot; title=&quot;Перемещение объекта в другой договор&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;group title=&quot;Значения списковых параметров&quot;&gt;<br /> &lt;action id=&quot;238&quot; mask=&quot;module=contract.object;action=ListValueList&quot; title=&quot;Просмотр значений спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10012&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=24&quot; title=&quot;Удаление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10013&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=25&quot; title=&quot;Удаление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10014&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=27&quot; title=&quot;Удаление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;239&quot; mask=&quot;module=contract.object;action=ListValueDelete&quot; title=&quot;Удаление значения спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10015&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=24&quot; title=&quot;Обновление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10016&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=25&quot; title=&quot;Обновление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10017&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=27&quot; title=&quot;Обновление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;240&quot; mask=&quot;module=contract.object;action=ListValueUpdate&quot; title=&quot;Изменение значения спискового параметра&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> <br /> == Редактирование статического IP-адреса (фиксированного Framed-IP-Address) в модуле DialUp/VPN ==<br /> <br /> Для задания статического IP-адреса используется соответствующая вкладка в свойствах логина клиента. Попробуем зайти на эту вкладку и выполнить разные манипуляции с IP-адресом.<br /> После каждой манипуляции нужно нажимать на &quot;Ок&quot; как внизу самой вкладки &quot;IP-адрес&quot;, так и внизу родительской вкладки &quot;Логины&quot;, иначе изменения не сохраняются на сервере биллинга. Следует также заметить, что информация о каждой вкладке (&quot;Общие&quot;, &quot;IP-адрес&quot;, &quot;Атрибуты RADIUS&quot; и т.д.) будет сохраняться с помощью отдельного запроса к серверу биллинга.<br /> <br /> Нас интересуют только запросы, относящиеся к вкладке &quot;IP-адрес&quot;. Найдем их в отладочном журнале клиента:<br /> <br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.4%3Adefault%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.5%3Alocal%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> &lt;/pre&gt;<br /> <br /> Таким образом, любое изменение, в т.ч. и удаление статического IP-адреса, осуществляется с помощью действия IPAddressUpdate. Его и добавим в dialup.xml (к уже добавленным туда действиям по изменению RADIUS-атрибутов):<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;action id=&quot;24&quot; mask=&quot;module=dialup;action=UpdatePassword&quot; title=&quot;Изменение пароля логина&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo;rp_mode=1&quot; title=&quot;Установка режима RADIUS-атрибутов 'только локальный'&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo&quot; title=&quot;Изменение RADIUS атрибутов&quot;/&gt;<br /> &lt;action id=&quot;10002&quot; mask=&quot;module=dialup;action=IPAddressUpdate&quot; title=&quot;Изменение IP-адреса&quot;/&gt;<br /> &lt;action id=&quot;30&quot; mask=&quot;module=call;action=MoveLogin&quot; title=&quot;Перемещение логина в другой договор&quot;/&gt;<br /> &lt;action id=&quot;31&quot; mask=&quot;module=call;action=DeleteLogin&quot; title=&quot;Удаление логина&quot;/&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> == Модуль Reports ==<br /> {{Актуальность Версии|версия=5.1}}<br /> Для разграничения доступа генерации отчетов необходимо в файл '''./actions/reports.xml''' внести следующие изменения<br /> <br /> ''приведен уже готовый файл с разбивкой по отчетам основного модуля''<br /> <br /> &lt;pre&gt;<br /> &lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1251&quot;?&gt;<br /> &lt;actions&gt;<br /> &lt;group title=&quot;Администрирование&quot;&gt;<br /> &lt;group title=&quot;Конфигурация модуля&quot;&gt;<br /> &lt;action id=&quot;1&quot; mask=&quot;module=service;action=ModuleInfo&quot; title=&quot;Просмотр конфигураций&quot;/&gt;<br /> &lt;action id=&quot;2&quot; mask=&quot;module=service;action=GetModuleConfig&quot; title=&quot;Просмотр конфигурации&quot;/&gt;<br /> &lt;action id=&quot;3&quot; mask=&quot;module=service;action=UpdateModuleConfig&quot; title=&quot;Обновление конфигурации&quot;/&gt; <br /> &lt;action id=&quot;4&quot; mask=&quot;module=service;action=SetModuleConfig&quot; title=&quot;Установка конфигурации&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;group title=&quot;Отчеты&quot;&gt;<br /> &lt;action id=&quot;5&quot; mask=&quot;module=reports;report_id=kernel_contract_reward&quot; title=&quot;Агентский отчет&quot;/&gt;<br /> &lt;action id=&quot;6&quot; mask=&quot;module=reports;report_id=kernel_contract_account_detail&quot; title=&quot;Детализированный отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;7&quot; mask=&quot;module=reports;report_id=kernel_contract_tariff_account&quot; title=&quot;Наработка по тарифам&quot;/&gt;<br /> &lt;action id=&quot;8&quot; mask=&quot;module=reports;report_id=kernel_contract_contract&quot; title=&quot;Отчет по договорам&quot;/&gt;<br /> &lt;action id=&quot;9&quot; mask=&quot;module=reports;report_id=kernel_contract_account&quot; title=&quot;Отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;10&quot; mask=&quot;module=reports;report_id=kernel_contract_payment&quot; title=&quot;Отчет по платежам&quot;/&gt;<br /> &lt;action id=&quot;11&quot; mask=&quot;module=reports;report_id=kernel_contract_charge&quot; title=&quot;Отчет по расходам&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;action id=&quot;12&quot; mask=&quot;module=reports;action=Report&quot; title=&quot;Генерация отчета&quot;/&gt;<br /> &lt;/group&gt; <br /> &lt;/actions&gt;<br /> &lt;/pre&gt;<br /> Выглядеть в администрировании это будет следующим образом &lt;br/&gt;<br /> [[Файл:Admreports.png]]</div> Thu, 17 Feb 2011 07:06:37 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 Разграничение прав действий http://wiki.bitel.ru/index.php/%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 <p>SinTeZWh1te:&#32;</p> <hr /> <div>== Разграничение прав действий ==<br /> <br /> Например:<br /> Хотим выделить действия &quot;Начисление по всем договорам по VPN&quot; и &quot;Начисление по одному договору VPN&quot;.<br /> Находим соответствующие запросы:<br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> contracts=26019&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> <br /> http://192.168.169.3:8080/bgbilling/executer?<br /> mail=bakirov_t%40ufanet.ru&amp;<br /> module=dialup&amp;<br /> action=RecalculateSessions&amp;<br /> date2=30.04.2008&amp;<br /> mid=16&amp;<br /> groups=0&amp;<br /> date1=01.04.2008&amp;<br /> &lt;/pre&gt;<br /> В dialup.xml находим соответствующее действие:<br /> &lt;pre&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions&quot; title=&quot;Начисление&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> Параметр contract будет меняться поэтому используется REGEXP ( префикс R: )<br /> &lt;pre&gt;module=dialup;action=RecalculateSessions;contract=R:\d+&quot;&lt;/pre&gt;<br /> <br /> В результате имеем dialup.xml<br /> &lt;pre&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=dialup;action=RecalculateSessions;contracts=R:\d+&quot; title=&quot;Начисление по конкретному договору&quot;/&gt;<br /> &lt;action id=&quot;27&quot; mask=&quot;module=dialup;action=RecalculateSessions;&quot; title=&quot;Начисление по всем договорам&quot;/&gt;<br /> &lt;/pre&gt;<br /> <br /> == Права доступа к выбранным параметрам объектов заданного типа ==<br /> <br /> Необходимо разграничить доступ к редактированию и удалению текстовых и списковых параметров объектов заданного типа (в нашем примере, &quot;ЛВС у клиента&quot;), а также к изменению справочников для этих списковых параметров.<br /> <br /> Запускаем клиент биллинга в отладочном режиме, открываем договор, пробуем создать объект типа &quot;ЛВС у клиента&quot; и пробуем редактировать его текстовые и списковые параметры, клонировать его, переместить в другой договор и удалить. Затем переходим в &quot;Справочники/Объекты/Значения списков&quot; и пробуем добавлять, редактировать, удалять значения необходимых списковых параметров.<br /> <br /> Из отладочного журнала клиента биллинга получаем соответствующие запросы:<br /> <br /> &lt;pre&gt;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=25&amp;action=ListParamValueGet&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;module=contract.object&amp;action=ObjectUpdate&amp;type=5&amp;cid=14458&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?module=contract.object&amp;param=26&amp;value=&amp;action=TextParamValueUpdate&amp;object=113671&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=0&amp;title=123&amp;module=contract.object&amp;param_id=27&amp;action=ListValueUpdate&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?id=4050&amp;module=contract.object&amp;action=ListValueDelete&amp;<br /> &lt;/pre&gt;<br /> <br /> Вставляем свои действия в kernel.xml перед &quot;более общими&quot; действиями:<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;group title=&quot;Объекты&quot;&gt;<br /> &lt;action id=&quot;219&quot; mask=&quot;module=contract.object;action=ObjectTable&quot; title=&quot;Про<br /> смотр объектов договора&quot;/&gt;<br /> <br /> &lt;action id=&quot;220&quot; mask=&quot;module=contract.object;action=ObjectParamTable&quot; title<br /> =&quot;Просмотр значений параметров объекта&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=contract.object;action=ObjectUpdate;type=5&quot; title=&quot;Изменение периода и названия объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;221&quot; mask=&quot;module=contract.object;action=ObjectUpdate&quot; title=&quot;Изменение периода и названия объекта&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=contract.object;action=ObjectDelete;type=5&quot; title=&quot;Удаление объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;222&quot; mask=&quot;module=contract.object;action=ObjectDelete&quot; title=&quot;Удаление объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10002&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=26&quot; title=&quot;Изменение в объекте текстового параметра 'Имя сети (SSID)'&quot;/&gt;<br /> &lt;action id=&quot;10003&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=28&quot; title=&quot;Изменение в объекте текстового параметра 'Ключ шифрации'&quot;/&gt;<br /> &lt;action id=&quot;10004&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=29&quot; title=&quot;Изменение в объекте текстового параметра 'Логин/пароль для управления устройством'&quot;/&gt;<br /> &lt;action id=&quot;10005&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=30&quot; title=&quot;Изменение в объекте текстового параметра 'Серийный номер'&quot;/&gt;<br /> &lt;action id=&quot;10006&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate;param=31&quot; title=&quot;Изменение в объекте текстового параметра 'MAC-адрес'&quot;/&gt;<br /> &lt;action id=&quot;223&quot; mask=&quot;module=contract.object;action=TextParamValueUpdate&quot; title=&quot;Изменение текстового параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;224&quot; mask=&quot;module=contract.object;action=DateParamValueUpdate&quot; title=&quot;Изменение дата параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;225&quot; mask=&quot;module=contract.object;action=AddressParamValueUpdate&quot; title=&quot;Изменение адресного параметра объекта&quot;/&gt;<br /> &lt;action id=&quot;10007&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=24&quot; title=&quot;Изменение в объекте спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10008&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=25&quot; title=&quot;Изменение в объекте спискового параметра 'Тип подключения'&quot;/&gt;<br /> &lt;action id=&quot;10009&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate;param=27&quot; title=&quot;Изменение в объекте спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;226&quot; mask=&quot;module=contract.object;action=ListParamValueUpdate&quot; title=&quot;Изменение спискового параметра объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10010&quot; mask=&quot;module=contract.object;action=ObjectClone;type=5&quot; title=&quot;Клонирование объекта 'ЛВС у клиента'&quot;/&gt;<br /> &lt;action id=&quot;265&quot; mask=&quot;module=contract.object;action=ObjectClone&quot; title=&quot;Клонирование объекта&quot;/&gt;<br /> <br /> &lt;action id=&quot;10011&quot; mask=&quot;module=contract.object;action=MoveObject;type=5&quot; title=&quot;Перемещение объекта 'ЛВС у клиента' в другой договор&quot;/&gt;<br /> &lt;action id=&quot;252&quot; mask=&quot;module=contract.object;action=MoveObject&quot; title=&quot;Перемещение объекта в другой договор&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;group title=&quot;Значения списковых параметров&quot;&gt;<br /> &lt;action id=&quot;238&quot; mask=&quot;module=contract.object;action=ListValueList&quot; title=&quot;Просмотр значений спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10012&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=24&quot; title=&quot;Удаление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10013&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=25&quot; title=&quot;Удаление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10014&quot; mask=&quot;module=contract.object;action=ListValueDelete;param_id=27&quot; title=&quot;Удаление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;239&quot; mask=&quot;module=contract.object;action=ListValueDelete&quot; title=&quot;Удаление значения спискового параметра&quot;/&gt;<br /> &lt;action id=&quot;10015&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=24&quot; title=&quot;Обновление значения спискового параметра 'Модель устройства'&quot;/&gt;<br /> &lt;action id=&quot;10016&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=25&quot; title=&quot;Обновление значения спискового параметра 'Тип подключения (ЛВС у клиента)'&quot;/&gt;<br /> &lt;action id=&quot;10017&quot; mask=&quot;module=contract.object;action=ListValueUpdate;param_id=27&quot; title=&quot;Обновление значения спискового параметра 'Тип шифрации'&quot;/&gt;<br /> &lt;action id=&quot;240&quot; mask=&quot;module=contract.object;action=ListValueUpdate&quot; title=&quot;Изменение значения спискового параметра&quot;/&gt;<br /> &lt;/group&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> <br /> == Редактирование статического IP-адреса (фиксированного Framed-IP-Address) в модуле DialUp/VPN ==<br /> <br /> Для задания статического IP-адреса используется соответствующая вкладка в свойствах логина клиента. Попробуем зайти на эту вкладку и выполнить разные манипуляции с IP-адресом.<br /> После каждой манипуляции нужно нажимать на &quot;Ок&quot; как внизу самой вкладки &quot;IP-адрес&quot;, так и внизу родительской вкладки &quot;Логины&quot;, иначе изменения не сохраняются на сервере биллинга. Следует также заметить, что информация о каждой вкладке (&quot;Общие&quot;, &quot;IP-адрес&quot;, &quot;Атрибуты RADIUS&quot; и т.д.) будет сохраняться с помощью отдельного запроса к серверу биллинга.<br /> <br /> Нас интересуют только запросы, относящиеся к вкладке &quot;IP-адрес&quot;. Найдем их в отладочном журнале клиента:<br /> <br /> &lt;pre&gt;<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.4%3Adefault%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=1.2.3.5%3Alocal%3A16.05.2008-&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> ...<br /> http://192.168.169.3:8080/bgbilling/executer?lid=129878&amp;module=dialup&amp;values=&amp;action=IPAddressUpdate&amp;mid=16&amp;<br /> &lt;/pre&gt;<br /> <br /> Таким образом, любое изменение, в т.ч. и удаление статического IP-адреса, осуществляется с помощью действия IPAddressUpdate. Его и добавим в dialup.xml (к уже добавленным туда действиям по изменению RADIUS-атрибутов):<br /> <br /> &lt;pre&gt;<br /> ...<br /> &lt;action id=&quot;24&quot; mask=&quot;module=dialup;action=UpdatePassword&quot; title=&quot;Изменение пароля логина&quot;/&gt;<br /> &lt;action id=&quot;10000&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo;rp_mode=1&quot; title=&quot;Установка режима RADIUS-атрибутов 'только локальный'&quot;/&gt;<br /> &lt;action id=&quot;10001&quot; mask=&quot;module=dialup;action=UpdateRadiusInfo&quot; title=&quot;Изменение RADIUS атрибутов&quot;/&gt;<br /> &lt;action id=&quot;10002&quot; mask=&quot;module=dialup;action=IPAddressUpdate&quot; title=&quot;Изменение IP-адреса&quot;/&gt;<br /> &lt;action id=&quot;30&quot; mask=&quot;module=call;action=MoveLogin&quot; title=&quot;Перемещение логина в другой договор&quot;/&gt;<br /> &lt;action id=&quot;31&quot; mask=&quot;module=call;action=DeleteLogin&quot; title=&quot;Удаление логина&quot;/&gt;<br /> ...<br /> &lt;/pre&gt;<br /> <br /> == Модуль Reports ==<br /> {{Актуальность Версии|версия=5.1}}<br /> Для разграничения доступа для генерации отчетов необходимо в файл '''./actions/reports.xml''' внести следующие изменения<br /> <br /> ''приведен уже готовый файл с разбивкой по отчетам основного модуля''<br /> <br /> &lt;pre&gt;<br /> &lt;?xml version=&quot;1.0&quot; encoding=&quot;windows-1251&quot;?&gt;<br /> &lt;actions&gt;<br /> &lt;group title=&quot;Администрирование&quot;&gt;<br /> &lt;group title=&quot;Конфигурация модуля&quot;&gt;<br /> &lt;action id=&quot;1&quot; mask=&quot;module=service;action=ModuleInfo&quot; title=&quot;Просмотр конфигураций&quot;/&gt;<br /> &lt;action id=&quot;2&quot; mask=&quot;module=service;action=GetModuleConfig&quot; title=&quot;Просмотр конфигурации&quot;/&gt;<br /> &lt;action id=&quot;3&quot; mask=&quot;module=service;action=UpdateModuleConfig&quot; title=&quot;Обновление конфигурации&quot;/&gt; <br /> &lt;action id=&quot;4&quot; mask=&quot;module=service;action=SetModuleConfig&quot; title=&quot;Установка конфигурации&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;group title=&quot;Отчеты&quot;&gt;<br /> &lt;action id=&quot;5&quot; mask=&quot;module=reports;report_id=kernel_contract_reward&quot; title=&quot;Агентский отчет&quot;/&gt;<br /> &lt;action id=&quot;6&quot; mask=&quot;module=reports;report_id=kernel_contract_account_detail&quot; title=&quot;Детализированный отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;7&quot; mask=&quot;module=reports;report_id=kernel_contract_tariff_account&quot; title=&quot;Наработка по тарифам&quot;/&gt;<br /> &lt;action id=&quot;8&quot; mask=&quot;module=reports;report_id=kernel_contract_contract&quot; title=&quot;Отчет по договорам&quot;/&gt;<br /> &lt;action id=&quot;9&quot; mask=&quot;module=reports;report_id=kernel_contract_account&quot; title=&quot;Отчет по наработке&quot;/&gt;<br /> &lt;action id=&quot;10&quot; mask=&quot;module=reports;report_id=kernel_contract_payment&quot; title=&quot;Отчет по платежам&quot;/&gt;<br /> &lt;action id=&quot;11&quot; mask=&quot;module=reports;report_id=kernel_contract_charge&quot; title=&quot;Отчет по расходам&quot;/&gt;<br /> &lt;/group&gt;<br /> &lt;action id=&quot;12&quot; mask=&quot;module=reports;action=Report&quot; title=&quot;Генерация отчета&quot;/&gt;<br /> &lt;/group&gt; <br /> &lt;/actions&gt;<br /> &lt;/pre&gt;<br /> Выглядеть в администрировании это будет следующим образом &lt;br/&gt;<br /> [[Файл:Admreports.png]]</div> Thu, 17 Feb 2011 07:03:26 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%A0%D0%B0%D0%B7%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%B0%D0%B2_%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9 Файл:Admreports.png http://wiki.bitel.ru/index.php/%D0%A4%D0%B0%D0%B9%D0%BB:Admreports.png <p>SinTeZWh1te:&#32;Администрирование. Модуль отчетов</p> <hr /> <div>Администрирование. Модуль отчетов</div> Thu, 17 Feb 2011 06:57:34 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D1%84%D0%B0%D0%B9%D0%BB%D0%B0:Admreports.png Эффективная настройка MySQL http://wiki.bitel.ru/index.php/%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F_%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0_MySQL <p>SinTeZWh1te:&#32;</p> <hr /> <div>Пример работающей оптимизированной конфигурации MySQL сервера с поддержкой только MyIsam таблиц.<br /> <br /> &lt;pre&gt;<br /> [mysqld]<br /> max_allowed_packet=50M<br /> datadir=/var/lib/mysql<br /> socket=/var/lib/mysql/mysql.sock<br /> tmpdir = /storage/mysql-tmp<br /> # Default to using old password format for compatibility with mysql 3.x<br /> # clients (those using the mysqlclient10 compatibility package).<br /> old_passwords=1<br /> <br /> # modified parameters<br /> max_connections=1000<br /> table_cache=2048<br /> sort_buffer_size=8M<br /> join_buffer_size=8M<br /> thread_cache_size=40<br /> thread_concurrency=2<br /> query_cache_size = 64M<br /> query_cache_limit = 2M<br /> query_cache_type = 1<br /> memlock<br /> tmp_table_size = 64M<br /> key_buffer_size = 200M<br /> wait_timeout = 28800<br /> <br /> # log slow queries<br /> log-slow-queries=/var/log/slowquery.log<br /> <br /> # myisam<br /> read_buffer_size = 2M<br /> read_rnd_buffer_size = 16M<br /> bulk_insert_buffer_size = 64M<br /> myisam_sort_buffer_size = 256M<br /> myisam_max_sort_file_size = 10G<br /> myisam_max_extra_sort_file_size = 10G<br /> myisam_repair_threads = 1<br /> myisam_recover<br /> myisam_data_pointer_size = 6<br /> <br /> # bdb<br /> skip-bdb<br /> # innodb<br /> skip-innodb<br /> <br /> # misc<br /> default-character-set=cp1251<br /> default-collation=cp1251_general_ci<br /> <br /> [mysql.server]<br /> user=mysql<br /> basedir=/var/lib<br /> <br /> [mysqld_safe]<br /> log-error=/var/log/mysqld.log<br /> pid-file=/var/run/mysqld/mysqld.pid<br /> open-files-limit=32000<br /> <br /> [client]<br /> default-character-set=cp1251<br /> &lt;/pre&gt;<br /> <br /> <br /> Иногда при этой конфигурации MySQL может выдавать ошибку типа <br /> &lt;pre&gt;<br /> Can't create/write to file '/tmp/mysql-tmp/MYle0eKC' (Errcode: 13)<br /> &lt;/pre&gt;<br /> В этом случае необходимо<br /> &lt;pre&gt;<br /> chown mysql:mysql /tmp/mysql-tmp<br /> chmod 1777 /tmp/mysql-tmp<br /> &lt;/pre&gt;<br /> хотя скорее всего подойдут и просто права 777 на /tmp от рута</div> Sat, 30 Oct 2010 10:01:43 GMT SinTeZWh1te http://wiki.bitel.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%AD%D1%84%D1%84%D0%B5%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F_%D0%BD%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0_MySQL