Restricting Backward movement in Business Process Flow (CRM 2015) - crm

We have a certain requirement in CRM 2015 in which we need to restrict backward movement in Business Process Flow for Non-S/S Admin users.
I iterated through Client API’s (including scripting for Upgrade 1) but I didn’t find any API for achieving using any of the exposed method. So, finally I wrote custom code for this by hijacking the backward movement of the Business Process Flow and prompting user that this is the restricted move for Non-S/S admin users.
However, this is an unsupported change and I see this won’t be an issue as long as DOM ids are same (since on a quick look I found DOM Ids are same in 2013, 2015 and 2015 Rollup1 for BPF).
function restrictBPFPreviousMove() {
var originalPreviousStageHandler = $("#stageBackActionContainer").data("events")["click"][0].handler;
$("#stageBackActionContainer").unbind("click");
$("#stageBackActionContainer").click(function (e) {
alert("Restricted Back Move!");
});
}
However, I was wondering if there is any alternative (supported) to this approach?

CRM 2015 has events for stage selection and change that can be handled.
Business Process Flow control events
Microsoft Dynamics CRM 2015 and
Microsoft Dynamics CRM Online 2015 Update provides two events for user
interaction with the business process flow control. OnStageChange
Occurs when a stage changes. More information: OnStageChange event.
OnStageSelected Occurs when a stage is selected. More information:
OnStageSelected event. There is no UI to register scripts for these
events. Use the following methods in functions registered in the form
OnLoad event to register your functions for these events.
Xrm.Page.data.process.addOnStageChange
Xrm.Page.data.process.addOnStageSelected
Xrm.Page.data.process.removeOnStageChange
Xrm.Page.data.process.removeOnStageSelected
You still have to check the role of the user by hand (retrieve systemuser, retrieve role, mix & match)

First get all the Stages guid with Xrm.Page.data.process.getActiveProcess().getStages() and store it in var as
var stage1= "efe2a761-9f5c-492c-9843-54decc2ab76a";
var stage2= "dddddd34-9f5c-492c-9843-54decc2ab76a";
var stage3= "abcdef12-9f5c-492c-9843-54decc2ab76a";
Next add a Event Handler using Xrm.Page.data.process.addOnStageChange() that checks for the Active stage guid as
var currentStageId = Xrm.Page.data.process.getActiveStage().getId();
then you try moving the stage using either of the following
Xrm.Page.data.process.moveNext();
Xrm.Page.data.process.movePrevious();
Xrm.Page.data.process.setActiveStage();

Related

Axon Framework Execute EventUpcaster

I need to upgrade an event to a new version. This entails removing an old property that is growing (due to a design decision) and is not longer needed.
Having read the documentation available at https://docs.axoniq.io/reference-guide/axon-framework/events/event-versioning and implementing the required parts
#Bean
public EventUpcasterChain eventUpcasterChain(){
return new EventUpcasterChain(
new CurrentLoanBalanceAcceptedEventUpcaster(),
new InterestCalculatedEventUpcaster()
);
}
I cannot seem to get the upcasters to fire the "doUpcast" method. My understanding is that on start up the application will find all old events and convert them to the new version of the events. Is this correct? Or does it only upcast the old events when they are replayed? I am hoping there is a way to do this without replaying all the events.
Versions:
Spring Boot: 2.4.11
Axon Framework: 4.5.4
Update:
After trying to figure out how to remove nodes from the event xml using the upcasters I failed miserably. I must point out that this issue is not an Axon issue but was a poor design decision and a lack of understanding what Axon was doing with the events. The primary lesson is to keep events as simple as possible.
I managed to unload the unnecessary xml from the domain event store using the following query:
update domainevententry
set payload = lo_from_bytea(0, decode(regexp_replace(
subquery.output,
'\<nodeToReplace\>(.*)\<\/nodeToReplace\>',
''
), 'escape'))
from (
SELECT eventidentifier, payloadtype, encode(lo_get(payload::oid), 'escape') as output
FROM domainevententry
WHERE eventidentifier in (
'<id>'
)
AND payloadtype = '<payloadType>'
) as subquery
where domainevententry.eventidentifier = subquery.eventidentifier;
every upcaster in the upcaster chain is called only when it finds an 'old' event to convert to the new one. New events that are fired are the new version of it, so the upcaster will not be used for that.
Upcasters are used when:
An aggregate is loaded (without snapshot) and an old event is encountered
A projection is replayed and an old event is encountered
In all other cases, it will be the new event, so the upcaster won't have to be fired. The upcaster is there so aggregates can keep being loaded, and projections can be replayed from the beginning of the event store.
If this is not the case, we need to take a look at the Revision parameter on the old event definition and the new event definition. For example, if the old event had no #Revision annotation, the SimpleSerializedType needs a version of null or it won't match.
Please include the code of the upcasters if we need to dig further, that would help greatly!

Axon Partialy replay, how do i get a TrackingToken for the startPosition for the replay?

I want my Axon replay events, not all but partially.
A full replay is up and running but when i want a partially replay i need a TrackingToken startPosition for the method resetTokens(), my problem is how to get this token for the partial replay?
I tried with GapAwareTracingToken but this does not work.
public void resetTokensWithRestartIndexFor(String trackingEventProcessorName, Long restartIndex) {
eventProcessingConfiguration
.eventProcessorByProcessingGroup(trackingEventProcessorName, TrackingEventProcessor.class)
.filter(trackingEventProcessor -> !trackingEventProcessor.isReplaying())
.ifPresent(trackingEventProcessor -> {
// shutdown this streaming processor
trackingEventProcessor.shutDown();
// reset the tokens to prepare the processor with start index for replay
trackingEventProcessor.resetTokens(GapAwareTrackingToken.newInstance(restartIndex - 1, Collections.emptySortedSet()));
// start the processor to initiate the replay
trackingEventProcessor.start();
});
}
When i use the GapAwareTrackingToken then i get the exception:
[] - Resolved [java.lang.IllegalArgumentException: Incompatible token type provided.]
I see that there is also a GlobalSequenceTrackingToken i can use, but i don't see any documentatieon about when these can/should be used.
The main "challenge" when doing a partial reset, is that you need to be able to tell where to reset to. In Axon, the position in a stream is defined with a TrackingToken.
The source that you read from will provide you with such a token with each event that it provides. However, when you're doing a reset, you probably didn't store the relevant token while you were consuming those events.
You can also create tokens using any StreamableMessageSource. Generally, this is your Event Store, but if you read from other sources, it could be something else, too.
The StreamableMessageSource provides 4 methods to create a token:
createHeadToken - the position at the most recent edge of the stream, where only new events will be read
createTailToken - the position at the very beginning of the stream, allowing you to replay all events.
createTokenAt(Instant) - the most recent position in the stream that will return all events created on or after the given Instant. Note that some events may still have a timestamp earlier than this timestamp, as event creation and event storage isn't guaranteed to be the same.
createTokenSince(Duration) - similar to createTokenAt, but accepting an amount of time to go back.
So in your case, createTokenAt should do the trick.

making multiple http call after Switching between components

I have one query which is bit complex for me to explain but do ask me if you need any further details...
Angular version: 8.
Subject : issue while Switching components is circular.
Like from Component A. -> B -> A -> B
Brief details of my problem
From 'A' component I have selected couple of employees then click on the apply filter button so that I can switch to B component.
On every employees check-box clicked emitting event using service so that from 'B' component I should be able to fetch those selected employees and do further logic (like. API call)
Switching from A to B is working as expected because based on selected employees I am hitting the API to get their details.
But to reset the selected employees I am redirecting back to A component so that I can add more or remove employees...
Now the problem what I was facing is
As I have logic in component B, to hit the API and get the employees details.
The problem is after one round back from component 'B' on every selection one hit goes to API to get updated emp details.
I know it's happening bcz of EvenEmitter but what is the best possible solution for this so that on every event emit it should not make API call from 'A' untill and untill I am not in component B.
I have fixed my problem.. every time when we redirect to other route it will automatically call the ngOnDestroy where you can unsubscribe all the services that you have subscribed.
Syntax to unsubscribe:
Declare one property
ServiceSubscriptions: Subscription;
ngOnDestroy() {
this.ServiceSubscriptions.unsubscribe();
debugger;
}
Feel free to ask me if anybody has any query.

Android event tracking in Analytics Audiences

I have kind of a tricky question without an answer (I went through the documentation but did not find what I was looking for) :
I am tracking two specific events in my app, one is the start of a GPS tracking, the other one is the stop event. In Firebase Analytics, I am able to select those events in order to create an audience.
The audience I want is when an user triggers the start event of the GPS tracking process, but does not go through the whole process and does not trigger the stopevent.
So basically when I create the audience I have to select both startand stop event, but the thing is I actually have no value assigned to those events. For the moment, as a test case I told the audience to track if start > 0 and stop <= 0.
I suppose it is not going to work as expected. How should I track the event in the Android app, and how should I retrieve it in the audience creation ? By default, is my start event value is the number of times the event triggered ?
Thanks in advance,
Your question does not mention which SDK you are using (Android, iOS, etc. please make your question more precise) - I will assume it's Android.
When logging an event, you can set parameters. A parameter is made of a key and a value. If you want a value assigned to your event, you must use a predefined key : FirebaseAnalytics.Param.VALUE. In this case, the value is accumulated automatically for each event type.
The following snippet will do the work for your start event, stop will work the same way of course :
private void logStartEvent() {
Bundle bundle = new Bundle();
bundle.putInt(FirebaseAnalytics.Param.VALUE, 1);
firebaseAnalytics.logEvent("start", bundle);
}
Then you should be able to create an audience with start > 0 and stop <= 0
Hope this helps.

Keeping instances of a recurring event synchronized

I've been trying all day to figure out how to "rehydrate" instances of a recurring event from my app.
Let me explain the flow real quick:
User grants access to my app to edit their calendar
The app sets up a recurring event
The app subscribes to the /watch endpoint for that calendar
So far so good, now when the creator moves that event to another time, I get a notification on the webhook url, which is fine (well, sorta), it looks like this:
'x-goog-channel-id': 'my_specified_channel_id',
'x-goog-channel-expiration': 'Thu, 29 Sep 2016 12:58:10 GMT',
'x-goog-resource-state': 'exists',
'x-goog-message-number': '333384',
'x-goog-resource-id': 'some-resource-id', // This id apparently has nothing to do with any resources I know of
'x-goog-resource-uri': 'https://www.googleapis.com/.../resource-uri'
So I would figure that I could call https://www.googleapis.com/calendar/v3/calendars/primary/events/some-resource-id and get the updated resource, but the resource-id doesn't seem to have anything to do with any events in the calendar, nor is it the id of the calendar itself (I use the 'primary' keyword)
So I thought, I could as a work-around get all the instances of the recurring event using the https://www.googleapis.com/calendar/v3/calendars/primary/events/recurring-event-id/instances endpoint, but now the event that was moved is no longer part of that payload anymore. I'm guessing google removes the event from the parent event because it doesn't happen at the same time of day anymore (I haven't been able to confirm this anywhere)?
So what I'm asking is:
Am I interpreting x-goog-resource-id wrong?
Can someone confirm that once an event is edited from the google calendar app it looses its relation to the recurring parent event?
To answer my own question:
x-goog-resource-id is the identifier of the calendar, as that is the entity you're putting the watcher on
Once an event that is part of a recurring set is edited, it is no longer part of that set

Resources