Index: pykota/trunk/bin/pkinvoice
===================================================================
--- pykota/trunk/bin/pkinvoice (revision 3303)
+++ pykota/trunk/bin/pkinvoice (revision 3341)
@@ -21,4 +21,6 @@
 #
 #
+
+"""An invoice generator for PyKota"""
 
 import sys
@@ -45,92 +47,13 @@
 
 import pykota.appinit
-from pykota.utils import *
-
+from pykota.utils import run
+from pykota.commandline import PyKotaOptionParser, \
+                               checkandset_pagesize, \
+                               checkandset_positiveint, \
+                               checkandset_percent
+from pykota.pdfutils import getPageSize
 from pykota.errors import PyKotaToolError, PyKotaCommandLineError
 from pykota.tool import Percent, PyKotaTool
 
-__doc__ = N_("""pkinvoice v%(__version__)s (c) %(__years__)s %(__author__)s
-
-An invoice generator for PyKota.
-
-command line usage :
-
-  pkinvoice [options] [filterexpr]
-
-options :
-
-  -v | --version       Prints pkinvoice's version number then exits.
-  -h | --help          Prints this message then exits.
-  
-  -l | --logo img      Use the image as the invoice's logo. The logo will
-                       be drawn at the center top of the page. The default
-                       logo is /usr/share/pykota/logos/pykota.jpeg
-                       
-  -p | --pagesize sz   Sets sz as the page size. Most well known
-                       page sizes are recognized, like 'A4' or 'Letter'
-                       to name a few. The default size is A4.
-                       
-  -n | --number N      Sets the number of the first invoice. This number
-                       will automatically be incremented for each invoice.
-                       
-  -o | --output f.pdf  Defines the name of the invoice file which will
-                       be generated as a PDF document. If not set or
-                       set to '-', the PDF document is sent to standard
-                       output. 
-                       
-  -u | --unit u        Defines the name of the unit to use on the invoice.                       
-                       The default unit is 'Credits', optionally translated
-                       to your native language if it is supported by PyKota.
-  
-  -V | --vat p         Sets the percent value of the applicable VAT to be
-                       exposed. The default is 0.0, meaning no VAT
-                       information will be included.
-  
-
-  Use the filter expressions to extract only parts of the 
-  datas. Allowed filters are of the form :
-                
-         key=value
-                         
-  Allowed keys for now are :  
-                       
-         username       User's name
-         printername    Printer's name
-         hostname       Client's hostname
-         jobid          Job's Id
-         billingcode    Job's billing code
-         start          Job's date of printing
-         end            Job's date of printing
-         
-  Dates formatting with 'start' and 'end' filter keys :
-  
-    YYYY : year boundaries
-    YYYYMM : month boundaries
-    YYYYMMDD : day boundaries
-    YYYYMMDDhh : hour boundaries
-    YYYYMMDDhhmm : minute boundaries
-    YYYYMMDDhhmmss : second boundaries
-    yesterday[+-NbDays] : yesterday more or less N days (e.g. : yesterday-15)
-    today[+-NbDays] : today more or less N days (e.g. : today-15)
-    tomorrow[+-NbDays] : tomorrow more or less N days (e.g. : tomorrow-15)
-    now[+-NbDays] : now more or less N days (e.g. now-15)
-
-  'now' and 'today' are not exactly the same since today represents the first
-  or last second of the day depending on if it's used in a start= or end=
-  date expression. The utility to be able to specify dates in the future is
-  a question which remains to be answered :-)
-  
-  Contrary to other PyKota management tools, wildcard characters are not 
-  expanded, so you can't use them.
-  
-examples :
-
-  $ pkinvoice --unit EURO --output /tmp/invoices.pdf start=now-30
-  
-  Will generate a PDF document containing invoices for all users
-  who have spent some credits last month. Invoices will be done in
-  EURO.  No VAT information will be included.
-""") 
-        
 class PKInvoice(PyKotaTool) :        
     """A class for invoice generator."""
@@ -144,14 +67,4 @@
                       ]
                       
-    def getPageSize(self, pgsize) :
-        """Returns the correct page size or None if not found."""
-        try :
-            return getattr(pagesizes, pgsize.upper())
-        except AttributeError :    
-            try :
-                return getattr(pagesizes, pgsize.lower())
-            except AttributeError :
-                pass
-                
     def printVar(self, label, value, size) :
         """Outputs a variable onto the PDF canvas.
@@ -181,5 +94,6 @@
             self.printVar(_("Username"), name, 22)
             self.ypos -= 20
-            self.printVar(_("Edited on"), time.strftime("%c", time.localtime()), 14)
+            datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace")
+            self.printVar(_("Edited on"), datetime, 14)
                 
             self.ypos -= 20
@@ -279,22 +193,5 @@
             raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
         
-        try :    
-            vat = float(options["vat"])
-            if not (0.0 <= vat < 100.0) :
-                raise ValueError
-        except :    
-            raise PyKotaCommandLineError, _("Incorrect value '%s' for the --vat command line option") % options["vat"]
-            
-        try :    
-            firstnumber = number = int(options["number"])
-            if number <= 0 :
-                raise ValueError
-        except :    
-            raise PyKotaCommandLineError, _("Incorrect value '%s' for the --number command line option") % options["number"]
-            
-        self.pagesize = self.getPageSize(options["pagesize"])
-        if self.pagesize is None :
-            self.pagesize = self.getPageSize("a4")
-            self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn")
+        self.pagesize = getPageSize(options.pagesize)
             
         extractonly = {}
@@ -312,5 +209,5 @@
             
         percent = Percent(self)
-        outfname = options["output"].strip()
+        outfname = options.output.strip().encode(sys.getfilesystemencoding())
         if outfname != "-" :
             percent.display("%s..." % _("Extracting datas"))
@@ -361,67 +258,66 @@
         if outfname != "-" :
             percent.done()
-        self.genInvoices(peruser, options["logo"].strip(), outfname, firstnumber, options["unit"], vat)
+        self.genInvoices(peruser, 
+                         options.logo.strip().encode(sys.getfilesystemencoding()), 
+                         outfname, 
+                         options.number, 
+                         options.unit or _("Credits"), 
+                         options.vat)
         if outfname != "-" :    
-            print _("Invoiced %i users for %i jobs, %i pages and %.3f credits") % (len(peruser), nbjobs, nbpages, nbcredits)
+            print _("Invoiced %i users for %i jobs, %i pages and %.3f credits") \
+                % (len(peruser), nbjobs, nbpages, nbcredits)
                      
 if __name__ == "__main__" : 
-    retcode = 0
-    try :
-        defaults = { "vat" : "0.0",
-                     "unit" : N_("Credits"),
-                     "output" : "-",
-                     "pagesize" : "a4", \
-                     "logo" : "/usr/share/pykota/logos/pykota.jpeg",
-                     "number" : "1",
-                   }
-        short_options = "vho:u:V:p:l:n:"
-        long_options = ["help", "version", "unit=", "output=", \
-                        "pagesize=", "logo=", "vat=", "number="]
-        
-        # Initializes the command line tool
-        invoiceGenerator = PKInvoice(doc=__doc__)
-        invoiceGenerator.deferredInit()
-        
-        # parse and checks the command line
-        (options, args) = invoiceGenerator.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=True)
-        
-        # sets long options
-        options["help"] = options["h"] or options["help"]
-        options["version"] = options["v"] or options["version"]
-        
-        options["vat"] = options["V"] or options["vat"] or defaults["vat"]
-        options["unit"] = options["u"] or options["unit"] or defaults["unit"]
-        options["output"] = options["o"] or options["output"] or defaults["output"]
-        options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"]
-        options["number"] = options["n"] or options["number"] or defaults["number"]
-        options["logo"] = options["l"] or options["logo"]
-        if options["logo"] is None : # Allows --logo="" to disable the logo entirely
-            options["logo"] = defaults["logo"]  
-        
-        if options["help"] :
-            invoiceGenerator.display_usage_and_quit()
-        elif options["version"] :
-            invoiceGenerator.display_version_and_quit()
-        else :
-            retcode = invoiceGenerator.main(args, options)
-    except KeyboardInterrupt :        
-        logerr("\nInterrupted with Ctrl+C !\n")
-        retcode = -3
-    except PyKotaCommandLineError, msg :     
-        logerr("%s : %s\n" % (sys.argv[0], msg))
-        retcode = -2
-    except SystemExit :        
-        pass
-    except :
-        try :
-            invoiceGenerator.crashed("pkinvoice failed")
-        except :    
-            crashed("pkinvoice failed")
-        retcode = -1
-
-    try :
-        invoiceGenerator.storage.close()
-    except (TypeError, NameError, AttributeError) :    
-        pass
-        
-    sys.exit(retcode)    
+    parser = PyKotaOptionParser(description=_("Invoice generator for PyKota."),
+                                usage="pkinvoice [options] [filterexpr]")
+    parser.add_option("-l", "--logo",
+                            dest="logo",
+                            default=u"/usr/share/pykota/logos/pykota.jpeg",
+                            help=_("The image to use as a logo. The logo will be drawn at the center top of the page. The default logo is %default"))
+    parser.add_option("-p", "--pagesize",
+                            type="string",
+                            action="callback",
+                            callback=checkandset_pagesize,
+                            dest="pagesize",
+                            default=u"A4",
+                            help=_("Set the size of the page. Most well known page sizes are recognized, like 'A4' or 'Letter' to name a few. The default page size is %default"))
+    parser.add_option("-n", "--number",                        
+                            dest="number",
+                            type="int",
+                            action="callback",
+                            callback=checkandset_positiveint,
+                            default=1,
+                            help=_("Sets the number of the first invoice. This number will automatically be incremented for each invoice. The default value is %default"))
+    parser.add_option("-o", "--output",
+                            dest="output",
+                            type="string",
+                            default=u"-",
+                            help=_("The name of the file to which the PDF invoices will be written. If not set or set to '%default', the PDF document will be sent to the standard output."))
+                            
+    # TODO : due to Python's optparse.py bug #1498146 fixed in rev 46861
+    # TODO : we can't use 'default=_("Credits")' for this option
+    parser.add_option("-u", "--unit",                   
+                            dest="unit",
+                            type="string",
+                            help=_("The name of the unit to use on the invoices. The default value is 'Credits' or its locale translation."))
+                            
+    parser.add_option("-V", "--vat", 
+                            dest="vat",
+                            type="float",
+                            action="callback",
+                            callback=checkandset_percent,
+                            default=0.0,
+                            help=_("The value in percent of the applicable VAT to be exposed. The default is %default, meaning no VAT."))
+                            
+    parser.add_filterexpression("username", _("User's name"))                        
+    parser.add_filterexpression("printername", _("Printer's name"))                        
+    parser.add_filterexpression("hostname", _("Host's name"))                        
+    parser.add_filterexpression("jobid", _("Job's id"))                        
+    parser.add_filterexpression("billingcode", _("Job's billing code"))
+    parser.add_filterexpression("start", _("Job's date of printing"))                        
+    parser.add_filterexpression("end", _("Job's date of printing"))                        
+    
+    parser.add_example('--unit EURO --output /tmp/invoices.pdf start=now-30', 
+                       _("This would generate a PDF document containing invoices for all users who have spent some credits last month. Amounts would be in EURO and not VAT information would be included."))
+                       
+    run(parser, PKInvoice)                   
