Sales invoice timesheet Sorting

Running:
ERPNext: v12.6.0 (version-12)
Frappe Framework: v12.4.1 (version-12)

How can I sort the entries in the Sale Invoice Timesheet table by start date?

Thank you!

Do you want to sort the timesheets by date as you enter new rows to the table or sort them by date after entry , prior to printing the invoice?

Thank you for your reply!

I added a “Print Timesheets” checkbox to the Sales Invoice form. I have a custom Print Format for sales invoices that prints a table of the timesheets if that check box is selected.

The problem I am having is that I would like that table of timesheets to be sorted by starting date.

I hope that helps.

Thank you!

Try to add End Date to the Sales Invoice Timesheet form, set it as the Sort Field, check List view. see if it works with the print format.

I made the modification that you suggested, however, when I create a new Sales Invoice, the timesheet table is populated but the Start and End Date fields are empty. Is there something I need to do to get those fields populated?

I ran for good measure:

bench clear-cache
bench clear-website-cache
bench restart

Thank you!

My field linking skills are not well honed. As a workaround, hopefully temporary, A timesheet report could be fashioned that will select and sort the data for printing.

A Google search using linking fields erpnext as a search term may provide some useful info.

1 Like

Thanks for the suggestion, I will check it out and report back

I’ve tried using fetch from as @lasalesi mentions in this post, without success. It may be that a script will be needed.

https://discuss.frappe.io/t/how-does-a-field-fetch-data/53973/3

I tried adding a linked field to the Sales Invoice Timesheet form for field start_date linked to Timesheets DocType.

The field was still empty in list view but if I expanded the row detail and clicked in the field, it gave me a drop down of timesheet tasks. What???

I am not sure why its not working. I think you’re right. I may have to do some scripting.

Thanks for continuing to try to figure it out. Its a head scratcher!

If you only need the print format to be sorted, consider gathering the data and sorting in Jinja… Something like

<!-- compile dict with dates -->
{% set ts_sorter = {} %}
{% for t in timesheets %}
    {% set source_ts = frappe.get_doc("Timesheet", t.time_sheet) %}
    {% if ts_sorter[t.idx|string].update({'timesheet': t.time_sheet, 'date': source_ts.start_date}) %}{% endif %}
{% endfor %}
<!-- output -->
{% for ts in ts_sorter|sort(attribute='date') %}
    <p>{{ ts.date }} - {{ ts.timesheet }}</p>
{% endfor %}

Extend and format to your liking… This will not affect the data but only aggregate at print time.

1 Like

Thank you for your suggestion. This makes complete sense!

I am pretty new to Jinja2 and I can understand all of your code and what it is doing, except for this line:

{% if ts_sorter[t.idx].update({'timesheet': t.time_sheet, 'date': source_ts.start_date}) %}{% endif %}

I think that this is making a new dict combining the values of t.time_sheet with source_ts.start_date. source_ts is getting its data from the frappe.get_doc. This provides the field start_date to sort on.

What I don’t understand is this ts_sorter[t.idx].update() - what is the t.idx referencing? I can’t seem to find anything on that syntax and when I use your code as is, I get this error

UndefinedError: dict object has no element 1

Any help you could provide is much appreciated!

Thanks for you feedback. Jinja has no built-in function to execute methods, this is why you can trick it to do so with a if-call.

In this case, the issue is that t.idx was a number and should have been a string. This should resolve this:

{% if ts_sorter[t.idx|string].update({'timesheet': t.time_sheet, 'date': source_ts.start_date}) %}{% endif %}

Then, the key should be created (as string)…

Thanks for the update!

I have placed this block of code in my Sales Invoice Print Format:

{% set ts_sorter = {} %}
{% for t in timesheets %}
    {% set source_ts = frappe.get_doc("Timesheet", t.time_sheet) %}
    {% if ts_sorter[t.idx|string].update({'timesheet': t.time_sheet, 'date': source_ts.start_date}) %}{% endif %}
{% endfor %}
<!-- output -->
{% for ts in ts_sorter|sort(attribute='date') %}
    <p>{{ ts.date }} - {{ ts.timesheet }}</p>
{% endfor %}

It doesn’t print any timesheets and no errors.

If I modify

{% for t in timesheets %}

To include doc.timesheets

{% for t in doc.timesheets %}

I then get this error:

UndefinedError: 'dict object' has no attribute u'1'

It looks like the “|string” did change t.idx to a string rather than a number but it still doesn’t like it.

did you get this working?