Split function in custom designs

twig split function

Hi,
in the notes of a product I have different lines, each line begins with a dash (‘-’). In my template for the invoice I would like to generate in the product table different list items from the notes by using the split function in twig as follows:

<td>
   <p>{{ item.product_key }}</p>
   <ul>
      {% set temp_notes = item.notes|split('-') %}
      {% for note in temp_notes %}
         <li> {{ note }} </li>
      {% endfor %}
   </ul>
</td>

But for some reason the split function does not work. It seems like

{% set temp_notes = item.notes|split('-') %}

returns nothing. The dash ist not the problem. I also tried different characters to seperat.I also tried

{% set temp_notes = item.notes|split('') %}

which should result in a separation after every character. But again the split returns nothing.

Any ideas or hints?

UPDATE:

I learnt that the split function is not active. I wonder if this is true only for the self-hosted version or for the hosted version too.
I am surprised that the split function is not active. If the twig module is used anyway, why is it disabled.

Another problem

I built a custom design with some statement in the <ninja> environment. In the preview everything works just fine and looks as I wanted it. The preview is based on a real quote. But when I look at the pdf of my quote in “normal operation” it looks like everything inside the ninja section is skipped.
I do not understand that. I would expect that both the preview and the real generation use the same pdf engine.

Since my code works fine in the preview I think I have no syntax errors. This is the coede which is completely skipped:

<ninja>
               {% set invoice = invoices|first %}
               
               {% if invoice %}
  
                  <table width="100%" cellspacing="0px" cellpadding="0px" class="tp-table01">
                     <thead>
                        <tr>
                           <th> $product.product1_label </th>
                           <th> $item_label/$product.description_label </th>
                           <th> $product.product2_label </th>
                           <th> $product.unit_cost_label </th>
                           <th> $quantity_label </th>
                           <th> $product.discount_label</th>
                           <th> $product.line_total_label</th>
                        </tr>
                     </thead>
                     <tbody>
                     {% for item in invoice.line_items|filter(item => item.type_id == 1) %}
                        <tr>
                           <td>{{ item.custom_value1 }}</td>
                           <td>
                              <p class="tp-item">{{ item.product_key }}</p>
                              <p>{{ item.notes|nl2br }} </p>
                           </td>
                           <td>{{ item.custom_value2 }} </td>
                           <td>{{ item.cost }} </td>
                           <td>{{ item.quantity }} </td>
                           <td>{{ item.discount }} </td>
                           <td>{{ item.line_total }} </td>
                        </tr>
                        
                     {% endfor %}
                     </tbody>
                  </table>
               {% endif %}
</ninja>

Thanks for any hints

Hi,

As mentioned in the other post I think your best option is to send an email asking the split function to be enabled. For security reasons all methods are disabled, we can enable them on a case by case basis.

Note: if you’d prefer you can request this change on GitHub by creating an issue.

I asked about twig-features, too. @david gave me some answers about it. If I remember correctly, it’s a matter of performance and security that some filters/features are not enabled by “default”.

About your twig-coding-problem: Well, your code is about invoices but not for quotes. If you want twig to append to quotes, you must write such code as:

{% if quotes %}
  {% set quote = quotes | first %}    {# not invoices, because this only applies to invoices #}
    [here your further code, but be beware that sometimes $variabes may not work]
{% endif %}

If you want a design and a ninja-code within apply to more than just one entity, do something like this:

<ninja>
{% if quotes %}
  {% set entity = quotes | first %}
{% elseif invoices %}
  {% set entity = invoices | first %}
{% elseif credits %}
  {% set entity = credits | first %}
(…)
{% endif %}

{{ entity.name }} {# to display the entity-name of the document for example #}

</ninja>

EDIT: Yes, and this what Hillel just said. :slight_smile:

1 Like

Hi There,

We have a security policy in place for all twig filters. I’ll look into split now and if it ok, i’ll get this merged in for both self/hosted.

Hi David,
thanks a lot for the Info. Also thanks to Schmitti!

One more question for my understanding:
Is there a principle difference between “designs” sand “templates” regarding to what is can I use there? To make my question more precise:
Does ninja work only in templates or can I use it in designs too?

Works in designs very well!

For example I made two very complex designs by using Twig which allows me to show different tables for quotes and invoices and to have free-text-lines or just comment-lines with italic font-format and so on. But it was damn a hard way to have this working as it should be.

Here’s what I mean:
In quotes twig helps me to offer alternative products or to add commentation-lines into product-tables.

And I made a lot of other complications, too (like a genuin note for the delivery date if none is explicitely given as custom-fieldX).

1 Like

Thanks for the help and the clarification. But:

If I chose in the designe area explicitly the entity: Quote and chose real data from a quote I set up everything works fine with

<ninja>
  {% set invoice = invoices | first %}
  {% if invoice %}
   ...
  {% for item in invoice.line_items|filter(item => item.type_id == 1) %}
  ..
  {% endfor %}
{% andif %}
</ninja>

but if I use:

<ninja>
  {% set quote = quotes | first %}
  {% if quote %}
   ...
  {% for item in quote.line_items|filter(item => item.type_id == 1) %}
  ..
  {% endfor %}
{% andif %}
</ninja>

I get nothing anymore.

In the user guide I can find the “invoice” item here: Free Source Available Invoicing, Expenses & Time-Tracking | Invoice Ninja.

I understand it that way that all line_items attributes can be found in invoices. It seems to me that there is no such thing as quote.lime_items? That also complies with the fact that I do get nothing from quotes.line_items in the statement above.

Anyway, the statements with quote(s)instead of invoice(es)do not work.

Despite all the technical issue it is still not comprehensible to me that the code works in the design tool, but not in real life. I guess that I am not the only one who uses quotes the way I try to do.

Is there probable any setting that I did miss?

Any ideas/support from IN 's side?
It still looks like a bug to me.

If you’re using the hosted platform you can send an email to [email protected] to ask.

I think quotes only work within real quotes, not in the editor.

You must be aware of using the right keywords/variables:

<ninja>
  {% set invoice = invoices | first %}
  {% if invoice %}
   ...
  {% for item in invoice.line_items|filter(item => item.type_id == 1) %}
  ..
  {% endfor %}
{% andif %}
</ninja>

Here’s a mistake in line 3 for example. It must be “if invoices”, not “invoice”.
Ahm, I don’t know, but does “andif” is a correct and implemented twig-code?

I come back to the issue.

In the meantime I paid IN for a design (!), but that still doese not work.
It is still the same thing what I described here and what looks more like a bug then a coding issue. The code works in the design editing preview but not when generating a real quote.

The item table is simply not built when I use it for quotes.

This is the original code from IN:

<table>
<thead>..</thead>
  <tbody>
               <ninja>
               {% set quote = invoices | first %}
               {% if quote %}       
                     {% for item in quote.line_items|filter(item => item.type_id == 1) %}
                        <tr>
                           <td>{{ item.custom_value1 }}</td>
                           <td>
                              <p class="tp-item">{{ item.product_key }}</p>
                              <p>{{ item.notes }} </p>
                           </td>
                           <td>{{ item.custom_value2 }} </td>
                           <td>{{ item.cost }} </td>
                           <td>{{ item.quantity }} </td>
                           <!-- <td>{{ item.discount }} </td> -->
                           <td>{{ item.line_total }} </td>
                        </tr>
                     {% endfor %}   
               {% endif %}
               </ninja>             
  </tbody>
</table>

For whatever reason the support keeps ignoring to address the core issue (with their own code I paid for). It is easy for everyone to reproduce the issue.

Any suggestions from the community?

This cannot work for quotes, because you set as „the“ quote the first invoice of the invoice-array. It must be „set quote = quotes | first“.

If you want a design for both quotes and invoices and maybe more entities, try something like this:

For every ninja-section at first:

{% if invoices %}
    {% set entity = invoices | first %}
{% elseif quotes %}
    {% set entity = quotes | first %}
{% elseif …
…
{% endif %}

[from here on your twig-code, and instead of invoice, quote or whatever use entity]

— EDIT #2
OK, now I’m at my PC.

Some more information: TWIG works this way:

To use TWIG code on entity-linked variables it’s necessary to first define the entity, on which the variable is based (for example: {{ invoice.date }} to show the date of the invoice).

So the code for this in general would look like this:

<ninja>
     {% set entity = invoices | first %}
     {{ entity.date }}
</ninja>

What have I done here? First I defined a variable named entity and mapped the first invoice of an array of one or more invoices to it. Why “one or more”? Because TWIG-templates can be used for more than one entities (invoices, tasks, projects and so on) if you select more than one at once in Invoice Ninja’s GUI. It’s like this:

Selected invoices:
Invoice No. 0001, 0002, 0003, 0005

Used template → template “invoice list” (which is meant to list all the invoice-numbers and invoice-dates in one document for example).

However, used in a design which is only used for invoices but nothing else you’ll still must define the variable which I named “entity” up there.

If you want to use this design for more than just invoices or something else, TWIG gives you the ability to choose which code shall be used for which document-entity.

If you want different output for invoices and quotes, do so:

<ninja>
<!-- This is for invoices -->
  {% if invoices %}
    <p>This is an invoice.</p>
  {% endif %}

<!-- This is for quotes -->
  {% if quotes %}
    <p>This is a quote.</p>
  {% endif % }}
</ninja>

So if the design is used for an invoice, it will output “This is an invoice”. For quotes: “This is a quote.”.

Now, if you want to use variables which are valid for more than just one kind of document/entity, you can do something like this:

<ninja>
{% if invoices %}
  {% set entity = invoices | first %}
{% elseif quotes %}
  {% set entity = quotes | first %}
{% elseif credits %}
  {% set entity = credits | first %}
{% endif %}

The date of this document is {{ entity.date }}
</ninja>

So now the design will always print “The date of this document is”. But it will only print the document-date in case of the design was used with an invoice, quote or credit, but not with a purchase, because I did not define the variable “entity” in case that the document is a purchase (no “if/elseif purchases”).

1 Like

Hi Schmitti, thanks you so much for the lesson. I highly appreciate that!
I will try and report.