Comments to, How to automatically create ODF invoices without OpenOffice

(Note: these are the comments appended to my original article, which I had to put in a separate page when I switched from Drupal to WordPress)

Just came to your site…

Just came to your site following a link from linuxtoday. Wow! This opens windows of opportunities! Somehow I’ve totally missed out on the fact that odt documents are just zip files. I’ve been reading a bit through some content.xml files. And it seems that it should be possible to use openoffice from a text editor just as fine.

I made my thesis in OpenOffice, but only after convincing myself that it wasn’t worth it to invest a lot of time in learning (La)tex. There are always these small things that just change when working on a big file. With my current understanding, it would make perfect sense to write a document in a text editor, and then put it into some file of which I like the lay-out. Use OpenOffice as a mark-up language. And that is just frigging awesome!

I haven’t started to really research or test the opportunities, I just want to express my enthusiasm. Maybe you could shed a light on how to use openoffice as a true mark-up language?

Thanks a lot!

Joep

On ODF as a markup language

My answer:

Joep,

first of all, thanks a lot for your appreciation of my work. There is no doubt that you can create OpenDocument (not openoffice!) files only using a plain text editor like notepad, emacs, Vim and so on. However, I would avoid doing so because it is very boring, time consuming and error-prone. One of the articles I have in the pipeline is how to write text in a much simpler and faster markup language liketxt2tags and then generate the OpenDocument version of the text with a script.

Another way to improve the zip/unzip part of this script…

….has been kindly suggested by Sander at lxer.com (thanks, Sander!):

The script will lead to an ODF file with an invalid mimetype. Creating an ODF file using the zip command on the commandline is only slightly more complicated. See this article on my blog

Useful improvement

Soren Roug just suggested an improvement through the ODF-discuss list:

It's somewhat of a brute force solution. The main issue is that the mimetype
has to be the first element in the zip-file and not be compressed in order to
comply fully with the specification

Since the my_template.odt file already complies, it is much easier to take out
only content.xml and then stuff it back in.



cp my_template.odt new_$FILENAME.odt
unzip new_$FILENAME.odt content.xml
sed ... content.xml >custom_content.xml
mv custom_content.xml content.xml
zip -f new_$FILENAME.odt content.xml

Thanks, Soren!

How to automatically create OpenDocument invoices without OpenOffice

Articles on how to create OpenDocument invoices already exist but almost always they require you to start and use OpenOffice manually each time. Here, instead, I’ll show how to have your computer to do all your OpenDocument work for you.

odf_scripting_sample_invoice The script explained below takes an ODF template like the one of the left and generates an ODF text file like the one you see on the right below, which is ready to be printed or sent via email (follow the links to download the template or the resulting ODF invoice).

odf_scripting_customized_invoice The advantages of creating the invoice with a script rather than with macros are explained in detail in the “Why and how ODF can save you a lot of time” page: in a nutshell, once you have created and saved with any ODF compliant word processor the initial template, the whole process is completely automatic, so it could run unattended and be integrated with other backend systems even where OpenOffice isn’t installed.

The script takes two arguments, the template name and an invoice data file:

odf_invoice_generator.sh odf_scripting_sample_invoice.odt my_data.sh

then opens the template, replaces placeholder data or strings like e.g. __Customer_name with the proper values from the invoice data file and finally saves everything as a separate OpenDocument text file. The data file has an extremely simple format, since it’s only variable assignments in shell script syntax:

  marco => cat my_data.sh
  INVOICE_DATE='2010/05/15'
  VENDOR_CODE='007'
  PO_NUMBER='Purchase Order #1'
  TOTAL=10
  ISSUE=150
  DESCRIPTION='Here is your invoice'

and can be automatically generated on the spot by querying a database, by a Web server or in many other ways.

Here is the complete script, followed by an explanation:

       0 #!/bin/bash
       1  WORK_DIR=odt_invoice_generator_temp_dir
       2
       3  rm -rf $WORK_DIR
       4  mkdir  $WORK_DIR
       5  FILENAME=`basename $1 .odt`
       6
       7  cp     $1 $WORK_DIR/my_template.odt
       8  cp     $2 $WORK_DIR/my_data.sh
       9
      10  ## preparation
      11  cd     $WORK_DIR
      12  mkdir  work
      13  mv     my_template.odt work
      14  cd     work
      15  source ../my_data.sh
      16  unzip  my_template.odt > /dev/null
      17  rm     my_template.odt
      18
      19  ## replace text strings
      20  sed "s|__INVOICE_DATE|$INVOICE_DATE|"  content.xml  
      21  | sed "s|__VENDOR_CODE|$VENDOR_CODE|"               
      22  | sed "s|__PO_NUMBER|$PO_NUMBER|"                   
      23  | sed "s|__TOTAL|$TOTAL|g"                          
      24  | sed "s|__ISSUE_NUMBER|$ISSUE|"                    
      25  | sed "s|__DESCRIPTION|$DESCRIPTION|"               
      26  | sed "s|__Customer_name|$Customer_name|"           
      27  > custom_content.xml
      28  mv custom_content.xml content.xml
      29
      30  ## zip everything, rename it as .odt file and clean up
      31  find . -type f -print0 | xargs -0 zip ../$FILENAME > /dev/null
      32  cd ..
      33  mv $FILENAME.zip ../new_$FILENAME.odt
      34  cd ..
      35  rm -rf $WORK_DIR

The lines from 1 to 17 don’t do anything difficult: create a temporary working directory (WORK_DIR) copy the template inside it, unzip the template, and load from the data file (line 15) the values that must fill the template.

The (relatively) tricky part are lines 19 to 26: this is where a series of sed commands replaces each placeholder string in the content.xml file which contains the template text with its value loaded from my_data.sh.
If you change the template you must add here one sed command for each string you want to substitute; the order is not important. Just remember that if a string occurs multiple times, as is the case with the __TOTAL price, you must add the g (global) option to sed (cfr line 23), otherwise the script will only replace the first occurrence of that string.

If you have any question or suggestion about this script, please email me or (even better, add it in the comments.