rails compact array and NilClass - arrays

I have a Client model with a Date field: last_issue
A Client has_many :tickets and a Ticket has a Date field: invoice_date
A Client has_many :adverts and an Advert has a Date field: issue_date
I am trying to use array with compact to find and present the max date from these 3 items in the Client show view, but am getting errors when the Client does not have a Ticket or an Advert.
When I try to display the max date in my view using:
[#client.last_issue, #client.adverts.max.issue_date, #client.tickets.max.invoice_date].compact.max
it fails whenever a Client is missing one of the associated models.
I know that compact will remove nil elements, but I am struck on the cleanest way to deal with the missing values from the Nil associations that lead to errors such as NoMethodError: undefined method 'issue_date' for nil:NilClass

According to your description you only want to show the maximum date from the three types of object client.last_issue, client.adverts and client.tickets. Then save your app ressources and do not instantiate the tickets and adverts.
Instead load the plain maximum dates by using aggregation like:
[
#client.last_issue,
#client.adverts.maximum(:issue_date),
#client.tickets.maximum(:invoice_date)
].compact.max
You certanly want to move that snippet into a decorator.
Besides I'm not sure if actually meant to expect the minimum date (means the oldest), although you asked for maximum.

As a one off thing you could do this.
[#client.try(:last_issue), #client.try(:adverts).try(:max).try(:issue_date), #client.try(:tickets).try(:max).try(:invoice_date)].compact.try(:max)
Have you considered implementing this so that you aren't reaching so deep into the other objects? So that you only have to do 1 message to client for max invoice and issue date?

Related

QBO SDK PHP getting all deposits customer

I would like to know how to get all deposits of a target customer with the following SDK (https://github.com/intuit/QuickBooks-V3-PHP-SDK).
Is there an easier way than getting all deposits, then looping to extract the wanted customer's deposits?
Official QBO answer:
You can get complete deposit list by querying the “Query a deposit”
API end point. If we use filter in query, then it may return incorrect
results. Better you can iterate the response and add filter logic in
your code and get specified

Firebase pagination using a timestamp/date as the orderBy

I am struggling to get pagination working when I use a date (firebase timestamp) to retrieve data.
This is basically what I do:
let jobsRef = db.collection("jobs")
.orderBy('createdAt', 'desc')
.limit(QUERY_LIMIT);
jobsRef = jobsRef.startAfter(this.props.jobs[this.props.jobs.length - 1].createdAt);
However it seems that i get returned items sometimes that I have just already received. I am guessing because of similar dates?
So how could I basically return a list of jobs ordered by createdAt and have an offset/limit (pagination)?
createdAt looks like the timestamp type: 23 October 2020 at 17:26:31 UTC+2
When I log createdAt however I see this: {seconds: 1603537477, nanoseconds: 411000000}
Maybe I should be storing createdAt as a unix timestamp? Or what is the ideal way to deal with this?
Here is how it looks in the database (popup when i click edit on createdAt):
If multiple documents can have the same value for the field you're sorting on, passing in a value for that field is not guaranteed to point to a unique document. So you indeed may be passing in an ambiguous instruction, leading to an unwanted result.
When possible, I highly recommend passing the entire document to the Firestore API. This leaves it up to Firestore to take the necessary data from that document to uniquely/unambiguously find the anchor for your query.
So instead of:
jobsRef.startAfter(this.props.jobs[this.props.jobs.length - 1].createdAt);
Do:
jobsRef.startAfter(this.props.jobs[this.props.jobs.length - 1]);
I was facings a similar problem, after may hours I finally found a solution, all you need to do is converting that number to firestore's Timestamp
import { Timestamp }. from #angular/fire/firestore;
let createdAt: number = 56772766688383;
let timestamp = Timestamp.fromMillis(createdAt);
//then pass that to startAfter
startAfter(timestamp)

How to send an Email notification by day end using Rules with all the nodes published that day?

I am trying to achieve email notification . The condition is , it should go by end of the day with the current day published content list.
For the same I have tried couple of things using Rules, but stuck in between.
Any help?
I tried using rules, and I created a rule like so:
Events:
After updating existing content of type(content type name)
Cron maintenance tasks are performed
Condition: Data to compare: [node:field-img-status], Data value: Approve
When I am trying to add second condition to check if the node is published within 24hrs, I am unable to achieve it. When I add strtotime("-1 day"), I get an error like:
Wrong date format. Specify the date in the format 2017-05-10 08:17:18.
I tried date('Y-m-d h:i:s',strtotime("-1 day")) but I did not succeed.
Now I am trying one more method to achieve it using Views Rules which is suggested in this answer to the question about 'How to create a Drupal rule to check (on cron) a date field and if passed set field "status" to "ended"?'.
Below is a blueprint of how I'd get this to work ...
Step 1: Create a single eMail for each node that was published
Create a view (using Views) of all the nodes that were published the last 24 hours. Make sure to include a column in that view for the various data you want to be included about each node in your eMail later on.
Use Rules to create a rule with a Rules Action that consists of a "Rules Loop", in which its "list items" are actually the list of nodes that you want to be included in your eMail later on. To create this Rules Loop, use the Views Rules combined with a Views display type of "Views Rules", for the view that you created. Refer to my answer to "How to pass arguments to a view from Rules?" for way more details on how to use the Views Rules module.
For each list item in the Rules Loop of the previous step, you have access to all data for each column in the View you created. By using these data you could add an additional Rules Action (within the same Rules Loop) to send an appropriate eMail about the node being processed.
Step 2: Group all eMails in a single eMail
Obviously, the previous step creates a single eMail for each node that was published in the last 24 hours. If you only have a few nodes that may not be a real issue to worry about. But if you have dozens (or more?) of such nodes then you might want to consider consolidating all such eMails in a single eMail, which contains (in its eMail body) the complete list of nodes.
A possible solution to implement such consolidation, is similar to what is shown in the Rules example included in my answer to "How to concatenate all token values of a list in a single field within a Rules loop?". In your case, you could make it work like so:
Add some new Rules variable that will be used later on as part of the eMail body, before the start of your loop. Say you name the variable nodes_list_var_for_email_body.
Within your loop, for each iteration, prepend or append the value for each "list item" to that variable nodes_list_var_for_email_body.
Move the Rules Action to send an eMail outside your loop, and after the loop completed. And finetune the details (configuration) of your (new) "send an eMail" Rules Action. When doing so, you'll be able to select the token for nodes_list_var_for_email_body to include anywhere in your eMail body.
Step 3: Schedule the daily execution of your rule
Use the Rules Once per Day to schedule the daily execution of your rule. Refer to my answer to "How to limit the execution of a rule for sending an email to only run once in a day?" for way more details about this module.
Voilà, that's it ...
This is how I would achieve this:
Make some view which would list all nodes created today.
Make some end-point (from my module, check out: https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_menu/7.x)
It would call this view, and grab that node list (i.e. with views_get_view_result : https://api.drupal.org/api/views/views.module/function/views_get_view_result/7.x-3.x ), loop through the list, compose the email and send it.
Then I would set cron job to call that end-point at end of every day.

TypeError: can't compare datetime.date to DateProperty

I am trying to query if a certain date belongs to a specific range of dates. Source code example:
billing_period_found = BillingPeriod.query(
ndb.AND(
transaction.date > BillingPeriod.start_date,
transaction.date < BillingPeriod.end_date)
).get()
Data definition:
class Transaction(ndb.Model):
date = ndb.DateProperty(required=False)
class BillingPeriod(ndb.Model):
start_date = ndb.DateProperty(required=False)
end_date = ndb.DateProperty(required=False)
Getting the following error:
TypeError: can't compare datetime.date to DateProperty
The message error does make sense because datetime is different from DateProperty. However, as you can see, the definition for transaction.date is not datetime, so I am not getting where this attempt to convert datetime to date is coming from. Anyways - If I figure out how to convert datetime to DateProperty, I guess it would fix the problem.
Any ideas on how to solve this?
Thanks!
The App Engine datastore does not allow queries with inequalities on multiple properties (not a limitation of ndb, but of the underlying datastore). Selecting date-range entities that contain a certain date is a typical example of tasks that this makes it impossible to achieve in a single query.
Check out Optimizing a inequality query in ndb over two properties for an example of this question, and, in the answer, one suggestion that might work: query for (in your case) all BillingPeriod entities with end_date greater than the desired date, perhaps with a projection to just get their key and start_date; then, select out of those only those with start_date less than the desired date, in your own application (if you only want one of them, then a next over the iterator will stop as soon as it finds one).
Edit: the issue above is problem #1 with this code; once solved, problem #2 arises -- as clearly listed at https://cloud.google.com/appengine/docs/python/ndb/queries, the property is ndb queries is always on the left of the comparison operator. So, one can't do date < BillingPeriod.end_date, as that would have the property on the right; rather, one does BillingPeriod.end_date > date.

Define a custom ordering criteria in the relations() method

I have a model A that has a relationship of type HAS_MANY with model B.
B's attributes are:
id,
user_id,
message,
date,
parent_message_id
I need elements of model B to be ordered by date (descending), but in case the parent_message_id is different from null, the date to be taken into consideration should be the date corresponding to parent_message_id.
Is it possible to customize the criteria used to order the relation?
Ok, i solved this the following way: model A HAS_MANY model B, therefore, i redefined the relationships method to the following:
public function relations()
{
return array(
'messages' => array(self::HAS_MANY, 'WallMessages', 'liga_id',
'condition'=>'specific_post.parent_message_id IS NULL',
'order'=>'specific_post.date DESC',
'alias'=>'specific_post'),
);
}
Therefore, I only compare the date of those messages with no parent id. The downside is that I have to access each post's "child messages"... but well, couldn't find another workaround. Thanks all for your help!
I think it is only possible to sort elements according to the same column. However there might be a database ninja that could help you.
In an perfect world you could use the afterFind() method for any customization at any level, not only sorting, but also changing some values for others. It is not as fast as a plan order, maybe, but this way you release the MySQL server from a little load. Plus it is called automatically. Cheers

Resources