forum.bitel.ru http://forum.bitel.ru/ |
|
Всё о новых статусах договоров (и о перетирании) http://forum.bitel.ru/viewtopic.php?f=22&t=4544 |
Страница 1 из 1 |
Автор: | dimOn [ 13 сен 2010, 15:08 ] |
Заголовок сообщения: | Всё о новых статусах договоров (и о перетирании) |
Сделан новый алгоритм смены статусов. Есть возможность задавать приоритет у статуса, чтобы некоторые статусы не перетирались. Сейчас выложу два кусочка документации. |
Автор: | dimOn [ 13 сен 2010, 15:10 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Смена статусов в случае использования приоритетов статусов и неперекрывающихся статусов Ахтунг! Сейчас уже неактуально! Имеется возможность усложнить логику автоматического перетирания статусов путём установки для каждого статуса некоего приоритета. Сделать это можно для трёх отдельных случаев: 1) для случая смены статуса руками из клиента, 2) для случая смены статуса сервером, 3) для случая смены статуса пользователем из web (речь о возможности приостановить договор). Статусы устанавливаются именно на каждый из шести статусов, а не на каждый временной промежуток каждого договора. Возможность включается прописываением в конфигурации сервера нескольких параметров. Код: # # Приоритеты статусов для смены статусов бОльшая цифра - бОльший приоритет. Статус с меньшим приоритетом не перетирает статус с бОльшим. С одинаковыми - перетираются. # Шесть цифр подряд, через запятую, соотвественно для статусов: #CONTRACT_STATUS_ACTIVE = 0 #CONTRACT_STATUS_IN_DISCONNECT = 1 #CONTRACT_STATUS_DISCONNECTED = 2 #CONTRACT_STATUS_CLOSED = 3 #CONTRACT_STATUS_SUSPENDED = 4 #CONTRACT_STATUS_IN_CONNECT = 5 # по умолчанию все нули, т.е. все приоритетные одинаково, всё работает как было - все всех перетирают. # для смены вручную менеджером contract.status.user.priority=0,0,0,0,1,0 # для автоматической смены сервером contract.status.server.priority=0,0,0,0,1,0 # для смены юзером через web contract.status.web.priority=0,0,0,0,1,0 # Без каких-либо параметров (всех трёх или каждого по-отдельности) все приоритеты считаются равными 0, то есть поведение будет как описано в оригинальной документации - все друг друга перетирают. После настройки этих параметров статусы будут перетираться избирательно. Кроме того, усложняется логика событий и скриптов. В случае наличия неперекрывающихся статусов возможны ситуации, когда изначальный статус укорачивается, разбивается другим промежутком(-ами) на несколько частей или совсем вырождается, если перекрывается уже находящимся промежутком с высоким приотиретом. Обратите внимание, что в события передаётся изначальный статус, без учёта разбиений или иных изменений изначального статуса. В событии ContractStatusChangingEvent также существует поле, содержащее список всех кусочков изначального статуса после обработки операции перекрытия промежутков разных статусов. Код: /** * Возвращает кусочки исходного статуса, они будут отличаться от основного, * если статус был разбит при пересечении с разными кусками неперетираемых * статусов. * * @return коллекция объектов ContractStatus. */ public Collection<ContractStatus> getStatusParts(); Учёт того, что, возможно, устанавливаемый статус не начал действовать или вообще никогда не начнёт надо делать вручную, внутри скрипта, опираясь на список этих кусочков. Более подробно о алгоритме и логике метода -- ниже. |
Автор: | Cromeshnic [ 13 сен 2010, 15:22 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
![]() ![]() ![]() |
Автор: | dimOn [ 13 сен 2010, 15:30 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Алгоритм установки статуса Ахтунг! Сейчас уже неактуально! Ниже приведены алгоритмические подробности, для более глубокого понимания логики установки статуса, что необходимо для изучения этого вопроса и написания качественных скриптов поведения. В целом описание алгоритма несёт мало пользы, но может помочь понять в какой момент происходит генерация событий и что именно туда попадает. Для начала рассмотрим общую сигнатуру метода. Код: /** * Смена статуса договора. При этом происходит корректное перекрытие * существующих на моменты времени статусов, с тем, * чтобы на каждый день была активна только одна запись о статусе. * * @param newStatus новый статус с периодом. * @param userId ид юзера. если будет null, то это эквивалентно 0. * @param processEvent проводить ли события. * @param isweb если смена проходит из веба. */ public void changeStatus( ContractStatus newStatus, Integer userId, boolean processEvent, boolean isweb ) throws SQLException Далее алгоритм. Многие технические части намеренно опущены. * Для каждого из случаев (клиент, сервер, web) выбирается из конфига 6 чисел -- приоритеты статусов. |
Автор: | dimOn [ 13 сен 2010, 15:59 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Сборку выложил. Если приоритеты статусов вообще не прописывать, то сломаться не должно ничего, всё будет как раньше. Но неперетираемые статусы надо ещё некоторое время тестировать, пишите если что-то не то. |
Автор: | dimOn [ 06 окт 2010, 15:56 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
![]() ![]() |
Автор: | dimOn [ 13 окт 2010, 12:33 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Всё, теперь смена статусов через скрипт: http://wiki.bgbilling.ru/index.php/%D0% ... 0%BE%D0%B2 |
Автор: | Cromeshnic [ 14 мар 2012, 11:47 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Решил наконец воспользоваться фичей. Проблема такая: У клиента несколько точек, оформленных в виде зависимых субдоговоров. Одна из них по просьбе клиента приостанавливается (статус="приостановлен"). При этом статус супердоговора может быть любой. Но если мы его меняем, то теряем приостановление на субдоговоре. Нужно сделать так, чтобы перетереть статус "приостановлен" зависимого субдоговора можно было только изменяя статус этого субдоговора, но не супердоговора. При этом остальные статусы для зависимых субдоговоров перетираются как обычно. В событии ContractSetStatusLogicEvent нет способа узнать, задаётся ли статус на субдоговоре индивидуально или сработал каскадом от супердоговора. Как быть? |
Автор: | dimOn [ 14 мар 2012, 19:48 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
И как это сделать? |
Автор: | Феанор [ 15 мар 2012, 11:57 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
А можно на зависимом субдоговоре по его типу как нибудь запретить перетирать статус активен статусом отключен? но разрешить перетирать статусами приостановлен, активен все остальное? Есть просто у клиента несколько субдоговоров - один из них телефонный. а его по закону только после 21го числа отключать можно. Баланс единый у абонентов, работают в минус. Чтобы оператором понятнее было че с абонентом - есть скриптик который дергает статус абонента сравнивая его с лимитом.. Получается засада с абонентами у которых есть телефония - им вроде и надо статус поменять, чтобы инет перестал работать, но телефонию трогать не надо. Независимым договором тоже не сделаешь - нужен единый баланс. |
Автор: | Феанор [ 15 мар 2012, 13:36 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Хочу чтобы на договоре на котором висит этот скрипт не выставлялся статус отключено. Код: public void onEvent( event1, setup, con, conSlave ) { ContractSetStatusLogicEvent event = (ContractSetStatusLogicEvent)event1; print( "do change status!" ); // старый статус ContractStatus status = event.getStatus1(); // Приходящий статус ContractStatus newStatus = event.getStatus2(); // Самый что ни на есть оригинальный статус ContractStatus originalStatus = event.getOriginalStatus(); if(newStatus.getStatus()==2) { print ("Disable overwrite"); event.setProcessed( true ); return; } } Функция выполняется, в логах Код: GENERATE_TIME: 15.03.12 15:33:34 EXECUTION_STOP_TIME: 15.03.12 15:33:34 PROCESS_TIME: 2 OUT: do change status! Disable overwrite но статус устанавливается. в настройках сервера use.event.set.status.logic=1 стоит, сервер перезапускал. нид хэлп энд экспланейшн =) |
Автор: | dimOn [ 15 мар 2012, 16:30 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
версии |
Автор: | dimOn [ 15 мар 2012, 16:36 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Кстати, он что, только один раз вызывается? Вы же понимаете логику его работы? Скрипт должен вызваться несколько раз, равное количеству уже существующих промежутков статусов на договоре? Т.е. применяется ко всем промежуткам оттуда новый статус. |
Автор: | dimOn [ 15 мар 2012, 16:58 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Ну я понял вас, НО: всё не так. Скрипт должен МОДИФИЦИРОВАТЬ статус. Тот, который приходит нам, новый. Он в конце работы этого цикла (который обходит все статусы) всегда сохраняется. Т.е. если вы его не изменили, то ничего и не изменится - он запишется как есть. А те статусы, которые есть в БД можно (нужно?) в этом же скрипте модифицировать тоже, но уже через БД напрямую. (поглядите на вики пример стандартной работы кода в виде этого же скрипта). Если вы хотите просто проигнорировать этот статус, то вам и в БД ничего не надо менять, но и этот статус ВЫРОДИТЬ. Ну и плюс поставить, конечно, этот флаг отработанности. Он влияет только на то, что в конкретном цикле (=одному запуску скрипта) произойдёт continue и не выполнится дельнейший стандартный код. |
Автор: | Феанор [ 15 мар 2012, 17:00 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
dimOn писал(а): Ну я понял вас, НО: всё не так. Скрипт должен МОДИФИЦИРОВАТЬ статус. Тот, который приходит нам, новый. Он в конце работы этого цикла (который обходит все статусы) всегда сохраняется. Т.е. если вы его не изменили, то ничего и не изменится - он запишется как есть. А те статусы, которые есть в БД можно (нужно?) в этом же скрипте модифицировать тоже, но уже через БД напрямую. (поглядите на вики пример стандартной работы кода в виде этого же скрипта). Если вы хотите просто проигнорировать этот статус, то вам и в БД ничего не надо менять, но и этот статус ВЫРОДИТЬ. Ну и плюс поставить, конечно, этот флаг отработанности. Он влияет только на то, что в конкретном цикле (=одному запуску скрипта) произойдёт continue и не выполнится дельнейший стандартный код. как я понял мне надо сделать newStatus=status? т.е. новый статус оставить таким же как и было? но так не работает ![]() |
Автор: | dimOn [ 15 мар 2012, 17:02 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Как выродить: поставить у этого нового статуса date2 предыдущим днём от date1, например. Попробуйте так. |
Автор: | dimOn [ 15 мар 2012, 17:06 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Феанор писал(а): dimOn писал(а): Ну я понял вас, НО: всё не так. Скрипт должен МОДИФИЦИРОВАТЬ статус. Тот, который приходит нам, новый. Он в конце работы этого цикла (который обходит все статусы) всегда сохраняется. Т.е. если вы его не изменили, то ничего и не изменится - он запишется как есть. А те статусы, которые есть в БД можно (нужно?) в этом же скрипте модифицировать тоже, но уже через БД напрямую. (поглядите на вики пример стандартной работы кода в виде этого же скрипта). Если вы хотите просто проигнорировать этот статус, то вам и в БД ничего не надо менять, но и этот статус ВЫРОДИТЬ. Ну и плюс поставить, конечно, этот флаг отработанности. Он влияет только на то, что в конкретном цикле (=одному запуску скрипта) произойдёт continue и не выполнится дельнейший стандартный код. как я понял мне надо сделать newStatus=status? т.е. новый статус оставить таким же как и было? но так не работает ![]() нет, статус второй вы никак не измените. этот статус УЖЕ ЕСТЬ в БД, это просто один из статусов в истории. смысл скрипта (который фактически замещает стандартный код) - просто решить как изменить новый статус , чтобы подвинуть его границы перед сохранением. либо же двигаем границы того что лежит уже в БД. если у вас лежит уже статус в БД 01.01.2012 - бесконечность, а вы ставите статус например 15.03.2012-бесконечность. то стандартный код двигает то что есть и записывает в БД. а потом этот новый статус (он стандатрным кодом не меняется) тоже в конце-концов кладёт в БД. ваш же скрипт который вы выложили испортит базу - он и старый не трогает, и новый не меняет. так что у вас окажется новый статус который конфликтует с периодам тем что уже есть. скрипт не может "ничего не делать". это довольно низкоуровневый скрипт и пользоваться им надо аккуратно. |
Автор: | Феанор [ 15 мар 2012, 17:09 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
dimOn писал(а): Как выродить: поставить у этого нового статуса date2 предыдущим днём от date1, например. Попробуйте так. newStatus.setDateTo(TimeUtils.getPrevDay(newStatus.getDateFrom)); Перетирает все как стандартной логикой. update - поэтому я все и делаю на тестовой базе, которую не жалко update2 - в коде который в начале сообщения пробовал - ошибка была, поэтому и не работало, обращался к полю а не к методу newStatus.setDateTo(TimeUtils.getPrevDay(newStatus.getDateFrom())) - делает то что мне надо на первый взгляд. тестировать уже завтра буду |
Автор: | dimOn [ 15 мар 2012, 17:10 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Ваш скрипт должен либо поправить БД чтобы предыдущий там изменить. либо изменить newStatus, и сделать его таким, который в итоге попадёт в БД. Если вы хотите чтобы в БД осталось всё что лежало, а новый вообще проигнорировался, то БД не трогаете, а новый грохаете, т.е. вырождаете как я написал. Но учтите, что у вас это ведь по некоторым условиям выполняется, то есть если эти условия не наступили, вам надо позаботиться чтобы нормально подвинулись статусы, чтобы не произошло казуса как я выше описал. В вашем случае проще всего тогда для этого случая не менять ни пришедший ни лежащий в БД, и установить обработанность=фалсе, чтобы стандартный код дальше сделал чо надо для этой пары статусов. |
Автор: | dimOn [ 15 мар 2012, 17:11 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Феанор писал(а): dimOn писал(а): Как выродить: поставить у этого нового статуса date2 предыдущим днём от date1, например. Попробуйте так. newStatus.setDateTo(TimeUtils.getPrevDay(newStatus.getDateFrom)); Перетирает все как стандартной логикой. update - поэтому я все и делаю на тестовой базе, которую не жалко update2 - в коде который в начале сообщения пробовал - ошибка была, поэтому и не работало, обращался к полю а не к методу newStatus.setDateTo(TimeUtils.getPrevDay(newStatus.getDateFrom())) - делает то что мне надо на первый взгляд. тестировать уже завтра буду сейчас подумаю.......... |
Автор: | Феанор [ 15 мар 2012, 17:15 ] | ||
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) | ||
он кстати в логах действий пишет : статус изменился (последний промежуток: 15.03.2012-14.03.2012: отключен)(т.е. выродился), но периоды при этом нормально остаются, остальными статусами перетираются, статус отключен никак не влияет на периоды
|
Автор: | Феанор [ 15 мар 2012, 17:20 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Cromeshnic писал(а): Решил наконец воспользоваться фичей. Проблема такая: У клиента несколько точек, оформленных в виде зависимых субдоговоров. Одна из них по просьбе клиента приостанавливается (статус="приостановлен"). При этом статус супердоговора может быть любой. Но если мы его меняем, то теряем приостановление на субдоговоре. Нужно сделать так, чтобы перетереть статус "приостановлен" зависимого субдоговора можно было только изменяя статус этого субдоговора, но не супердоговора. При этом остальные статусы для зависимых субдоговоров перетираются как обычно. В событии ContractSetStatusLogicEvent нет способа узнать, задаётся ли статус на субдоговоре индивидуально или сработал каскадом от супердоговора. Как быть? я бы это попробовал сделать так - на договоре сделал параметр типа флаг - в функции скрипта проверял бы - супердоговор это или нет. если супер то апдейтил бы флаг, а если суб и флаг супера установлен в заданный таймаут (5-10 секунд), то игнорировал бы статусы (как игнорировать статусы - в топике выше, у меня эта задача была)... костыль конечно, но почему бы и нет:) |
Автор: | Cromeshnic [ 20 мар 2012, 12:44 ] |
Заголовок сообщения: | Re: Всё о новых статусах договоров (и о перетирании) |
Феанор писал(а): я бы это попробовал сделать так - на договоре сделал параметр типа флаг Спасибо. Сделал флаг по-другому: добавил префикс в комментарий "С супердоговора: ". В событии ContractStatusChangingEvent ставим этот префикс, если событие сработало на супердоговоре. В событии ContractSetStatusLogicEvent, если status=4 и в originalStatus есть префикс, а в status префикса нет, то включаем нашу логику. Написал, побаловался на тестовом биллинге, сейчас запилю в продакшн, посмотрим. Код: package ru.dsi.bgbilling.kernel.scripts; import bitel.billing.server.contract.bean.Contract; import bitel.billing.server.contract.bean.ContractManager; import bitel.billing.server.contract.bean.ContractStatus; import ru.bitel.bgbilling.kernel.event.events.ContractStatusChangingEvent; import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.sql.ConnectionSet; public class SubcontractFlagContractStatusChangingEvent extends EventScriptBase<ContractStatusChangingEvent> { public static String subcontractCommentPrefix = "С супердоговора: "; @Override public void onEvent( ContractStatusChangingEvent event, Setup setup, ConnectionSet connectionSet ) throws Exception { int cid = event.getContractId(); ContractManager cm = new ContractManager(connectionSet.getConnection()); Contract c = cm.getContractById(cid); if(null==c){ return; } if(c.isSuper()){ ContractStatus cs = event.getOriginalStatus(); if(cs!=null){ String comment = cs.getComment(); if(null==comment){comment="";} cs.setComment(subcontractCommentPrefix+comment); } } } } Код: package ru.dsi.bgbilling.kernel.scripts;
import java.util.Calendar; import bitel.billing.common.TimeUtils; import bitel.billing.server.contract.bean.ContractStatus; import bitel.billing.server.contract.bean.ContractStatusManager.ContractStatusManager4Script; import ru.bitel.bgbilling.kernel.event.events.ContractSetStatusLogicEvent; import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase; import ru.bitel.bgbilling.server.util.Setup; import ru.bitel.common.sql.ConnectionSet; public class MyContractSetStatusLogicEvent extends EventScriptBase<ContractSetStatusLogicEvent> { @Override public void onEvent( ContractSetStatusLogicEvent event, Setup setup, ConnectionSet connectionSet ) throws Exception { ContractStatus originalStatus = event.getOriginalStatus(); this.print("status="+event.getStatus1()); String comment = originalStatus.getComment(); if(comment!=null){ if(comment.startsWith(SubcontractFlagContractStatusChangingEvent.subcontractCommentPrefix)){ //Если комментарий статуса начинается с SubcontractFlagContractStatusChangingEvent.subcontractCommentPrefix //и мы - субдоговор, то считаем, что статус устанавливается с супердоговора => // => не перекрываем островки статуса "приостановлен" // старый статус ContractStatus status = event.getStatus1(); // Приходящий статус ContractStatus newStatus = event.getStatus2(); String statusComment = status.getComment(); if(statusComment==null){statusComment="";} //Обрабатываем только статус 4 ("приостановлен"), установленный на конкретном субдоговоре (не спущенный сверху) if(status.getStatus()==4 && !statusComment.startsWith(SubcontractFlagContractStatusChangingEvent.subcontractCommentPrefix)){ // менеджер ContractStatusManager, оптимизированный для этого скрипта ContractStatusManager4Script csm = new ContractStatusManager4Script( connectionSet.getConnection() ); //Предыдущий день перед началом нового статуса Calendar prevDay = Calendar.getInstance(); prevDay.setTime( newStatus.getDateFrom() ); prevDay.add( Calendar.DAY_OF_MONTH, -1 ); // следующий день после конца нового статуса (или null) Calendar nextDay = null; if( originalStatus.getDateTo() != null ) { nextDay = Calendar.getInstance(); nextDay.setTime( newStatus.getDateTo() ); nextDay.add( Calendar.DAY_OF_YEAR, 1 ); } Calendar tmpprev = Calendar.getInstance(); tmpprev.setTime(status.getDateFrom()); tmpprev.add( Calendar.DAY_OF_MONTH, -1 ); Calendar tmpnext = Calendar.getInstance(); if(status.getDateTo()!=null){ tmpnext.setTime(status.getDateTo()); tmpnext.add( Calendar.DAY_OF_MONTH, 1 ); }else{ tmpnext=null; } /* 1. * status:...[4444] * new:....[***********? * -> * status:...[4444] * new:....[]......[***? * * и да, мы теряем первый кусок от newStatus, поэтому сразу же его апдейтим (хоть и вне стандартной логики и без ContractStatusChangingEvent) */ if( TimeUtils.dateBeforeOrEq( newStatus.getDateFrom(), status.getDateFrom() ) && status.getDateTo() != null && (newStatus.getDateTo() == null || TimeUtils.dateBeforeOrEq( status.getDateTo(), newStatus.getDateTo() ) ) ) { //Запиливаем первый кусочек: if(TimeUtils.dateBefore(newStatus.getDateFrom(), tmpprev.getTime())){ ContractStatus tmp = newStatus.clone(); tmp.setDateTo(tmpprev.getTime()); if(ContractStatusManager4Script.isStatusPeriodValid(tmp)){ csm.updateStatus(tmp, event.getUserId()); } } //Меняем date1 второго кусочка newStatus newStatus.setDateFrom(tmpnext.getTime()); }else /* 2. * status:..[444] * new:.......[******? * -> * status:..[444] * new:..........[***? */ if(status.getDateTo() != null && TimeUtils.dateBeforeOrEq(status.getDateFrom(),newStatus.getDateFrom())){ newStatus.setDateFrom(tmpnext.getTime()); }else /* 3. * status:.....[444444? * new:.....[*****] * -> * status:.....[444444? * new:.....[*] */ if(newStatus.getDateTo()!=null && TimeUtils.dateBeforeOrEq(status.getDateFrom(), newStatus.getDateTo())){ newStatus.setDateTo(tmpprev.getTime()); }else /* 4. * status:.....[4444! * new:.....[*******? * or * status:.....[4444! * new:..........[**? * -> * status:.....[4444! * new:.....[*] * or * status:.....[4444! * new:.............. */ if(status.getDateTo()==null){ //либо статус обрезается до кусочка перед нашим диапазоном, либо вырождается newStatus.setDateTo(tmpprev.getTime()); } event.setProcessed( true ); } } } } } |
Страница 1 из 1 | Часовой пояс: UTC + 5 часов [ Летнее время ] |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |