Rechnung oder Lieferschein als PDF

Hallo Community,


ich würde gerne je Bestellung oder Retoure/Refund ein einzelnes Rechnungsdokument erzeugen. Ist es möglich, aus einem Spreadsheet für jeden einzelnen Datensatz ein PDF zu erzeugen? Falls nein, welche Alternativen gibt es? Ich bin am überlegen, ob es evtl. Sinn macht, eine Liste mit Bestellungen zu erzeugen und dann für jeden Eintrag in der Liste einen Webhook Flow via SpreadsheetUrlDownload Step aufzurufen?

Mit dem Step HTML2PDF Step kann man PDFs erzeugen. Dieser erwartet eine FILELIST mit HTML-Dateien. Diese Files könnte man sich per TextHTMLWriterMultiOutput (Handbuch) aus den Spreadsheet-Daten erzeugen und dann an den HTML2PDF übergeben.

Vielen Dank für den Tip! Wie würde man es denn machen, wenn man je Bestellung die Liefer und Rechnungsadresse und zusätzlich die jeweiligen Artikel, Versandkosten und Rabatte/Gutscheine in der Bestellung auflisten möchte? Wir nutzen ja zum Import den shopifyGetOrders Step und hier werden die entsprechenden Daten in einem Master-Child Datastore abgebildet?


So wie ich Synesty bis jetzt kenne, müsste ich für die jeweiligen Daten den passenden Datastore abfragen und jeweils in eine eigene Spreadsheet schreiben und dann innerhalb dem <#list> Aufruf für die Order im Template noch mal einen <#list> Aufruf auf das LineItem Spreadsheet machen und entsprechend filtern, ob denn die lineitems_orderid der order_id der aktuellen Order-Zeile entspricht, also etwa in der Art:

<#list spreadsheet@SearchMasterDatastore_1.getRows() as row>
<#assign order_id = row.get("id")>
<#assign customer_id = row.get("customer_id")>
Rechnung XYZ für Kunde ${customer_id!} zu Bestellung ${order_id!}
Artikel:
<#list spreadsheet@SearchChildDatastore_2.getRows() as articlerow>
<#if articlerow.get("lineitems_orderid") == order_id>
${articlerow.get('lineitems_title')} - ${articlerow.get('lineitems_price')} 
</#if>
</#list>
</#list>

Und: wie kann ich den Dateinamen mit Daten aus dem Input Spreadsheet anreichern? Wir müssen z.B. eine eigene Rechnungsnummer erzeugen, welche ich in das Input Spreadsheet laden kann.

Eine weitere Frage habe ich noch: wie kann ich im HTML2PDF Output Bilder inkludieren? Z.B. Marken- oder Shoplogo?


Hier mal ihr Beispiel leicht adaptiert für den TextHTMLWriterMultioutput:


<#list spreadsheet@SearchMasterDatastore_1.getRows() as row>
 
  <#assign htmlfilecontent>

  <#assign order_id = row.get("id")>
  <#assign customer_id = row.get("customer_id")>
   Rechnung XYZ für Kunde ${customer_id!} zu Bestellung ${order_id!}
   Artikel:
  <#list row.children() as articlerow>
   <#if articlerow.get("lineitems_orderid") == order_id>
    ${articlerow.get('lineitems_title')} - ${articlerow.get('lineitems_price')} 
   </#if>
  </#list>


 
  </#assign>
 
  <#assign htmlfilename = "order"+row.get("identifier") + ".html" />
  ${output(htmlfilecontent, htmlfilename, "UTF-8")}
   
</#list>



Folgendes wäre hervorzuheben:

  • Die letzten beiden Zeilen zeigen, wie man den Dateinamen der entstehenden Datei anpasst.
  • Um auf die Child-Zeilen einer Order zuzugreifen kann man <#list row.children() as articlerow> nehmen (siehe hier)
  • Bilder sollten per IMG Tag und URL eingefügt werden. Die URL muss öffentlich erreichbar sein z.B. <img src="http://meinewebsite.de/bild.jpg" />



Sehr geil! Ich denke das hilft uns definitiv weiter.


Eine letzte Frage noch: wir würden die Dateien gerne auch gleich per E-Mail (via SMTP Gateway) verschicken, wie könnte man den E-Mail Text aus Daten der Bestellung anreichern? Z.B. Name, Bestell- und Rechnungsnummer?


Beispiel:


Sehr geehrter Herr Daniel Zauberhuber,


vielen Dank für Ihre Bestellung ${order_name} im Shop. Anbei finden Sie Ihre Rechnung ${rechnungsnummer}

Versand mehrerer Emails ist mit Synesty selbst nicht möglich. Dafür empfehlen wir auf Massenemailversand spezialisierte Dienste wie z.B. https://dev.mailjet.com/email/guides/send-api-v31/#send-with-attached-files

Wir haben das Beispiel aber gerade mal intern diskutiert und haben da evtl. noch eine "Lücke". Und zwar ist es aktuell recht "hakelig" wie man Daten aus einem Spreadsheet mit einer Dateiliste (FILELIST) zusammenführen kann, um z.B. den Dateianhang als Base64 an soetwas wie die Mailjet API zu schicken. Wir haben aber intern schon ein paar Lösungsideen diskutiert, die wir mit einplanen. Für die Art und Weise wie Mailjet das macht (Datei als Base64 String) gäbe es einen Workaround. Wenn das von Interesse ist, bitte kurz Bescheid sagen, dann können wir das hier mal beschreiben.



Hallo, ich habe ein Problem mit den Daten aus den Children (zumindest in der Vorschau).


Um die Children-Daten auszulesen, verwende ich folgenden Code:

<#if (order.children()?? && order.children()?size > 0) >
  <#assign line_number_counter = 1>
    <#list order.children() as lineitems>
		datatstore: ${lineitems.get('datastorename')!}
		identifier: ${lineitems.get('identifier')!}
		master_identifier: ${lineitems.get('master_identifier')!}
		id: ${lineitems.get('id')!}
 	    <#if lineitems.get('datastorename') == 'shopifyOrderItems'>
			<#assign sku = lineitems.get("line_items_sku")>
        ${line_number_counter!} - ${sku} - ${lineitems.get('line_items_title')!} - ${lineitems.get('line_items_quantity')!} - ${lineitems.get('line_items_price')!} - ${lineitems.get('line_items_tax_lines_rate')!} ${(lineitems.get('line_items_tax_lines_price')!)} - ${lineitems.get("line_items_quantity")!} ${lineitems.get('line_items_price')!}
        <#assign line_number_counter += 1>
  	  </#if>
    </#list>
  </#if

Die Ausgabe in der Vorschau ist aber leer weitegehend leer:

		datatstore: shopifyOrderTransactions
		identifier: 3055584247882
		master_identifier: 2438364430410
		id: 
		datatstore: shopifyOrderTransactions
		identifier: 3055594831946
		master_identifier: 2438364430410
		id: 
		datatstore: shopifyOrderItems
		identifier: 5338985562186
		master_identifier: 2438364430410
		id: 
        1 -  -  -  -  -   - 

Sieht auf den ersten Blick eigentlich gut aus. Aber wir haben evtl. eine Sache, die wir morgen genauer Prüfen müssen. Scheinbar haben Sie mehrere Child-Datastores. Nach einer kurzen Prüfung scheint es so zu sein, dass nur die Spalten des ersten Child-Datastores berücksichtigt werden. Wir prüfen das und erarbeiten eine Lösung.


Könnten Sie ggf. mal zum Test die Prüfung <#if lineitems.get('datastorename') == 'shopifyOrderItems'> mal auf shopifyOrderTransactions abändern und die Spaltennamen in der Ausgabe mal entsprechend anpassen, so dass es für shopifyOrderTransactions eine Ausgabe gibt? Damit könnten wir unsere These überprüfen.


Kleiner Tip am Rande: statt line_number_counter händisch mit einer extra Variable zu können Sie auch direkt ${lineitems?counter} benutzen (1-based).

Der Datastore ist eigentlich der letzte (zumindest in der alphabetischen Reihenfolge), aber es werden in der Tat die Spalten dieses Stores ausgegeben:

 <#if lineitems.get('datastorename') == 'shopifyOrderTransactions'>
			id: ${lineitems.get('identifier')!}
			id2: ${lineitems.get('identifier2')!}
			id3: ${lineitems.get('identifier3')!}
			trx_id: ${lineitems.get('transaction_id')!}
			parent_id: ${lineitems.get('parent_id')!}
			order_id: ${lineitems.get('order_id')!}
			status: ${lineitems.get('status')!}
			kind: ${lineitems.get('kind')!}
			gateway: ${lineitems.get('gateway')!}
</#if>

			id: 3055594831946
			id2: 2438364430410
			id3: 2438364430410-somecard-sale
			trx_id: 3055594831946
			parent_id: 2438364430410
			order_id: 2438364430410
			status: success
			kind: sale
			gateway: somecard

Ok vielen Dank für die Rückmeldung. Das ist ein Bug unserseits, der bei mehreren Child-Datastores auftritt.

Leider fällt uns auch kein Workaround dafür ein, deshalb erarbeiten wir jetzt eine Lösung. Wir bitten noch um etwas Geduld, da wir erstmal verschiedene Optionen prüfen müssen. Wir melden uns gegen Nachmittag nochmal, wann wir voraussichtlich einen Fix schaffen.


Ok. Ich bin jetzt erst mal so verfahren, dass ich die notwendigen Daten erst einmal in einem dedizierten SearchDatastore Step hole.

Hallo Synesty Support,


es scheint wohl so, dass CSS Angaben im Head Bereich ignoriert werden. Kann man wenigstens mit style Attributen in Elementen arbeiten?

Nächstes Problem: wenn ich in den HTML Elementen Style Attribute nutze, dann kriege ich im HTML2PdfConverter Step keinen Output

1. zur Child-Datastore Problematik:

Wir haben glücklicherweise eine schnelle Lösung gefunden. Ihr vorheriger Code sollte jetzt wie gewünscht funktionieren. Bitte versuchen Sie es mal.

Wir haben gleich noch eine Möglichkeit eingebaut, dass man den gewünschten Child-Datastore als Parameter mitgeben kann. Das wäre in Ihrem Fall sinnvoll und vereinfacht das Freemarker-Skript.



Probieren Sie mal folgendes Skript.


<#if (order.children()?? && order.children()?size > 0) >
  <#assign line_number_counter = 1>
    <#list order.children("shopifyOrderItems") as lineitems>
    datatstore: ${lineitems.get('datastorename')!}
    identifier: ${lineitems.get('identifier')!}
    master_identifier: ${lineitems.get('master_identifier')!}
    id: ${lineitems.get('id')!}
       
      <#assign sku = lineitems.get("line_items_sku")>
        ${line_number_counter!} - ${sku} - ${lineitems.get('line_items_title')!} - ${lineitems.get('line_items_quantity')!} - ${lineitems.get('line_items_price')!} - ${lineitems.get('line_items_tax_lines_rate')!} ${(lineitems.get('line_items_tax_lines_price')!)} - ${lineitems.get("line_items_quantity")!} ${lineitems.get('line_items_price')!}
        <#assign line_number_counter += 1>

    </#list>
  </#if


Hier ist der Filter auf den Child-Datastore enthalten:


<#list order.children("shopifyOrderItems") as lineitems>


und dadurch kann der zusätzliche if-check <#if lineitems.get('datastorename') == 'shopifyOrderItems'> entfallen.


Bitte probieren Sie das mal.



2. zu HTML2PDF


Der Step und die verwendete Technologie unterstützt nur sehr wenige Basis-HTML-Elemente. Viel lässt sich da nicht machen.
Style-Attribute scheint aber teilweise unterstützt zu werden.

Können Sie vielleicht mal ein Beispiel-HTML-Code schicken? Dann könnten wir prüfen, was davon gehen würde.
Vielleicht ist aber auch ein externer Dienst wie z.B. dieser eine Alternative.






Hallo,


anbei die Dateien, die erzeugt werden.


Zuerst wird die HTML Datei erzeugt, siehe "rechnung(6).html"

Im HTML2PDF Step wird dann die Datei "rechnung(2).pdf" erzeugt

Als Vergleich das PDF, wenn ich die HTML Datei im Browser öffne und als PDF speichere (und das wäre auch das erwünschte Ergebnis)


Ich habe jetzt mal zum Test die Style Attribute den jeweilgen HTML Elementen zugeordnet, und dann wird gar keine PDF Datei mehr erzeugt. Im Anhang die FTL Datei sowie das vom StringToFile Step erzeugte HTML Dokument (dieses wird im Browser auch korrekt dargestellt).

Also die Alternative mit Restpack macht ja alles nur noch komplizierter... Zum einen, wie bekommt Restpack das HTML Dokument? Wenn ich einen Flow per URL Trigger zur Verfügung stelle, dann ist es meines Wissens nach nicht möglich, das HTML aus einem Step als Response Body zurück zu geben. Und wie kann ich dann das PDF Dokument herunterladen und per SFTP archivieren?

Vielen Dank für die Beispiel-HTML Datei mit den Style-Attributen an den Elementen. Wir konnten das auf einem lokalen Testsystem nachstellen.
Entfernen Sie mal bitte dort das background-size: contain;


Daran stört sich der Converter. Wir nehmen das mit auf und versuchen die Fehlerausgabe zu verbessern. Leider wurde die Fehlermeldung momentan geschluckt.


Jetzt sieht es schon besser aus! Die Schriftgrößen passen noch nicht ganz und auch die Größe des Bildes im Header ist noch nicht passend, aber ich habe jetzt eine Basis :-)