Алгоритм установки статуса в системе
Материал из BiTel WiKi
DimOn (Обсуждение | вклад) м |
DimOn (Обсуждение | вклад) |
||
Строка 19: | Строка 19: | ||
Далее алгоритм. Многие технические части намеренно опущены. | Далее алгоритм. Многие технические части намеренно опущены. | ||
- | * | + | * Проверяется нужно ли нам будет использовать событие для логики перетирания статусов - '''флаг useEventSetStatusLogic''' |
* Запоминается '''оригинальный_статус''', ибо устанавливаемый '''newStatus''' подготавливается к постепенному видоизменению. | * Запоминается '''оригинальный_статус''', ибо устанавливаемый '''newStatus''' подготавливается к постепенному видоизменению. | ||
* Из устанавливаемого статуса берётся cid, получается соответствующий '''договор'''. Если договора нет - молча на выход. | * Из устанавливаемого статуса берётся cid, получается соответствующий '''договор'''. Если договора нет - молча на выход. | ||
- | + | * Берутся все промежутки статусов для этого договора (в реальности только те, что не раньше того момента, откуда самое раннее будет действовать новый статус; но это непринципиально) по ним делается цикл: | |
- | * Берутся все промежутки статусов для этого договора (в реальности только те, что не раньше того момента, откуда самое раннее будет действовать новый статус; но это непринципиально) по ним делается цикл | + | |
{ | { | ||
- | * '''выбранный_статус''' - статус текущей итерации (один из промежутков статуса договора). | + | * '''выбранный_статус''' (status) - статус текущей итерации (один из промежутков статуса договора). |
- | + | * если newStatus выродился (может быть только за счёт изменения в скрипте, ибо стандартной логикой он не изменяется), то выйти из цикла | |
- | + | ||
- | + | * если useEventSetStatusLogic, то запускаем событие задания логики перетирания ContractSetStatusLogicEvent. | |
- | + | * если в скрипте был установлен флаг isProcessed, то вернуться в следующей итерации цикла (continue). иначе продолжим итерацию цикла далее. | |
- | + | ||
- | + | // далее следует логика учёта перекрытий статусов | |
- | + | * Если статусы ([b]newStatus[/b] и [b]выбранный_статус[/b] (status)) вообще не перекрываются | |
- | + | { | |
- | + | то возвращается к очередной итерации цикла (continue). | |
- | + | } | |
- | + | ||
- | + | ||
- | + | * Если [b]newStatus[/b] полностью перекрыл [b]выбранный_статус[/b] то | |
- | + | { | |
- | + | // полное перекрытие статуса | |
- | + | // old .......!*****?..... | |
- | + | // new ......!************ | |
- | + | // | |
- | + | // old .......!*****!..... | |
- | + | // new .....!*********!... | |
- | + | если [b]старый_статус_перетираемый[/b] то удаляем из списка [b]выбранный_статус[/b]. | |
- | + | иначе (если старый статус нельзя перетереть устанавливаемым) newStatus бьётся на две части. | |
- | + | // old .......!*****!..... | |
- | + | // new .....!].......[*?.. | |
- | + | левый кусочек добавляется в список [b]кусочки_нового_статуса[/b], а правый становится новым [b]newStatus[/b] и мы его дальше используем в следующих итерациях. | |
- | + | } | |
- | + | * Если происходит разрыв статусом [b]выбранного_статуса[/b] | |
- | + | { | |
- | + | // old .....[*****]..... | |
- | + | // new ......[**!....... | |
- | + | если [b]старый_статус_перетираемый[/b] то разрываем его на два кусочка и пишем оба в БД. новый не меняется. | |
- | + | иначе (если старый статус нельзя перетереть устанавливаемым) то выходит, что [b]newStatus[/b] вообще вырождается окончательно, делаем newStatus=null и выходим из цикла. | |
- | + | } | |
- | + | *перекрытие старого статуса ([b]выбранного_статуса[/b]) "слева" | |
- | + | { | |
- | + | // old ........!*****].. | |
- | + | // new .....?******!.... | |
- | + | если [b]старый_статус_перетираемый[/b] то делаем как раньше - двигаем старый до следующего дня после нового | |
- | + | // old .............!].. | |
- | + | // new .....?******!.... | |
- | + | иначе (если старый статус нельзя перетереть устанавливаемым), то мы наоборот, двигаем новый конец назад, до предыдущего к старому | |
- | + | // old ........!*****].. | |
- | + | // new .....?*!......... | |
- | + | } | |
- | + | *перекрытие старого статуса ([b]выбранного_статуса[/b]) "справа" | |
- | + | { | |
- | + | // old ....[*****]...... | |
- | + | // new ......[******]... | |
- | + | если [b]старый_статус_перетираемый[/b] то делаем как раньше - двигаем старый до предыдущего дня до нового | |
+ | // old ....[]........... | ||
+ | // new ......[******]... | ||
+ | иначе (если старый статус нельзя перетереть устанавливаемым), то мы наоборот, двигаем новый начало вперёд, до следующего к старому | ||
+ | // old ....[*****]...... | ||
+ | // new ...........[*]... | ||
+ | } | ||
} | } | ||
* Закончили цикл, если [b]newStatus[/b] остался ещё (то есть newStatus!=null), то кладём его тоже в [b]кусочки_нового_статуса[/b], это будет самый правый кусочек исходного статуса. Легко видеть, что если у нас вообще нет никаких неперетираемых статусо итд, то этот кусочек как раз будет единственным в списке и будет равен [b]оригинальному_статусу[/b]. | * Закончили цикл, если [b]newStatus[/b] остался ещё (то есть newStatus!=null), то кладём его тоже в [b]кусочки_нового_статуса[/b], это будет самый правый кусочек исходного статуса. Легко видеть, что если у нас вообще нет никаких неперетираемых статусо итд, то этот кусочек как раз будет единственным в списке и будет равен [b]оригинальному_статусу[/b]. |
Версия 08:33, 1 декабря 2010
Алгоритм установки статуса в системе
Ниже приведены алгоритмические подробности, для более глубокого понимания логики установки статуса, что необходимо для изучения этого вопроса и написания качественных скриптов поведения. В целом описание алгоритма несёт мало пользы, но может помочь понять в какой момент происходит генерация событий и что именно туда попадает.
Для начала рассмотрим общую сигнатуру метода.
/** * Смена статуса договора. При этом происходит корректное перекрытие * существующих на моменты времени статусов, с тем, * чтобы на каждый день была активна только одна запись о статусе. * * @param newStatus новый статус с периодом. * @param userId ид юзера. если будет null, то это эквивалентно 0. * @param processEvent проводить ли события. */ public void changeStatus( ContractStatus newStatus, Integer userId, boolean processEvent ) throws SQLException
Далее алгоритм. Многие технические части намеренно опущены.
- Проверяется нужно ли нам будет использовать событие для логики перетирания статусов - флаг useEventSetStatusLogic
- Запоминается оригинальный_статус, ибо устанавливаемый newStatus подготавливается к постепенному видоизменению.
- Из устанавливаемого статуса берётся cid, получается соответствующий договор. Если договора нет - молча на выход.
- Берутся все промежутки статусов для этого договора (в реальности только те, что не раньше того момента, откуда самое раннее будет действовать новый статус; но это непринципиально) по ним делается цикл:
{
- выбранный_статус (status) - статус текущей итерации (один из промежутков статуса договора).
- если newStatus выродился (может быть только за счёт изменения в скрипте, ибо стандартной логикой он не изменяется), то выйти из цикла
- если useEventSetStatusLogic, то запускаем событие задания логики перетирания ContractSetStatusLogicEvent.
- если в скрипте был установлен флаг isProcessed, то вернуться в следующей итерации цикла (continue). иначе продолжим итерацию цикла далее.
// далее следует логика учёта перекрытий статусов
- Если статусы ([b]newStatus[/b] и [b]выбранный_статус[/b] (status)) вообще не перекрываются
{ то возвращается к очередной итерации цикла (continue). }
- Если [b]newStatus[/b] полностью перекрыл [b]выбранный_статус[/b] то
{ // полное перекрытие статуса // old .......!*****?..... // new ......!************ // // old .......!*****!..... // new .....!*********!... если [b]старый_статус_перетираемый[/b] то удаляем из списка [b]выбранный_статус[/b]. иначе (если старый статус нельзя перетереть устанавливаемым) newStatus бьётся на две части. // old .......!*****!..... // new .....!].......[*?.. левый кусочек добавляется в список [b]кусочки_нового_статуса[/b], а правый становится новым [b]newStatus[/b] и мы его дальше используем в следующих итерациях. }
- Если происходит разрыв статусом [b]выбранного_статуса[/b]
{ // old .....[*****]..... // new ......[**!....... если [b]старый_статус_перетираемый[/b] то разрываем его на два кусочка и пишем оба в БД. новый не меняется. иначе (если старый статус нельзя перетереть устанавливаемым) то выходит, что [b]newStatus[/b] вообще вырождается окончательно, делаем newStatus=null и выходим из цикла. }
- перекрытие старого статуса ([b]выбранного_статуса[/b]) "слева"
{ // old ........!*****].. // new .....?******!.... если [b]старый_статус_перетираемый[/b] то делаем как раньше - двигаем старый до следующего дня после нового // old .............!].. // new .....?******!.... иначе (если старый статус нельзя перетереть устанавливаемым), то мы наоборот, двигаем новый конец назад, до предыдущего к старому // old ........!*****].. // new .....?*!......... }
- перекрытие старого статуса ([b]выбранного_статуса[/b]) "справа"
{ // old ....[*****]...... // new ......[******]... если [b]старый_статус_перетираемый[/b] то делаем как раньше - двигаем старый до предыдущего дня до нового // old ....[]........... // new ......[******]... иначе (если старый статус нельзя перетереть устанавливаемым), то мы наоборот, двигаем новый начало вперёд, до следующего к старому // old ....[*****]...... // new ...........[*]... } }
- Закончили цикл, если [b]newStatus[/b] остался ещё (то есть newStatus!=null), то кладём его тоже в [b]кусочки_нового_статуса[/b], это будет самый правый кусочек исходного статуса. Легко видеть, что если у нас вообще нет никаких неперетираемых статусо итд, то этот кусочек как раз будет единственным в списке и будет равен [b]оригинальному_статусу[/b].
- Далее, готовим событие ContractStatusChangingEvent, куда кладём [b]оригинальный_статус[/b] (!) и плюс все [b]кусочки_нового_статуса[/b]. То есть всё останется как и было, кроме того случая, когда включаются приоритеты статусов, тогда, возможно, нужно будет учитывать кусочки в скрипте.
- Здесь самое интересное начинается. как известно, в скрипте можно изменить статус с бывшего на другой. в случае равноправных промежутков всё понятно - новый изменённый статус так и пишется. сейчас статус это список кусочков.
Так вот, смотрится [b]оригинальный_статус[/b] и статус, побывавший в событии. Если статус был изменён, то меняется статус всех [b]кусочков_нового_статуса[/b]. После Этого все кусочки пишутся в БД. То есть логика здесь такая - можно взять и поменять статус в скрипте у отдельных кусочков. Но если поменян статус у целого контрактстатуса, то он распространится на все кусочки.
- При этом всём смотрится каждый кусочек и проверяется, что попадает на сегодня. Если это так, то устанавливается статус договора. После этого генерируется событие ContractStatusChangedEvent.
Внимание: в событие попадает не оригинальный статус, а кусочек соответствующий... не уверен пока что так надо.
- Записывается лог смены статусов. Если что-то меняется, то в комментарий лога смены статусов добавится, что статус был подрезан или разбит или выродился.
- Если договор - супердоговор
{ вызывается changeStatus для всех субдоговоров с зависимым балансом, куда передаётся [b]оригинальный_статус[/b]. если установлен independ.subcontract.status.change, то и для субдоговоров с независимым - тоже самое. }
--dimOn 11:52, 26 ноября 2010 (UTC)