Алгоритм установки статуса в системе

Материал из BiTel WiKi

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

Текущая версия на 12:48, 28 марта 2013

Ниже приведены алгоритмические подробности, для более глубокого понимания логики установки статуса, что необходимо для изучения этого вопроса и написания качественных скриптов поведения для задания своей логики смены статусов. В целом описание алгоритма несёт мало пользы, но может помочь понять в какой момент происходит генерация событий и что именно туда попадает.

Для начала рассмотрим общую сигнатуру метода.

/**
 * Смена статуса договора. При этом происходит корректное перекрытие
 * существующих на моменты времени статусов, с тем,
 * чтобы на каждый день была активна только одна запись о статусе.
 * 
 * @param newStatus новый статус с периодом.
 * @param userId ид юзера. если будет null, то это эквивалентно 0.
 * @param processEvent проводить ли события.
 */
public void changeStatus( ContractStatus newStatus, Integer userId, boolean processEvent ) throws SQLException

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

* Проверяется нужно ли нам будет использовать событие для логики перетирания статусов - 'флаг useEventSetStatusLogic'
* Запоминается 'оригинальный_статус', ибо устанавливаемый 'newStatus' подготавливается к постепенному видоизменению.
* Из устанавливаемого статуса берётся cid, получается соответствующий 'договор'. Если договора нет - молча на выход (return).
* Берутся все промежутки статусов для этого договора (в реальности только те, что не раньше того момента, откуда самое раннее будет действовать новый статус; но это непринципиально) по ним делается цикл:
{
	* 'выбранный_статус' (status) - статус текущей итерации (один из промежутков статуса договора).
	* если newStatus выродился (может быть только за счёт изменения в скрипте, ибо стандартной логикой он не изменяется), то выйти из цикла (break)
 
	* если useEventSetStatusLogic, то запускаем событие задания логики перетирания ContractSetStatusLogicEvent.
	* если в скрипте был установлен флаг isProcessed, то вернуться к следующей итерации цикла (continue). (иначе продолжим итерацию цикла далее).
 
	// далее следует стандартная зашитая логика учёта перекрытий статусов
 
	* Если статусы ('newStatus' и 'выбранный_статус' (status)) вообще не перекрываются
	{
		то возвращается к очередной итерации цикла (continue).
	}
	* Если 'newStatus' полностью перекрыл 'выбранный_статус' то
	{
		// полное перекрытие статуса
		// old .......!*****?.....
		// new ......!************
		//
		// old .......!*****!.....
		// new .....!*********!...
		удаляем из списка и из БД 'выбранный_статус'.
	}
	* Если происходит разрыв статусом 'выбранного_статуса'
	{
		// old .....[*****].....
		// new ......[**!.......
		разрываем старый_статус на два кусочка и пишем оба в БД. новый не меняется.
	}
	* перекрытие старого статуса ('выбранного_статуса') "слева"
	{
		// old ........!*****]..
		// new .....?******!....
		двигаем старый до следующего дня после нового
		// old .............!]..
		// new .....?******!....	
	}
	*перекрытие старого статуса ('выбранного_статуса') "справа"
	{
		// old ....[*****]......
		// new ......[******]...
		двигаем старый до предыдущего дня до нового
		// old ....[]...........
		// new ......[******]...
	}
}
* Далее, готовим событие ContractStatusChangingEvent, куда кладём 'оригинальный_статус' плюс 'newStatus'. То есть всё останется как и было, кроме того случая, когда включаются приоритеты статусов, тогда, возможно, нужно будет учитывать кусочки в скрипте. В скрипте, если использовался скрипт задания логики статусов, возможно эти два объекта будут разные, надо учитывать это и использовать либо оригинальный, либо уже изменённый там статус.
// создаём статус для сувания в событие. кладём туда newStatus(!).
// если вдруг в событии смены логики мы делали что-либо меняющее наш newStatus,
// то в этом скрипте надо сделать то же самое пожалуй, чтобы увидеть его реальный.
// это может измениться в событии, дальше проверим. Также в событие отдадим
// оригинальный статус.
* Если по выходу из предыдущего события статус не вырожденный, то обновляем его в БД, т.е. в данном случае всегда фактически его insert-им.
// сохраняем статус (т.к. id нету то всегда будет insert), он уже прошёл через событие
// +надо проверить чокак чтобы не выродился (если мы используем задание логики скриптом).
// на данный момент newStatus отрезок даты мог выродиться вообще в
// ( +бесконечность, +бесконечность ). 
* смотрится статус по выходу из предыдущего события и проверяется, что попадает на сегодня. Если это так, то устанавливается статус договора. После этого генерируется событие ContractStatusChangedEvent. Внимание: в событие попадает не оригинальный статус, а кусочек соответствующий, прошедший через событие ContractStatusChangingEvent...
* Записывается лог смены статусов. Если что-то меняется, то в комментарий лога смены статусов добавится, что статус был подрезан или разбит или выродился.
* Если договор - супердоговор, то
{
	вызывается changeStatus для всех субдоговоров с зависимым балансом, куда передаётся 'оригинальный_статус' (!).
	если установлен independ.subcontract.status.change, то и для субдоговоров с независимым - тоже самое.
}

--dimOn 11:52, 26 ноября 2010 (UTC)

Личные инструменты