Changeset 3347

Show
Ignore:
Timestamp:
02/23/08 22:29:50 (16 years ago)
Author:
jerome
Message:

Now works new style.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/pkrefund

    r3303 r3347  
    2121# 
    2222# 
     23 
     24"""A refunding tool for PyKota""" 
    2325 
    2426import sys 
     
    4547 
    4648import pykota.appinit 
    47 from pykota.utils import * 
    48  
     49from pykota.utils import run 
     50from pykota.commandline import PyKotaOptionParser, \ 
     51                               checkandset_pagesize, \ 
     52                               checkandset_positiveint 
     53from pykota.pdfutils import getPageSize 
    4954from pykota.errors import PyKotaToolError, PyKotaCommandLineError 
    5055from pykota.tool import Percent, PyKotaTool 
    51  
    52 __doc__ = N_("""pkrefund v%(__version__)s (c) %(__years__)s %(__author__)s 
    53  
    54 Refunds jobs. 
    55  
    56 command line usage : 
    57  
    58   pkrefund [options] [filterexpr] 
    59  
    60 options : 
    61  
    62   -v | --version       Prints pkrefund's version number then exits. 
    63   -h | --help          Prints this message then exits. 
    64    
    65   -f | --force         Doesn't ask for confirmation before refunding jobs. 
    66   -r | --reason txt    Sets textual information to explain the refunding. 
    67  
    68   -l | --logo img      Use the image as the receipt's logo. The logo will 
    69                        be drawn at the center top of the page. The default 
    70                        logo is /usr/share/pykota/logos/pykota.jpeg 
    71  
    72   -p | --pagesize sz   Sets sz as the page size. Most well known 
    73                        page sizes are recognized, like 'A4' or 'Letter' 
    74                        to name a few. The default size is A4. 
    75  
    76   -n | --number N      Sets the number of the first receipt. This number 
    77                        will automatically be incremented for each receipt. 
    78  
    79   -o | --output f.pdf  Defines the name of the PDF file which will contain 
    80                        the receipts. If not set, then no PDF file will 
    81                        be created. If set to '-', then --force is assumed, 
    82                        and the PDF document is sent to standard output. 
    83  
    84   -u | --unit u        Defines the name of the unit to use on the receipts. 
    85                        The default unit is 'Credits', optionally translated 
    86                        to your native language if it is supported by PyKota. 
    87    
    88  
    89   Use the filter expressions to extract only parts of the  
    90   datas. Allowed filters are of the form : 
    91                  
    92          key=value 
    93                           
    94   Allowed keys for now are :   
    95                         
    96          username       User's name 
    97          printername    Printer's name 
    98          hostname       Client's hostname 
    99          jobid          Job's Id 
    100          billingcode    Job's billing code 
    101          start          Job's date of printing 
    102          end            Job's date of printing 
    103           
    104   Dates formatting with 'start' and 'end' filter keys : 
    105    
    106     YYYY : year boundaries 
    107     YYYYMM : month boundaries 
    108     YYYYMMDD : day boundaries 
    109     YYYYMMDDhh : hour boundaries 
    110     YYYYMMDDhhmm : minute boundaries 
    111     YYYYMMDDhhmmss : second boundaries 
    112     yesterday[+-NbDays] : yesterday more or less N days (e.g. : yesterday-15) 
    113     today[+-NbDays] : today more or less N days (e.g. : today-15) 
    114     tomorrow[+-NbDays] : tomorrow more or less N days (e.g. : tomorrow-15) 
    115     now[+-NbDays] : now more or less N days (e.g. now-15) 
    116  
    117   'now' and 'today' are not exactly the same since today represents the first 
    118   or last second of the day depending on if it's used in a start= or end= 
    119   date expression. The utility to be able to specify dates in the future is 
    120   a question which remains to be answered :-) 
    121    
    122   Contrary to other PyKota management tools, wildcard characters are not  
    123   expanded, so you can't use them. 
    124    
    125 Examples : 
    126  
    127   $ pkrefund --output /tmp/receipts.pdf jobid=503 
    128    
    129   This will refund all jobs which Id is 503. BEWARE : installing CUPS 
    130   afresh will reset the first job id at 1, so you probably want to use 
    131   a more precise filter as explained below. A confirmation will 
    132   be asked for each job to refund, and a PDF file named /tmp/receipts.pdf 
    133   will be created which will contain printable receipts. 
    134    
    135   $ pkrefund --reason "Hardware problem" jobid=503 start=today-7 
    136    
    137   Refunds all jobs which id is 503 but which were printed during the 
    138   past week. The reason will be marked as being an hardware problem. 
    139    
    140   $ pkrefund --force username=jerome printername=HP2100 
    141    
    142   Refunds all jobs printed by user jerome on printer HP2100. No 
    143   confirmation will be asked. 
    144    
    145   $ pkrefund --force printername=HP2100 start=200602 end=yesterday 
    146    
    147   Refunds all jobs printed on printer HP2100 between February 1st 2006 
    148   and yesterday. No confirmation will be asked. 
    149 """) 
    150          
    151 class PkRefund(PyKotaTool) :         
     56         
     57class PKRefund(PyKotaTool) :         
    15258    """A class for refund manager.""" 
    15359    validfilterkeys = [ "username", 
     
    16066                      ] 
    16167                       
    162     def getPageSize(self, pgsize) : 
    163         """Returns the correct page size or None if not found.""" 
    164         try : 
    165             return getattr(pagesizes, pgsize.upper()) 
    166         except AttributeError :     
    167             try : 
    168                 return getattr(pagesizes, pgsize.lower()) 
    169             except AttributeError : 
    170                 pass 
    171                  
    17268    def printVar(self, label, value, size) : 
    17369        """Outputs a variable onto the PDF canvas. 
     
    19490            self.printVar(_("Username"), name, 22) 
    19591            self.ypos -= 20 
    196             self.printVar(_("Edited on"), time.strftime("%c", time.localtime()), 14) 
     92            datetime = time.strftime("%c", time.localtime()).decode(self.charset, "replace") 
     93            self.printVar(_("Edited on"), datetime, 14) 
    19794                 
    19895            self.ypos -= 20 
     
    261158    def genReceipts(self, peruser, logo, outfname, firstnumber, reason, unit) : 
    262159        """Generates the receipts file.""" 
    263         if outfname and len(peruser) : 
     160        if len(peruser) : 
    264161            percent = Percent(self, size=len(peruser)) 
    265162            if outfname != "-" : 
     
    279176                percent.done() 
    280177         
    281     def main(self, arguments, options, restricted=1) : 
    282         """Print Quota Data Dumper.""" 
     178    def main(self, arguments, options) : 
     179        """Refunds jobs.""" 
    283180        if not hasRL : 
    284181            raise PyKotaToolError, "The ReportLab module is missing. Download it from http://www.reportlab.org" 
     
    286183            raise PyKotaToolError, "The Python Imaging Library is missing. Download it from http://www.pythonware.com/downloads" 
    287184             
    288         if restricted and not self.config.isAdmin : 
     185        if not self.config.isAdmin : 
    289186            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command.")) 
    290187             
    291         if (not options["reason"]) or not options["reason"].strip() : 
     188        self.pagesize = getPageSize(options.pagesize) 
     189         
     190        if (not options.reason) or (not options.reason.strip()) : 
    292191            raise PyKotaCommandLineError, _("Refunding for no reason is forbidden. Please use the --reason command line option.") 
    293              
    294         outfname = options["output"] 
    295         if outfname : 
    296             outfname = outfname.strip() 
    297             if outfname == "-" : 
    298                 options["force"] = True 
    299                 self.printInfo(_("The PDF file containing the receipts will be sent to stdout. --force is assumed."), "warn") 
    300              
    301         try :     
    302             firstnumber = int(options["number"]) 
    303             if firstnumber <= 0 : 
    304                 raise ValueError 
    305         except (ValueError, TypeError) :     
    306             raise PyKotaCommandLineError, _("Incorrect value '%s' for the --number command line option") % options["number"] 
    307              
    308         self.pagesize = self.getPageSize(options["pagesize"]) 
    309         if self.pagesize is None : 
    310             self.pagesize = self.getPageSize("a4") 
    311             self.printInfo(_("Invalid 'pagesize' option %s, defaulting to A4.") % options["pagesize"], "warn") 
    312192             
    313193        extractonly = {} 
     
    325205             
    326206        percent = Percent(self) 
     207        outfname = options.output.strip().encode(sys.getfilesystemencoding()) 
    327208        if outfname != "-" : 
    328209            percent.display("%s..." % _("Extracting datas")) 
     210        else :     
     211            options.force = True 
     212            self.printInfo(_("The PDF file containing the receipts will be sent to stdout. --force is assumed."), "warn") 
    329213             
    330214        username = extractonly.get("username")     
     
    352236                                            end=end, 
    353237                                            limit=0) 
     238                                             
    354239        peruser = {}                                     
    355240        nbjobs = 0                                     
    356241        nbpages = 0                                             
    357242        nbcredits = 0.0 
    358         reason = (options.get("reason") or "").strip() 
    359243        percent.setSize(len(jobs)) 
    360244        if outfname != "-" : 
     
    362246        for job in jobs :                                     
    363247            if job.JobSize and (job.JobAction not in ("DENY", "CANCEL", "REFUND")) : 
    364                 if options["force"] : 
     248                if options.force : 
    365249                    nbpages += job.JobSize 
    366250                    nbcredits += job.JobPrice 
     
    368252                    counters["nbpages"] += job.JobSize 
    369253                    counters["nbcredits"] += job.JobPrice 
    370                     job.refund(reason) 
     254                    job.refund(options.reason) 
    371255                    counters["nbjobs"] += 1 
    372256                    nbjobs += 1 
     
    392276                            counters["nbpages"] += job.JobSize 
    393277                            counters["nbcredits"] += job.JobPrice 
    394                             job.refund(reason) 
     278                            job.refund(options.reason) 
    395279                            counters["nbjobs"] += 1 
    396280                            nbjobs += 1 
     
    401285        if outfname != "-" : 
    402286            percent.done() 
    403         self.genReceipts(peruser, options["logo"].strip(), outfname, firstnumber, reason, options["unit"]) 
     287        self.genReceipts(peruser,  
     288                         options.logo.strip().encode(sys.getfilesystemencoding()),  
     289                         outfname,  
     290                         options.number,  
     291                         options.reason,  
     292                         options.unit or _("Credits")) 
    404293        if outfname != "-" :     
    405             print _("Refunded %i users for %i jobs, %i pages and %.3f credits") % (len(peruser), nbjobs, nbpages, nbcredits) 
     294            nbusers = len(peruser) 
     295            print _("Refunded %(nbusers)i users for %(nbjobs)i jobs, %(nbpages)i pages and %(nbcredits).3f credits") \ 
     296                     % locals() 
    406297             
    407298if __name__ == "__main__" :  
    408     retcode = 0 
    409     try : 
    410         defaults = { "unit" : N_("Credits"), 
    411                      "pagesize" : "a4", \ 
    412                      "logo" : "/usr/share/pykota/logos/pykota.jpeg", 
    413                      "number" : "1", 
    414                    } 
    415         short_options = "vhfru:o:p:l:n:" 
    416         long_options = ["help", "version", "force", "reason=", "unit=", "output=", "pagesize=", "logo=", "number="] 
    417          
    418         # Initializes the command line tool 
    419         refundmanager = PkRefund(doc=__doc__) 
    420         refundmanager.deferredInit() 
    421          
    422         # parse and checks the command line 
    423         (options, args) = refundmanager.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1) 
    424          
    425         # sets long options 
    426         options["help"] = options["h"] or options["help"] 
    427         options["version"] = options["v"] or options["version"] 
    428         options["force"] = options["f"] or options["force"] 
    429         options["reason"] = options["r"] or options["reason"] 
    430         options["unit"] = options["u"] or options["unit"] or defaults["unit"] 
    431         options["output"] = options["o"] or options["output"] 
    432         options["pagesize"] = options["p"] or options["pagesize"] or defaults["pagesize"] 
    433         options["number"] = options["n"] or options["number"] or defaults["number"] 
    434         options["logo"] = options["l"] or options["logo"] 
    435         if options["logo"] is None : # Allows --logo="" to disable the logo entirely 
    436             options["logo"] = defaults["logo"]   
    437          
    438         if options["help"] : 
    439             refundmanager.display_usage_and_quit() 
    440         elif options["version"] : 
    441             refundmanager.display_version_and_quit() 
    442         else : 
    443             retcode = refundmanager.main(args, options) 
    444     except KeyboardInterrupt :         
    445         logerr("\nInterrupted with Ctrl+C !\n") 
    446         retcode = -3 
    447     except PyKotaCommandLineError, msg :     
    448         logerr("%s : %s\n" % (sys.argv[0], msg)) 
    449         retcode = -2 
    450     except SystemExit :         
    451         pass 
    452     except : 
    453         try : 
    454             refundmanager.crashed("pkrefund failed") 
    455         except :     
    456             crashed("pkrefund failed") 
    457         retcode = -1 
    458  
    459     try : 
    460         refundmanager.storage.close() 
    461     except (TypeError, NameError, AttributeError) :     
    462         pass 
    463          
    464     sys.exit(retcode)     
     299    parser = PyKotaOptionParser(description=_("Refunding tool for PyKota."), 
     300                                usage="pkrefund [options] [filterexpr]") 
     301    parser.add_option("-f", "--force", 
     302                            dest="force", 
     303                            action="store_true", 
     304                            help=_("Doesn't ask for confirmation before refunding.")) 
     305    parser.add_option("-l", "--logo", 
     306                            dest="logo", 
     307                            default=u"/usr/share/pykota/logos/pykota.jpeg", 
     308                            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")) 
     309    parser.add_option("-p", "--pagesize", 
     310                            type="string", 
     311                            action="callback", 
     312                            callback=checkandset_pagesize, 
     313                            dest="pagesize", 
     314                            default=u"A4", 
     315                            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")) 
     316    parser.add_option("-n", "--number",                         
     317                            dest="number", 
     318                            type="int", 
     319                            action="callback", 
     320                            callback=checkandset_positiveint, 
     321                            default=1, 
     322                            help=_("Sets the number of the first receipt. This number will automatically be incremented for each receipt. The default value is %default")) 
     323    parser.add_option("-o", "--output", 
     324                            dest="output", 
     325                            type="string", 
     326                            default=u"-", 
     327                            help=_("The name of the file to which the PDF receipts will be written. If not set or set to '%default', the PDF document will be sent to the standard output.")) 
     328    parser.add_option("-r", "--reason", 
     329                            dest="reason", 
     330                            type="string", 
     331                            help=_("The reason why there was a refund.")) 
     332                             
     333    # TODO : due to Python's optparse.py bug #1498146 fixed in rev 46861 
     334    # TODO : we can't use 'default=_("Credits")' for this option 
     335    parser.add_option("-u", "--unit",                    
     336                            dest="unit", 
     337                            type="string", 
     338                            help=_("The name of the unit to use on the receipts. The default value is 'Credits' or its locale translation.")) 
     339                             
     340    parser.add_filterexpression("username", _("User's name")) 
     341    parser.add_filterexpression("printername", _("Printer's name")) 
     342    parser.add_filterexpression("hostname", _("Host's name")) 
     343    parser.add_filterexpression("jobid", _("Job's id")) 
     344    parser.add_filterexpression("billingcode", _("Job's billing code")) 
     345    parser.add_filterexpression("start", _("Job's date of printing")) 
     346    parser.add_filterexpression("end", _("Job's date of printing")) 
     347     
     348    parser.add_example('--output /tmp/receipts.pdf jobid=503', 
     349                       _("This would refund all jobs which Id is 503. A confirmation would be asked for each job to refund, and a PDF file named /tmp/receipts.pdf would be created containing printable receipts. BEWARE of job ids rolling over if you reset CUPS' history.")) 
     350   
     351    parser.add_example('--reason "Hardware problem" jobid=503 start=today-7', 
     352                       _("This would refund all jobs which id is 503 but which would have been printed during the  past week. The reason would be marked as being an hardware problem.")) 
     353   
     354    parser.add_example('--force username=jerome printername=HP2100', 
     355                       _("This would refund all jobs printed by user jerome on printer HP2100. No confirmation would be asked.")) 
     356   
     357    parser.add_example('--force printername=HP2100 start=200602 end=yesterday', 
     358                       _("This would refund all jobs printed on printer HP2100 between February 1st 2006 and yesterday. No confirmation would be asked.")) 
     359     
     360    (options, arguments) = parser.parse_args() 
     361    run(parser, PKRefund)