How to implement a 'past due' notification in Meteor.js - node.js

I have a "task" model (collection) in my app, it has a due date and I'd like to send out notifications once the task is past due.
How should I implement the "past due" property so the system can detect "past due" at any time?
Do I set up cron job to check every minute or is there a better way?

I'd recommend using synced-cron for this. It has a nice interface, and if you expand to multiple instances, you don't have to worry about each instance trying to execute the task. Here is an example of how you could use it:
SyncedCron.add({
name: 'Notify users about past-due tasks',
schedule: function(parser) {
// check every two minutes
return parser.recur().on(2).minute();
},
job: function() {
if(Tasks.find(dueAt: {$lte: new Date}).count())
emailUsersAboutPastDueTasks()
}
});
Of course, you'd also want to record which users had been notified or run this less frequently so your users don't get bombarded with notifications.

Related

Intercepting an assignment to a table relation field

I created a one-to one relationship between two tables in strapi.
As an example, suppose that Bob currently has a job, say messenger, if we assign Bob’s Job to secretary, Strapi simply reassigns the new Job, without warning that Bob was already in a job
If a person is not in a current job, it’s job would be ‘none’
I’d like to forbid the reassignment of the job, if Bob was already in a job (the user would have to assign the Bob's job to ‘none’ before assigning a new job)
In strapi, what would be the right way to forbid it (checking if the current job is not ‘none’, and, if it’s the case, stopping the assignment), using a service, a controller or a lifecycle hook?
One way to handle this in Strapi would be to use a lifecycle hook. Lifecycle hooks allow you to perform specific actions at certain stages of the CRUD operations (create, update, delete) on a model. In this case, you can use the beforeUpdate hook to check if the current job is not none before allowing the assignment of a new job:
// api/person/models/Person.js
module.exports = {
lifecycles: {
// This hook will be called before updating a person
async beforeUpdate(params, data) {
// Check if the current job is not 'none'
if (params.current.job !== 'none') {
// If the current job is not 'none', throw an error
throw new Error('Cannot reassign a job to a person who already has a job');
}
}
}
};
You can also use a service or a controller to handle this logic, but using a lifecycle hook allows you to centralize this logic and keep it separate from your business logic.

Call NetSuite native calculate shipping button by script?

I am Using User event aftersubmit on Sales order to add/update line item. As soon as line item updated shipping cost should recalculate. I am using real time shipping method and cost.
Now If I change item manually, I need to click ‘calculate’ button under Shipping tab, which calculate and update shipping cost. But when I add/update line item using user event, it became ZERO.
Is there any way to calculate shipping cost by script? Is there any way to run functionality of native ‘calculate’ shipping cost button by script?
For your case i.e User event, we need a dynamic record to do this, so load a dynamic Sales Order record, using id from the Standard record in User Event context:-
var drSalesOrder = record.load({type: record.Type.SALES_ORDER, id: salesOrderId, isDynamic: true});
Then doing the following operations in this order(will calculate and set the shipping cost on the order):-
drSalesOrder.setValue({fieldId: 'shipcarrier', value: 'nonups'});
drSalesOrder.setValue({fieldId: 'shipmethod', value: SHIP_ITEMS.FedEx_Ground}); // your shipmethod id here
drSalesOrder.setValue({fieldId: 'shippingcostoverridden', value: true});
drSalesOrder.save({ignoreMandatoryFields: true, enableSourcing: true});
Not natively. We do the calculation by overriding the page element on pageInit, and adding other operations before running the native NS API call.
I know this question is old but on my case I cant get these answers to work (although its the same what is in SuiteAnswer), and I was stuck for some hours trying to retrigger the computation of shipping cost.
What I did is to call the calculateRates() Netsuite's function on saveRecord function in client script. I am lucky the client does not require this in the server. Although its not the correct way but its more okay than not working :)
const saveRecord = (context) => { Shipping.calculateRates(); return true; }
Hope this helps. Thank you!

Twilio Taskrouter: how to implement a "do not contact" list of WorkerSids in Workflow Configuration?

This question is similar to this one I previously asked, in that I want the task to perform a Target Worker Expression check on a list of WorkerSids that I've added as one of the task's attributes. But I think this problem is different enough to warrant its own question.
My goal is to associate a "do not contact" list of WorkerSids with a Task; these are workers who should not be assigned the task (maybe the customer previously had a bad interaction with them).
I have the following workflow configuration:
{
"task_routing":{
"filters":[
{
"filter_friendly_name":"don't call self",
"expression":"1==1",
"targets":[
{
"queue":queueSid,
"expression":"(task.caller!=worker.contact_uri) and (worker.sid not in task.do_not_contact)",
"skip_if": "workers.available == 0"
},
{
"queue":automaticQueueSid
}
]
}
],
"default_filter":{
"queue":queueSid
}
}
}
When I create a task, checking the Twilio Console, I can see that the task has the following attributes:
{"from_country":"US","do_not_contact":["WORKER_SID1_HERE","WORKER_SID_2_HERE"],
... bunch of other attributes...
}
So I know that the task has successfully been assigned the array of WorkerSids as one of its attributes.
There is only one worker who is Idle and whose attributes match the queueSid TaskQueue. That worker's SID is WORKER_SID1_HERE, so the only available worker is ineligible to receive the task reservation. So what should happen is that the first target expression worker.sid not in task.do_not_contact returns false, and the task falls through to the automaticQueueSid TaskQueue.
Instead, the task remains in queueSid unassigned. The following sequence of Taskrouter events are logged:
task-queue.entered
Task TASK_SID entered TaskQueue QUEUESID_QUEUENAME
task.created
Task TASK_SID created
workflow.target-matched
Task TASK_SID matched a workflow target
workflow.entered
Task TASK_SID entered Workflow WORKFLOW_NAME
What do I need to change to get the desired workflow behavior?
Changing the skip_if to
"skip_if": "1==1"
solved the problem.
Per Twilio developer support, the worker.sid not in task.do_not_contact returns true for workers who are unavailable but are also not in do_not_contact, so the target expression still returns a set of workers, and then the "skip_if": "workers.available==0" returns false because technically there is one "available" worker--the one who is ineligible due to the do_not_contact list.
What's needed is for the skip_if to always return true, so when the first target processes the task without assigning it, the skip_if then passes it to the next target, as discussed in Taskrouter Workflow documentation:
"TaskRouter will only skip a routing step in a Workflow if:
No Reservations are immediately created when a Task enters the routing step
The Skip Timeout expression evaluates to true"

EventSourcing for Aggregates that rely on other aggregates

I'm currently working on a calendar system written in an EventSource style.
What I'm currently struggling with is how to create an event which create lots of smaller events and how to store the other events in a way which will allow them to be replayed.
For example I may trigger an CreateReminderSchedule which then triggers the construction of many smaller events such as CreateReminder.
{
id:1
description: "Clean room",
weekdays:[5]
start: 01.12.2018,
end: 01.12.2018
type: CREATEREMINDERSCHEDULE
}
This will then create loads of CreateReminder aggregates with different ids so you can edit the smaller ones i.e.
{
id:2
description: "Clean room"
date: 07.12.2018
type: CREATEREMINDER
scheduleId: 1
}
So to me one problem is when I replay all the events the createReminderSchedule will then retrigger createReminderEvents which mean I'll have more reminders than needed during the replay.
Is the answer to remove the smaller events and just have one big create event listing all the ids of the reminders within the event like:
{
id:1
description: "Clean room",
weekdays:[5]
start: 01.12.2018,
end: 01.12.2018
type: CREATEREMINDERSCHEDULE
reminderIds:[2,3,4,5,...]
}
But if i do this way then I won't have the base event for all my reminder aggregates.
Note the reminders must be aware of the reminderSchedule so I can later change the reminderSchedule to update all the reminders related to that reminderschedule
Perhaps you are confusing events with commands. You could have a command that is processed to create your reminders (in the form of events, ie ReminderCreated) which is then applied to your aggregate to create your reminder-objects. This state is recreated in the same way every time you replay your events from its source.

Modeling time-based application in NodeJs

Im developing an auction style web app, where products are available for a certain period of time.
I would like to know how would you model that.
So far, what I've done is storing products in DB:
{
...
id: p001,
name: Product 1,
expire_date: 'Mon Oct 7 2013 01:23:45 UTC',
...
}
Whenever a client requests that product, I test *current_date < expire_date*.
If true, I show the product data and, client side, a countdown timer. If the timer reaches 0, I disable the related controls.
But, server side, there are some operations that needs to be done even if nobody has requested that product, for example, notify the owner that his product has ended.
I could scan the whole collection of products on each request, but seems cumbersome to me.
I thought on triggering a routine with cron every n minutes, but would like to know if you can think on any better solutions.
Thank you!
Some thoughts:
Index the expire_date field. You'll want to if you're scanning for auction items older than a certain date.
Consider adding a second field that is expired (or active) so you can also do other types of non-date searches (as you can always, and should anyway, reject auctions that have expired).
Assuming you add a second field active for example, you can further limit the scans to be only those auction items that are active and beyond the expiration date. Consider a compound index for those cases. (As over time, you'll have more an more expired items you don't need to scan through for example).
Yes, you should add a timed task using your favorite technique to scan for expired auctions. There are lots of ways to do this -- your infrastructure will help determine what makes sense.
Keep a local cache of current auction items in memory if possible to make scanning efficient as possible. There's no reason to hit the database if nothing is expiring.
Again, always check when retrieving from the database to confirm that items are still active -- as there easily could be race conditions where expired items may expire while being retrieved for display.
You'll possible want to store the state of status e-mails, etc. in the database so that any server restarts, etc. are properly handled.
It might be something like:
{
...
id: p001,
name: "Product 1",
expire_date: ISODate("Mon Oct 7 2013 01:23:45 UTC"),
active: true,
...
}
// console
db.auctions.esureIndex({expire_date: -1, active: 1})
// javascript idea:
var theExpirationDate = new Date(2013, 10, 06, 0, 0, 0);
db.auctions.find({ expire_date : { "$lte" : theExpirationDate }, active: true })
Scanning the entire collection on each request sounds like a huge waste of processing time.
I would use something like pm2 to handle both keeping track of your main server process as well as running periodic tasks with its built-in cron-like functionality.

Resources