We have a requirement where in we want to provide users with an option to change case type manually. What is the best way to achieve this functionality?
I am able to think of 2 ways-
1. Use OOTB flow action rule ChangeClass which allows to change class of a case. The problem I see with this approach is that the post activity of this flow action only changes the class of pyWorkPage to the new class but does not alter any of the page in pxFlow page group and they still holds old class value. Will this be a problem where in pages in pxFlow page group has different class than work page ?
2. Resolve the current case and instantiate a new case with new class value.
If you change class to a more specialized class that pattern-inherits or directly extends the existing case type class you would be fine.
If you want to convert to a completely different case type class it would be best to close the case and create a new one salvaging what information you can from the original case such as a Link-Attachments.
In your example you would not only have to modify properties within pxFlow() such pxFlowInsKey and pxAssignmentKey you would also have to update the pxRefObjectKey and pxRefObjectClass properties within the assignment instance referenced by pxAssignmentKey.
The reason why modifying a case' type's class, pxObjClass, using pattern-inheritance is perfectly fine is because the key to the case, pyID, would remain the same. Plus the first half of a case's pzInsKey, the case’s class group (work pool), would remain the same. The case's pzInsKey hence would remain the same despite the change made to the case's pxObjClass. There is no need to change pxRefObjectKey on assignments, pxAssignmentKey on pxFlow() pages, so on and so forth. It just “works”.
A simple test proves this is to be true. For a given case type Save-As the class rule appending “-A” to the class name, then do the same using “-B”. In the first screen of the case display a drop-down that has options “<blank>, A, and B. On change refresh the section calling an Activity named OnChangeTest passing the value of the drop-down as a parameter. Initialize a local Text parameter named “NEW_CLASS” to the case’s class name. If the drop-down’s value is not <blank> append a dash then the drop-down’s value to the local Text parameter. Finally invoke Page-Change-Class + param.NEW_CLASS. Afterward open the case to see if its assignments still display correctly or, conversely, open one of case’s assignments from the worklist. Everything works fine. The same is true for attachments.
Nice explanation Pedel, just adding to that, case type modification is not possible, it s better to have a new case type. "Page-Change-Class" can be used to switch work class at runtime for the same case type. For the same case type work instances we can set pattern inherited class or direct inherited class at runtime.
But completely changing casetype rule manually is not possible.
Direct inheritance is fine also as long as the class group does not change to where a different database table is used.
When using the App Explorer's tree view, you can directly navigate between classes in the inheritance hierarchy when pattern inheritance is used unlike direct inheritance.
Modifying the pxObjClass to a case type outside the original case type's inheritance hierarchy would not work. In that situation you would need to create a new case type instance
Persisting the bulk of the original case's data as Data- instances outside the case would simplify the transition plus avoid redundancy. You would only need to propagate lookup key values such as ClaimID.
Actual idea is to change a case type at runtime will lead to the corruption of the current case as the stages/process of the current case might conflict with a new case (if there is a way) but can you please let us understand the actual requirement?
Hi, As per my understanding the requirement is to change the case life cycle entirely, not only the work object class. He expects initially "Contest" case type will be initiated and traversed through its stages, meanwhile if the user would like to change the case type to more specific case type like "Cricket" , "Golf" etc., which have a entirely different life cycle. Here two scenarios are there as below.
1) Having a single case type which is generic like "Contest", throughout the application which is having defined stages and steps that to be followed by specific work instances like "Cricket", "Golf" etc., but with a different implementation at step or flow levels. Once after case creation as soon as the user selected more specific type of contest the polymorphism can be implemented through page-change-class by overwriting the generic work class "xxx-xxx-Work-Contest" with "xxx-xxx-Work-Cricket" ensuring these two are directly inherited. Avoiding the class name extension for pattern inheritance is better suggested, otherwise the class name will be more stretched like "xxx-xxx-Work-Contest-Cricket". Once after work "page-change-class" is done, all the specific flows, UI implementations, data elements of specific work instance "Cricket" or "Golf" can be achieved still by following the same case life cycle of "Contest" case type.
2)Other scenario is the case life cycle itself is different for "Contest", "Cricket" and "Golf" i.e, means the stages,steps all are different completely. In this case you can go with "Case Specialisation", while instantiation of the case based on a property like "Contest Type", system will decide which case life cycle to adopt, instead of base case type's life cycle. If "Contest Type" is "Cricket", then "Cricket" version of case life cycle is implemented. If "Contest Type" has no match with specialised case types then base case type "Contest" case lifecycle will be followed.
Another approach is instantiating "Contest" case type in which the "Contest Type" value will be captured from the user and based on that another specific case type like "Cricket" or "Golf" can be instantiated and "Contest" case can be resolved. This approach is not suggested except "Contest" case type has some parallel process apart from creation of specific case type.
I think your requirement suits the 2nd option, which you can achieve through case specialisation.
Regarding: "the class name will be more stretched". There is no restriction on the length on the applies-to property, pyClassName, other than database column size, for example 2000 characters.
A pzInsKey is restricted to 256 characters. The maximum length for a work pool class is 256 - 1 - pyID.length(), the "1" representing the space between the work pool class and pyID.
From a readability perspective you want to avoid overly lengthy pyClassName values . Pattern inheritance makes it possible to view inheritance as a tree within the App Explorer. The left panel may need to be expanded to the right.
On another note, if changing to a new class after case creation. how would you deal with pyDefault plus avoid calling it twice?
One approach to the post-construction, dynamic-class-change initialization problem is to use an @baseclass-defined Boolean “WasPageInitialized” ValueGroup property. Every pyDefault Data Transform within an inheritance hierarchy could be altered as follows.
Set param.Class = @replaceAll(.pxObjClass,"-","_")
When .WasPageInitialized(param.Class) Exit Data Transform
<if this transform called from application level as opposed to enterprise level, apply pattern-inherited Default transform(s) left to right>
<steps to initialize the defaults for this class go here>
Set .WasPageInitialized(param.Class) = true
pyDefault Data Transform would be called from the bottom up, each higher DT adding initialization or overriding inherited initialization.
What gets tricky is changing the class dynamically more than once. Should the instance be completely reinitialized? Might that overwrite information that was manually set/overridden after the first dynamic class change and before the second dynamic class change?
Perhaps best either not to allow this or force a do-over. What is the possibility that someone would go from Org-Data-Vehicle to Org-Data-Vehicle-Car, and then decide to change to Org-Data-Vehicle-Truck instead?
If you were built on Component App, and that Component App defines an Org-Example-Work-Specializable case type, you could specialize that case type multiple times in your parent app, e.g., Work-SpecializationA, Work-SpecializationB, etc.. Here similar cases types have their names immediately after Work-.
Within the same layer you would use pattern inheritance. If wanting to specialize Org-App-Work-Contest by sport your would have, for example, Org-App-Work-Contest-Cricket, Org-App-Work-Contest-Golf, etc.. Here your specialization (Cricket, Golf, etc) does not appear directly after Work-. Instead the specialization appears after the name of the case type that is being specialized within the same layer.
It would be very odd to go from a Cricket contest case to a Golf contest case - let's not go there.
Org-App-Work-Contest does not directly extend Org-App-Work.
Suppose you want define initialization for every Org-App-Work case. Org-App-Work is pattern-inherited, not directly inherited. How can Org-App-Work initialization be "visited" once and only once?
Step 3 in the algorithm shows a way:
3. <if this transform called from application level as opposed to enterprise level, apply pattern-inherited Default transform(s) left to right>
With pattern inheritance, left-to-right means going from generic to more specialized.
With direct inheritance, bottom-up means from generic to more specialized. Pega does this for you, i.e., direct inheritance, bottom-up, one-time initialization.
Like other pyDefault Data Transforms, pattern-inherited Org-App-Work pyDefault avoids being called twice thanks to algorithm steps 2 and 5.
2. When .WasPageInitialized(param.Class) Exit Data Transform
You are trying to change pxObjClass within a pyDefault (??) Data Transform while trying to propagate data from a parent class to "some" class, that propagation effected by a different Data Transform defined in the child case's class (which)?
You have a lot going on at the same time. Suggest simplifying for the sake of maintainability.
The Application rule defines the default class for each case type.
The parent class that is creating the child case does have the ability to dictate the pxObjClass of the child case (DCR). But....
According to Separation of Concerns, it is not necessarily the parent case's responsibility to micro-manage the pxObjClass of a child case. Liskov Substitution Principle also applies. The parent case should not care as long the methods and properties defined in child case's base class are used by any derived class.
This discussion thread is about changing pxObjClass post construction, for example. using a downstream Data Transform.
"SetRules" is not a very descriptive name. You should not hard-code the pxObjClass, instead ask a Data Page what the pxObjClass should be. The Data Page can take a parameter, for example, Param.Sport.
I find the algorithm proposed by Pedel really interesting, although I can't understand the replacement used in step 1:
Set param.Class = @replaceAll(.pxObjClass,"-","_")
Our problem is similar to the one discussed here, we have a case type similar to Org-App-Work-Onboarding, and in one of the first assignments we ask for the Country (we have previously created available classes like -USA, or -MEX) so if the user selects one of the available countries we try to change the class to Org-App-Work-Onboarding-USA. If the user selects a country that is not available, the class would stay as it is.
How I tried to resolve this problem in my project, was to do something like this in pyDefault:
Set .pxObjClass = DataPage[Country:Param.Country].CountryClass
Where param is the one chosen by the user in the Country drop-down.
This approach works, however, it generates a severe warning for trying to change the class of the containing page.
Let me know if this approach looks good or if you see any problems with it.