Show
Ignore:
Timestamp:
11/29/06 22:21:57 (18 years ago)
Author:
jerome
Message:

pkrefund can now create refunding receipts in the PDF format.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/pkrefund

    r3068 r3084  
    11#! /usr/bin/env python 
    22# -*- coding: ISO-8859-15 -*- 
     3 
     4"""pkrefund is a tool to refund print jobs and generate PDF receipts.""" 
    35 
    46# PyKota Print Job Refund Manager 
     
    2628 
    2729import sys 
    28  
    29 from pykota.tool import PyKotaTool, PyKotaCommandLineError, crashed, N_ 
     30import os 
     31import pwd 
     32import time 
     33import cStringIO 
     34 
     35try : 
     36    from reportlab.pdfgen import canvas 
     37    from reportlab.lib import pagesizes 
     38    from reportlab.lib.units import cm 
     39except ImportError :     
     40    hasRL = 0 
     41else :     
     42    hasRL = 1 
     43     
     44try : 
     45    import PIL.Image  
     46except ImportError :     
     47    hasPIL = 0 
     48else :     
     49    hasPIL = 1 
     50 
     51from pykota.tool import Percent, PyKotaTool, PyKotaToolError, PyKotaCommandLineError, crashed, N_ 
    3052 
    3153__doc__ = N_("""pkrefund v%(__version__)s (c) %(__years__)s %(__author__)s 
     
    4466  -f | --force         Doesn't ask for confirmation before refunding jobs. 
    4567  -r | --reason txt    Sets textual information to explain the refunding. 
     68 
     69  -l | --logo img      Use the image as the receipt's logo. The logo will 
     70                       be drawn at the center top of the page. The default 
     71                       logo is /usr/share/pykota/logos/pykota.jpeg 
     72 
     73  -p | --pagesize sz   Sets sz as the page size. Most well known 
     74                       page sizes are recognized, like 'A4' or 'Letter' 
     75                       to name a few. The default size is A4. 
     76 
     77  -n | --number N      Sets the number of the first receipt. This number 
     78                       will automatically be incremented for each receipt. 
     79 
     80  -o | --output f.pdf  Defines the name of the PDF file which will contain 
     81                       the receipts. If not set, then no PDF file will 
     82                       be created. If set to '-', then --force is assumed, 
     83                       and the PDF document is sent to standard output. 
     84 
     85  -u | --unit u        Defines the name of the unit to use on the receipts. 
     86                       The default unit is 'Credits', optionally translated 
     87                       to your native language if it is supported by PyKota. 
     88   
    4689 
    4790  Use the filter expressions to extract only parts of the  
     
    83126Examples : 
    84127 
    85   $ pkrefund jobid=503 
     128  $ pkrefund --output /tmp/receipts.pdf jobid=503 
    86129   
    87130  This will refund all jobs which Id is 503. BEWARE : installing CUPS 
    88   afresh will reset the first job id at 1. So you probably want to use 
    89   a more precise filter as explained below 
     131  afresh will reset the first job id at 1, so you probably want to use 
     132  a more precise filter as explained below. A confirmation will 
     133  be asked for each job to refund, and a PDF file named /tmp/receipts.pdf 
     134  will be created which will contain printable receipts. 
    90135   
    91136  $ pkrefund --reason "Hardware problem" jobid=503 start=today-7 
     
    115160                        "end", 
    116161                      ] 
     162                       
     163    def getPageSize(self, pgsize) : 
     164        """Returns the correct page size or None if not found.""" 
     165        try : 
     166            return getattr(pagesizes, pgsize.upper()) 
     167        except AttributeError :     
     168            try : 
     169                return getattr(pagesizes, pgsize.lower()) 
     170            except AttributeError : 
     171                pass 
     172                 
     173    def printVar(self, label, value, size) : 
     174        """Outputs a variable onto the PDF canvas. 
     175         
     176           Returns the number of points to substract to current Y coordinate. 
     177        """    
     178        xcenter = (self.pagesize[0] / 2.0) - 1*cm 
     179        self.canvas.saveState() 
     180        self.canvas.setFont("Helvetica-Bold", size) 
     181        self.canvas.setFillColorRGB(0, 0, 0) 
     182        self.canvas.drawRightString(xcenter, self.ypos, "%s :" % self.userCharsetToUTF8(label)) 
     183        self.canvas.setFont("Courier-Bold", size) 
     184        self.canvas.setFillColorRGB(0, 0, 1) 
     185        self.canvas.drawString(xcenter + 0.5*cm, self.ypos, self.userCharsetToUTF8(value)) 
     186        self.canvas.restoreState() 
     187        self.ypos -= (size + 4) 
     188         
     189    def pagePDF(self, receiptnumber, name, values, unitname, reason) : 
     190        """Generates a new page in the PDF document.""" 
     191        if values["nbpages"] : 
     192            self.canvas.doForm("background") 
     193            self.ypos = self.yorigine - (cm + 20) 
     194            self.printVar(_("Refunding receipt"), "#%s" % receiptnumber, 22) 
     195            self.printVar(_("Username"), name, 22) 
     196            self.ypos -= 20 
     197            self.printVar(_("Edited on"), time.strftime("%c", time.localtime()), 14) 
     198                 
     199            self.ypos -= 20 
     200            self.printVar(_("Jobs refunded"), str(values["nbjobs"]), 22) 
     201            self.printVar(_("Pages refunded"), str(values["nbpages"]), 22) 
     202            self.printVar(_("Amount refunded"), "%.3f %s" % (values["nbcredits"], unitname), 22) 
     203            self.ypos -= 20 
     204            self.printVar(_("Reason"), reason, 14) 
     205            self.canvas.showPage() 
     206            return 1 
     207        return 0     
     208         
     209    def initPDF(self, logo) : 
     210        """Initializes the PDF document.""" 
     211        self.pdfDocument = cStringIO.StringIO()         
     212        self.canvas = c = canvas.Canvas(self.pdfDocument, \ 
     213                                        pagesize=self.pagesize, \ 
     214                                        pageCompression=1) 
     215         
     216        c.setAuthor(self.originalUserName) 
     217        c.setTitle("PyKota print job refunding receipts") 
     218        c.setSubject("Print job refunding receipts generated with PyKota") 
     219         
     220         
     221        self.canvas.beginForm("background") 
     222        self.canvas.saveState() 
     223         
     224        self.ypos = self.pagesize[1] - (2 * cm)             
     225         
     226        xcenter = self.pagesize[0] / 2.0 
     227        if logo : 
     228            try :     
     229                imglogo = PIL.Image.open(logo) 
     230            except IOError :     
     231                self.printInfo("Unable to open image %s" % logo, "warn") 
     232            else : 
     233                (width, height) = imglogo.size 
     234                multi = float(width) / (8 * cm)  
     235                width = float(width) / multi 
     236                height = float(height) / multi 
     237                self.ypos -= height 
     238                c.drawImage(logo, xcenter - (width / 2.0), \ 
     239                                  self.ypos, \ 
     240                                  width, height) 
     241         
     242        self.ypos -= (cm + 20) 
     243        self.canvas.setFont("Helvetica-Bold", 14) 
     244        self.canvas.setFillColorRGB(0, 0, 0) 
     245        msg = _("Here's the receipt for the refunding of your print jobs") 
     246        self.canvas.drawCentredString(xcenter, self.ypos, "%s :" % self.userCharsetToUTF8(msg)) 
     247         
     248        self.yorigine = self.ypos 
     249        self.canvas.restoreState() 
     250        self.canvas.endForm() 
     251         
     252    def endPDF(self, fname) :     
     253        """Flushes the PDF generator.""" 
     254        self.canvas.save() 
     255        if fname != "-" :         
     256            outfile = open(fname, "w") 
     257            outfile.write(self.pdfDocument.getvalue()) 
     258            outfile.close() 
     259        else :     
     260            sys.stdout.write(self.pdfDocument.getvalue()) 
     261            sys.stdout.flush() 
     262         
     263    def genReceipts(self, peruser, logo, outfname, firstnumber, reason) : 
     264        """Generates the receipts file.""" 
     265        if outfname and len(peruser) : 
     266            percent = Percent(self) 
     267            percent.setSize(len(peruser)) 
     268            if outfname != "-" : 
     269                percent.display("%s...\n" % _("Generating receipts")) 
     270                 
     271            self.initPDF(logo) 
     272            number = firstnumber 
     273            for (name, values) in peruser.items() : 
     274                number += self.pagePDF(number, name, values, options["unit"], reason) 
     275                if outfname != "-" : 
     276                    percent.oneMore() 
     277                     
     278            if number > firstnumber : 
     279                self.endPDF(outfname) 
     280                 
     281            if outfname != "-" : 
     282                percent.done() 
     283         
    117284    def main(self, arguments, options, restricted=1) : 
    118285        """Print Quota Data Dumper.""" 
     286        if not hasRL : 
     287            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org" 
     288        if not hasPIL : 
     289            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads" 
     290             
    119291        if restricted and not self.config.isAdmin : 
    120292            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command.")) 
     293             
     294        if (not options["reason"]) or not options["reason"].strip() : 
     295            raise PyKotaCommandLineError, _("Refunding for no reason is forbidden. Please use the --reason command line option.") 
     296             
     297        if options["output"] : 
     298            options["output"] = options["output"].strip() 
     299            if options["output"] == "-" : 
     300                options["force"] = True 
     301                self.printInfo(_("The PDF file containing the receipts will be sent to stdout. --force is assumed."), "warn") 
     302             
     303        try :     
     304            firstnumber = int(options["number"]) 
     305            if firstnumber <= 0 : 
     306                raise ValueError 
     307        except (ValueError, TypeError) :     
     308            raise PyKotaCommandLineError, _("Incorrect value '%s' for the --number command line option") % options["number"] 
     309             
     310        self.pagesize = self.getPageSize(options["pagesize"]) 
     311        if self.pagesize is None : 
     312            self.pagesize = self.getPageSize("a4") 
     313            self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn") 
    121314             
    122315        extractonly = {} 
     
    198391                            break 
    199392                    print         
    200         print _("Refunded %i jobs, %i pages and %.3f credits") % (nbjobs, nbpages, nbcredits)                                  
     393        self.genReceipts(peruser, options["logo"].strip(), options["output"], firstnumber, reason) 
     394        if options["output"] != "-" :     
     395            print _("Refunded %i jobs, %i pages and %.3f credits") % (nbjobs, nbpages, nbcredits) 
    201396             
    202397if __name__ == "__main__" :  
    203398    retcode = 0 
    204399    try : 
    205         short_options = "vhfr" 
    206         long_options = ["help", "version", "force", "reason="] 
     400        defaults = { "unit" : N_("Credits"), 
     401                     "pagesize" : "a4", \ 
     402                     "logo" : "/usr/share/pykota/logos/pykota.jpeg", 
     403                     "number" : "1", 
     404                   } 
     405        short_options = "vhfru:o:p:l:n:" 
     406        long_options = ["help", "version", "force", "reason=", "unit=", "output=", "pagesize=", "logo=", "number="] 
    207407         
    208408        # Initializes the command line tool 
     
    218418        options["force"] = options["f"] or options["force"] 
    219419        options["reason"] = options["r"] or options["reason"] 
     420        options["unit"] = options["u"] or options["unit"] or defaults["unit"] 
     421        options["output"] = options["o"] or options["output"] 
     422        options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"] 
     423        options["number"] = options["n"] or options["number"] or defaults["number"] 
     424        options["logo"] = options["l"] or options["logo"] 
     425        if options["logo"] is None : # Allows --logo="" to disable the logo entirely 
     426            options["logo"] = defaults["logo"]   
    220427         
    221428        if options["help"] :