root / pykota / trunk / bin / pkrefund @ 3066

Revision 3066, 9.0 kB (checked in by jerome, 17 years ago)

Now maintain per user counters for refunds. Doesn't use them yet.

  • 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  Contrary to other PyKota management tools, wildcard characters are not
63  expanded, so you can't use them.
64 
65Examples :
66
67  $ pkrefund jobid=503
68 
69  This will refund all jobs which Id is 503. BEWARE : installing CUPS
70  afresh will reset the first job id at 1. So you probably want to use
71  a more precise filter as explained below
72 
73  $ pkrefund --reason "Hardware problem" jobid=503 start=today-7
74 
75  Refunds all jobs which id is 503 but which were printed during the
76  past week. The reason will be marked as being an hardware problem.
77 
78  $ pkrefund --force username=jerome printername=HP2100
79 
80  Refunds all jobs printed by user jerome on printer HP2100. No
81  confirmation will be asked.
82 
83  $ pkrefund --force printername=HP2100 start=200602 end=yesterday
84 
85  Refunds all jobs printed on printer HP2100 between February 1st 2006
86  and yesterday. No confirmation will be asked.
87""")
88       
89class PkRefund(PyKotaTool) :       
90    """A class for refund manager."""
91    validfilterkeys = [ "username",
92                        "printername",
93                        "hostname",
94                        "jobid",
95                        "billingcode",
96                        "start",
97                        "end",
98                      ]
99    def main(self, arguments, options, restricted=1) :
100        """Print Quota Data Dumper."""
101        if restricted and not self.config.isAdmin :
102            raise PyKotaCommandLineError, "%s : %s" % (pwd.getpwuid(os.geteuid())[0], _("You're not allowed to use this command."))
103           
104        extractonly = {}
105        for filterexp in arguments :
106            if filterexp.strip() :
107                try :
108                    (filterkey, filtervalue) = [part.strip() for part in filterexp.split("=")]
109                    filterkey = filterkey.lower()
110                    if filterkey not in self.validfilterkeys :
111                        raise ValueError               
112                except ValueError :   
113                    raise PyKotaCommandLineError, _("Invalid filter value [%s], see help.") % filterexp
114                else :   
115                    extractonly.update({ filterkey : filtervalue })
116           
117        username = extractonly.get("username")   
118        if username :
119            user = self.storage.getUser(username)
120        else :
121            user = None
122           
123        printername = extractonly.get("printername")   
124        if printername :
125            printer = self.storage.getPrinter(printername)
126        else :   
127            printer = None
128           
129        start = extractonly.get("start")
130        end = extractonly.get("end")
131        (start, end) = self.storage.cleanDates(start, end)
132       
133        jobs = self.storage.retrieveHistory(user=user,   
134                                            printer=printer, 
135                                            hostname=extractonly.get("hostname"),
136                                            billingcode=extractonly.get("billingcode"),
137                                            jobid=extractonly.get("jobid"),
138                                            start=start,
139                                            end=end,
140                                            limit=0)
141        peruser = {}                                   
142        nbjobs = 0                                   
143        nbpages = 0                                           
144        nbcredits = 0.0
145        reason = (options.get("reason") or "").strip()
146        for job in jobs :                                   
147            if job.JobSize and (job.JobAction not in ("DENY", "CANCEL", "REFUND")) :
148                if options["force"] :
149                    nbpages += job.JobSize
150                    nbcredits += job.JobPrice
151                    counters = peruser.setdefault(job.UserName, { "nbjobs" : 0, "nbpages" : 0, "nbcredits" : 0.0 })
152                    counters["nbpages"] += job.JobSize
153                    counters["nbcredits"] += job.JobPrice
154                    job.refund(reason)
155                    counters["nbjobs"] += 1
156                    nbjobs += 1
157                else :   
158                    print _("Date : %s") % str(job.JobDate)[:19]
159                    print _("JobId : %s") % job.JobId
160                    print _("Username : %s") % job.UserName
161                    print _("Printername : %s") % job.PrinterName
162                    print _("Billing code : %s") % job.JobBillingCode
163                    print _("Pages : %i") % job.JobSize
164                    print _("Credits : %.3f") % job.JobPrice
165                    print _("Title : %s") % job.JobTitle
166                   
167                    while True :                             
168                        answer = raw_input("\t%s ? " % _("Refund (Y/N)")).strip().upper()
169                        if answer == _("Y") :
170                            nbpages += job.JobSize
171                            nbcredits += job.JobPrice
172                            counters = peruser.setdefault(job.UserName, { "nbjobs" : 0, "nbpages" : 0, "nbcredits" : 0.0 })
173                            counters["nbpages"] += job.JobSize
174                            counters["nbcredits"] += job.JobPrice
175                            job.refund(reason)
176                            counters["nbjobs"] += 1
177                            nbjobs += 1
178                            break   
179                        elif answer == _("N") :   
180                            break
181                    print       
182        print _("Refunded %i jobs, %i pages and %.3f credits") % (nbjobs, nbpages, nbcredits)                                 
183           
184if __name__ == "__main__" : 
185    retcode = 0
186    try :
187        short_options = "vhfr"
188        long_options = ["help", "version", "force", "reason="]
189       
190        # Initializes the command line tool
191        refundmanager = PkRefund(doc=__doc__)
192        refundmanager.deferredInit()
193       
194        # parse and checks the command line
195        (options, args) = refundmanager.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1)
196       
197        # sets long options
198        options["help"] = options["h"] or options["help"]
199        options["version"] = options["v"] or options["version"]
200        options["force"] = options["f"] or options["force"]
201        options["reason"] = options["r"] or options["reason"]
202       
203        if options["help"] :
204            refundmanager.display_usage_and_quit()
205        elif options["version"] :
206            refundmanager.display_version_and_quit()
207        else :
208            retcode = refundmanager.main(args, options)
209    except KeyboardInterrupt :       
210        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
211        retcode = -3
212    except PyKotaCommandLineError, msg :   
213        sys.stderr.write("%s : %s\n" % (sys.argv[0], msg))
214        retcode = -2
215    except SystemExit :       
216        pass
217    except :
218        try :
219            refundmanager.crashed("pkrefund failed")
220        except :   
221            crashed("pkrefund failed")
222        retcode = -1
223
224    try :
225        refundmanager.storage.close()
226    except (TypeError, NameError, AttributeError) :   
227        pass
228       
229    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.