root / pykota / trunk / bin / pkrefund @ 3068

Revision 3068, 9.7 kB (checked in by jerome, 17 years ago)

Added help about date formatting.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota Print Job Refund Manager
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005, 2006 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22#
23# $Id$
24#
25#
26
27import sys
28
29from pykota.tool import PyKotaTool, PyKotaCommandLineError, crashed, N_
30
31__doc__ = N_("""pkrefund v%(__version__)s (c) %(__years__)s %(__author__)s
32
33Refunds jobs.
34
35command line usage :
36
37  pkrefund [options] [filterexpr]
38
39options :
40
41  -v | --version       Prints pkrefund's version number then exits.
42  -h | --help          Prints this message then exits.
43 
44  -f | --force         Doesn't ask for confirmation before refunding jobs.
45  -r | --reason txt    Sets textual information to explain the refunding.
46
47  Use the filter expressions to extract only parts of the
48  datas. Allowed filters are of the form :
49               
50         key=value
51                         
52  Allowed keys for now are : 
53                       
54         username       User's name
55         printername    Printer's name
56         hostname       Client's hostname
57         jobid          Job's Id
58         billingcode    Job's billing code
59         start          Job's date of printing
60         end            Job's date of printing
61         
62  Dates formatting with 'start' and 'end' filter keys :
63 
64    YYYY : year boundaries
65    YYYYMM : month boundaries
66    YYYYMMDD : day boundaries
67    YYYYMMDDhh : hour boundaries
68    YYYYMMDDhhmm : minute boundaries
69    YYYYMMDDhhmmss : second boundaries
70    yesterday[+-NbDays] : yesterday more or less N days (e.g. : yesterday-15)
71    today[+-NbDays] : today more or less N days (e.g. : today-15)
72    tomorrow[+-NbDays] : tomorrow more or less N days (e.g. : tomorrow-15)
73    now[+-NbDays] : now more or less N days (e.g. now-15)
74
75  'now' and 'today' are not exactly the same since today represents the first
76  or last second of the day depending on if it's used in a start= or end=
77  date expression. The utility to be able to specify dates in the future is
78  a question which remains to be answered :-)
79 
80  Contrary to other PyKota management tools, wildcard characters are not
81  expanded, so you can't use them.
82 
83Examples :
84
85  $ pkrefund jobid=503
86 
87  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
90 
91  $ pkrefund --reason "Hardware problem" jobid=503 start=today-7
92 
93  Refunds all jobs which id is 503 but which were printed during the
94  past week. The reason will be marked as being an hardware problem.
95 
96  $ pkrefund --force username=jerome printername=HP2100
97 
98  Refunds all jobs printed by user jerome on printer HP2100. No
99  confirmation will be asked.
100 
101  $ pkrefund --force printername=HP2100 start=200602 end=yesterday
102 
103  Refunds all jobs printed on printer HP2100 between February 1st 2006
104  and yesterday. No confirmation will be asked.
105""")
106       
107class PkRefund(PyKotaTool) :       
108    """A class for refund manager."""
109    validfilterkeys = [ "username",
110                        "printername",
111                        "hostname",
112                        "jobid",
113                        "billingcode",
114                        "start",
115                        "end",
116                      ]
117    def main(self, arguments, options, restricted=1) :
118        """Print Quota Data Dumper."""
119        if restricted and not self.config.isAdmin :
120            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
121           
122        extractonly = {}
123        for filterexp in arguments :
124            if filterexp.strip() :
125                try :
126                    (filterkey, filtervalue) = [part.strip() for part in filterexp.split("=")]
127                    filterkey = filterkey.lower()
128                    if filterkey not in self.validfilterkeys :
129                        raise ValueError               
130                except ValueError :   
131                    raise PyKotaCommandLineError, _("Invalid filter value [%s], see help.") % filterexp
132                else :   
133                    extractonly.update({ filterkey : filtervalue })
134           
135        username = extractonly.get("username")   
136        if username :
137            user = self.storage.getUser(username)
138        else :
139            user = None
140           
141        printername = extractonly.get("printername")   
142        if printername :
143            printer = self.storage.getPrinter(printername)
144        else :   
145            printer = None
146           
147        start = extractonly.get("start")
148        end = extractonly.get("end")
149        (start, end) = self.storage.cleanDates(start, end)
150       
151        jobs = self.storage.retrieveHistory(user=user,   
152                                            printer=printer, 
153                                            hostname=extractonly.get("hostname"),
154                                            billingcode=extractonly.get("billingcode"),
155                                            jobid=extractonly.get("jobid"),
156                                            start=start,
157                                            end=end,
158                                            limit=0)
159        peruser = {}                                   
160        nbjobs = 0                                   
161        nbpages = 0                                           
162        nbcredits = 0.0
163        reason = (options.get("reason") or "").strip()
164        for job in jobs :                                   
165            if job.JobSize and (job.JobAction not in ("DENY", "CANCEL", "REFUND")) :
166                if options["force"] :
167                    nbpages += job.JobSize
168                    nbcredits += job.JobPrice
169                    counters = peruser.setdefault(job.UserName, { "nbjobs" : 0, "nbpages" : 0, "nbcredits" : 0.0 })
170                    counters["nbpages"] += job.JobSize
171                    counters["nbcredits"] += job.JobPrice
172                    job.refund(reason)
173                    counters["nbjobs"] += 1
174                    nbjobs += 1
175                else :   
176                    print _("Date : %s") % str(job.JobDate)[:19]
177                    print _("JobId : %s") % job.JobId
178                    print _("Username : %s") % job.UserName
179                    print _("Printername : %s") % job.PrinterName
180                    print _("Billing code : %s") % job.JobBillingCode
181                    print _("Pages : %i") % job.JobSize
182                    print _("Credits : %.3f") % job.JobPrice
183                    print _("Title : %s") % job.JobTitle
184                   
185                    while True :                             
186                        answer = raw_input("\t%s ? " % _("Refund (Y/N)")).strip().upper()
187                        if answer == _("Y") :
188                            nbpages += job.JobSize
189                            nbcredits += job.JobPrice
190                            counters = peruser.setdefault(job.UserName, { "nbjobs" : 0, "nbpages" : 0, "nbcredits" : 0.0 })
191                            counters["nbpages"] += job.JobSize
192                            counters["nbcredits"] += job.JobPrice
193                            job.refund(reason)
194                            counters["nbjobs"] += 1
195                            nbjobs += 1
196                            break   
197                        elif answer == _("N") :   
198                            break
199                    print       
200        print _("Refunded %i jobs, %i pages and %.3f credits") % (nbjobs, nbpages, nbcredits)                                 
201           
202if __name__ == "__main__" : 
203    retcode = 0
204    try :
205        short_options = "vhfr"
206        long_options = ["help", "version", "force", "reason="]
207       
208        # Initializes the command line tool
209        refundmanager = PkRefund(doc=__doc__)
210        refundmanager.deferredInit()
211       
212        # parse and checks the command line
213        (options, args) = refundmanager.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1)
214       
215        # sets long options
216        options["help"] = options["h"] or options["help"]
217        options["version"] = options["v"] or options["version"]
218        options["force"] = options["f"] or options["force"]
219        options["reason"] = options["r"] or options["reason"]
220       
221        if options["help"] :
222            refundmanager.display_usage_and_quit()
223        elif options["version"] :
224            refundmanager.display_version_and_quit()
225        else :
226            retcode = refundmanager.main(args, options)
227    except KeyboardInterrupt :       
228        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
229        retcode = -3
230    except PyKotaCommandLineError, msg :   
231        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
232        retcode = -2
233    except SystemExit :       
234        pass
235    except :
236        try :
237            refundmanager.crashed("pkrefund failed")
238        except :   
239            crashed("pkrefund failed")
240        retcode = -1
241
242    try :
243        refundmanager.storage.close()
244    except (TypeError, NameError, AttributeError) :   
245        pass
246       
247    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.