Sending push notification on firestore document field change - node.js

I have a Flutter app that lets users rent items from eachother with Firestore RTDB. In my rental document, I have a field status that determines the status of the rental (think of it like shipping an item, where items can have status of 'ordered', 'shipped', 'delivered' etc). My status variable is a number between 0 and 5, and each number represents a different phase. When the status variable changes, I want to notify the other user in the rental with a push notification. But I don't know which of the following methods is best.
The first way is to use a cloud function that triggers every time the rental document is updated. But I only check for the status field. It would look something like this:
exports.notify = functions.firestore.document('rentals/{rentalId}')
.onUpdate(async (snapshot, context) => {
const oldSnap = snapshot.before.data(); // previous document
const newSnap = snapshot.after.data(); // current document
// status changes from 0 to 1
if (oldSnap.status === 0 && newSnap.status === 1) {
// do something
}
})
The one downside I can think of is I would have to do another read to get the device push token of the other user. Also, for every rental document update this cloud function will trigger, and ultimately may not even need to execute in the first place
The other way would be to have a notifications collection that stores notifications, and have a cloud function that triggers when a new notification document is added. Then, on the client side, when the user taps a button, update the status in the rental as well as create a new notification document.
Firestore.instance
.collection('rentals')
.document(rentalId)
.updateData({'status': newStatus});
Firestore.instance.collection('notifications').add({
'title': title,
'body': body,
'pushToken': <TOKEN HERE>,
});
In comparison to method 1, this does an extra write instead of a read.
Which method is better?

Both approaches can technically work and are valid. Which one you choose is depending on the use-case, and (given that both can work here) on personal preference. That's why I'll simply highlight a few key differences below, and explain when I personally choose to use which one.
The first approach you describe is treating your database like a state machine, where each state and state transition has specific meaning. You then use Cloud Functions to trigger code in the state transition.
The second approach treats the database as a queue, where the presence of data indicates what needs to happen. So Cloud Functions then triggers on the simple presence of the document.
I typically use a queue based approach for production work, since it makes it very easy to see how much work is left to be done. Anything in your notifications collection is a notification that needs to be sent.
In the state-transition data model it is much harder to see this information easily. In fact, you'll need to add extra fields to the document in order to be able to get this list of "pending notifications". For example: rentals with a pending notification are rentals where the timestamp that the status changed from 0 to 1 (a field you'll need to add, e.g. status_1_timestamp) is smaller than the timestamp the last notification was sent (a field like notification_timestamp).
But I sometimes use the state transition approach too. Usually when I want to transform the existing document, or because it's just a cool use-case to show (as in most cases the Firebase/Firestore SDKs would not expose both the old and new state).
I'd probably pick the queue based approach here, but as said before: that's a personal preference for me based on the reasoning above. If those reasons don't apply to you, or you have different reasons, that can be fine too.

Related

Changing product price in Shopware 6 dynamically

I would like to change the price of a product based on the customer's selection. For example, I'm trying to build a small PDP widget to make customers able to choose the number of candles on a cake or write text on cakes and update the price accordingly. The docs only cover how to change the price by overwriting the cart's collector/processor but I don't want to use this method because of other plugins potentially overwriting the same service. So, is there are any other methods of changing the price of the products by subscribing to an event?
There are a few things you will need to consider in this one.
Firstly, you will need to save the user input data somewhere (amount of candles, text).
Possibly a separate database table that has a OneToMany relationship on cart line items. See this article. Und ya, this is also the part where you will hook into the onLineItemAdd event & save your user input to that table. You may as well also subscribe to the onLineItemUpdate for the same saving logic. You could do the same when removing the item from the cart, although that may not be necessary if you use database's "CASCADE on delete" when implementing your DB table. Meaning once the line item gets removed by the customer (deleted in the DB), your database entry gets deleted as well.
Afterwards, you can then use the extensions or otherwise called associations to pull this data on the cart page & the order pages. You can be a little more fancy here, if you look at all the frontend router calls, you will notice that Shopware sometimes passes "Criteria" class you can hook into.
public static function getSubscribedEvents(): array
{
return [
OrderRouteRequestEvent::class => 'alterCriteria',
DocumentOrderCriteriaEvent::class => 'alterCriteria',
];
}
public function alterCriteria(Event $event): void
{
if (method_exists($event, 'getCriteria')) {
$event->getCriteria()->addAssociation('lineItems.myExtension'); // check syntax, could be lineItem.
}
}
Now you can extend the twig templates to show your candles or text in the order page, cart page, document (invoice) pages.
Secondly, you will have to handle the price. This part will be easier now that you have data saved & being automatically pulled via criteria subscribers. If it's not possible to hook into those events all the time, you will still have an option to manually load your data.
I do not recommend modifying the price itself, but maybe you could look into adding a surcharge instead. Maybe this article will be helpful to understand the price flow. You could also see if there are any other plugins out there that implement surcharge logic to see it in action.

NetSuite: Calling an API in real time as field values get updated

I'm looking for a way (using SuiteScript 2.0) to handle real-time persistent (stored) field updates, where a field might have changed in NetSuite (for example a lead time was just updated), and it doesn't matter if a user saved the change, or some other automated process changed that field. I just want to be able to pick up on that change:
The moment that it's done, and
Without regard for who or what kicked it off (e.g. it could be a person, but it could also be an automated change from a workflow, or a formula on the field itself which pulls values from another field)
Doing some research I found some options that looked somewhat promising at first. One being the afterSubmit event in a client script, and the other being the fieldChanged event. My issue however is, from what I understood those only really seem to be triggered by a user manually going in and making those changes, but this is only one part of the puzzle and doesn't seem to cover changes made outside of the scope of the user making those changes. Is that correct however? Or would one of those events still be able to capture changes done to that field regardless of who (or what) initiated or triggered the change, and right at the moment the change was saved/ persisted to the database?
UserEvents are basically triggers. In their deployment records you can set the context in which they fire so you can get them to fire in all circumstances (called contexts in Netsuite) but one.
That circumstance is User Events are not fired for record saves made in User Event scripts. i.e., if an AfterSubmit UserEvent script loads, changes and saves your record a fresh user event will not be fired.

Alexa skill have user confirm slot values

I'm building Alexa skills using Node.js in a lambda function and can't find any tutorials on the best way to confirm the data I have in the slots. I got to the point that all slots now have data but would like to have Alexa read back the request and get a confirmation from the user before proceeding. What's the best & proper way to do this?
At first I thought to use an emit with :elicitSlot but then I would need a new slot to do this and it looks very hackish.
for example:
if(all slots have a valid value){
this.emit(':elicitSlot','confirm',"You're request is .... with data .... is this correct?");
}
if(user confirmed data is valid){
// do something
}else{
// the data was not correct get the right data
}
For the whole intent confirmation, check here. For only slot confirmation, check here.
Also, for your followup question,
can the confirmation for the skill and slots be fine tuned for example if one of the slots is something like a name and alexa knows 100% what name I said can it skip the confirmation?
Short answer - of course you can if you do not maintain the dialog. However, it's strongly discouraged to rely on that.
In order to maintain a dialog, you have to monitor dialogState attribute of the intent request, and as long as it's not in state COMPLETED send response with attribute directives as [{'type': 'Dialog.Delegate'}] to keep it flowing. You can maintain finer control of the dialog - consult this doc. Moreover, you are strongly suggested to omit outputSpeech and reprompt in those responses, otherwise Alexa gets upset. Once dialog status is COMPLETED, you get confirmationStatus (for both Intent and slots) - SUCCESS(?)/DENIED/NONE. If the confirmation is not successful. I have seen multiple matches being sent as reply. However, when successful, only the matched slot value is returned.
P.S. I have had this weird issue. When Alexa is asking for confirmation for one slot value, if I deliberately decline twice in a row, it gives up and does nothing! Although, pretty much 99% of the time Alexa was spot on.
P.P.S. Turns out 2 attempts was a hard limitation from Alexa. This is supposed to be improved in next iterations.

Breaking down 1 calendar event into smaller events in SharePoint

I'm trying to create some sort of reservation system in SharePoint using a calendar list. It's been recommend to me to create events and add a column which allows a user to claim it. From there, claimed events would change color and only those who've claimed the event would have permission to unclaim the event.
This is what it would look like (see alternative option):
What I'd like to be able to do though, is instead of having to create three events like shown in the alternative option, creating 1 event (see original) and have that be broken down into 3 events or more, maybe using some form of drop down asking for intervals (ie. 15m, 30m, 1h). Based on the selected interval, it'd break the event accordingly.
A possible solution is in your main event you add another field named Interval.
The you design a workflow when you create the event that creates new events according to the interval specified using a while loop while incrementing the start time with your interval.
Those new events have a content type with a field named UserClaimed. you then associate another workflow to those new events that checks for that field and changes permissions on the event to only allow modifications of that event to the user specified.
This is the general idea, the implementation should not be that hard
just a thought -
I mean, the reason i think you want the events to pre-exist is so that users can easily create them in the correct time slot (rather than clicking the new item menu, which throws them away from the calendar view/context). Is that right?
If so, allow me to offer you this scenario:
If you are using KWizCom's Calendar Plus web part (yeah, I work for KWizCom...) it allows you to type in the event in the calendar itself directly.
Something simple like: "1pm-2:30pm Training meeting with Josh"
check the demo video here: http://www.kwizcom.com/sharepoint-add-ons/sharepoint-calendar-plus-web-part/overview/
Also, drag and drop events in the calendar to move them easily, and it also supports color coding events based on categories (meta data, views, sources, etc.).
The one thing you will need to develop is the unique meeting logic, and owner permissions.
meaning, an event handler that does not accept 2 meetings at the same time for the same room (define the unique resource field, if any), and the logic that allows only the person who created an event to edit or delete it.
ping me, I can help with the event handler - perhaps we can add this to our product, this is actually a cool idea. my work mail is shai at kwizcom dot com

How to set up an workflow in SharePoint to only work when a specific field is changed and not everytime the item is edited?

The issue is that everytime an item is edited/changed all the users who are set up to receive updates are notified. I need the workflow to run only when a specific field is changed disregarding the others. For example if my item contains these values (Customer Name; Acc#; Contact Person; Address;) - I need the workflow to work only when the Acc# is changed and only if it is changed, no metter how many times the other fields are changed.
Thanks,
A quick way to do it is to have the workflow store the value each time the it starts, then tell it to wait until the field != the stored value. This may not work in all cases, but it could be enough for your purposes.
You should create an event handler to run on your content type or library. You can then check the before and after properties of the fields you mention. Then use the event handler to initiate the workflow if required.

Resources