source: timingandestimationplugin/branches/trac0.10/scripts/trac_billing.py

Last change on this file was 1283, checked in by Russ Tyndall, 17 years ago

TimingAndEstimationPlugin:

Moved everything into the trunk folder

File size: 5.4 KB
Line 
1from datetime import datetime as dt
2import time
3from utils import mail
4import adw_tracdb as db
5
6#defaultUrl= "https://sekhemt.acceleration.net/ADW/"
7_defaultUrl= "https://10.10.10.219/projects"
8_htmlLocation = '/var/BigVisibleCharts/Billing'
9
10def cond ( boolExpr, trueResult, falseResult ):
11    """ This is the classic ?: operator from languages like C expressed in python (from dive into python)
12    """
13    return (boolExpr and [trueResult] or [falseResult])[0]
14
15
16
17def accumulator():
18    var = [0]
19    def fn(*params):
20        for param in params:
21            var[0] = var[0] + param
22        return var[0]
23    return fn
24
25def progn(*params):
26    return params[-1]
27
28def prinTrue(s):
29    print s
30    return True
31
32
33def wn (name, attribs, *children):
34    return "<%s %s>\n%s\n</%s>\n" % \
35           (name, \
36            ' '.join(['%s="%s"' % (key, val) for (key, val) in attribs.items()]), \
37            '\n'.join([str(c) for c in children]), \
38            name)
39
40def ticket_link (number, projUrl):
41    return wn('a' , {'href':'/'.join([projUrl,'ticket' ,str(number)])}, "#"+str(number))
42
43def milestone_link (name, projUrl):
44    name = str(name)
45    return wn('a' , {'href':'/'.join([projUrl,'milestone' ,name])}, name)
46
47def make_project_output(project, rs, totalAcc):
48    projAcc = accumulator()
49    projLink = '/'.join([_defaultUrl, project ])
50   
51    def make_cell(idx, val):
52        if(idx == rs.columnMap['ticket']):
53            val = ticket_link(val, projLink)
54        elif idx == rs.columnMap['milestone'] and val != '&nbsp;':
55            val = milestone_link(val, projLink)
56        elif idx == rs.columnMap['hours']:
57            projAcc(float(val))
58            totalAcc(float(val))
59        return wn('td', {}, val)
60   
61    return progn(wn('div', {},
62                    wn('h2', {},
63                       wn('a',{'href':projLink},project)),
64                    wn('table', {"cellspacing":"0", "border":"1", "cellpadding":"3"},
65                       wn('tr', {},
66                          *[wn('th',{}, name) for name in rs.columnNames]),
67                       *[wn('tr', {},
68                            *[make_cell(idx, val)
69                              for idx in range(0, len(row))
70                              for val in [row[idx]]])
71                         for row in rs.rows]),
72                    wn('span',{}, "Total: "+str(projAcc()))))
73
74def make_all_projects_output():
75    totalAcc = accumulator()
76    sql = """
77SELECT
78 CASE WHEN t.milestone IS NOT NULL and t.milestone <> '' THEN t.milestone
79 ELSE '&nbsp;'
80 END as milestone,
81 t.id as ticket,
82 SUM(newvalue) as hours,
83 t.summary as summary,
84 strftime('%m/%d/%Y %H:%M:%S', MAX(ticket_change.time), 'unixepoch', 'localtime') as [most-recent-update] ,
85 (SELECT CASE WHEN MAX(time) IS NOT NULL THEN strftime('%m/%d/%Y %H:%M:%S', MAX(time), 'unixepoch', 'localtime')
86       ELSE 'No previous bill date'
87       END as time FROM bill_date ) as [previous-bill-date]
88FROM ticket as t
89LEFT JOIN ticket_custom as billable on billable.ticket = t.id
90  AND billable.name = 'billable'
91JOIN ticket_change on t.id = ticket_change.ticket
92  AND (
93     ticket_change.time >
94     (SELECT CASE WHEN MAX(time) IS NOT NULL THEN MAX(time)
95       ELSE 0
96       END as time FROM bill_date )
97)
98WHERE ticket_change.field = 'hours'
99    AND billable.value=1
100GROUP BY t.milestone, t.id
101"""
102
103    billingInfo = db.collectResultsFromAllTracs(sql);
104    projects_output = '\n'.join([make_project_output(project, rs, totalAcc)
105                                 for (project, rs) in billingInfo
106                                 if rs.rows ])
107    return wn('html', {},
108              wn('head', {}),
109              wn('body', {},
110                 projects_output,
111                 wn('span',{},"Total hours billed: "+str(totalAcc()))))
112
113
114def save_output_to_file(output, when=0):
115    if not when:
116        when = dt.now()
117    fname = '_'.join(["billing", str(when.year),
118                      str(when.month), str(when.day),
119                      str(when.hour), str(when.minute), ".html"])
120    p = "/".join([_htmlLocation, fname])
121    print "----"
122    print "Writing out billing information to '%s'" % p
123    print "----"
124    f = open(p, "w")
125    f.write(output)
126    f.close();
127
128
129
130def run_billing(emails="ryan@acceleration.net", when=0):   
131    if not when:
132        when = dt.now()
133    date = '/'.join([str(when.month), str(when.day), str(when.year)])
134   
135    print "Collecting output..."
136    output = make_all_projects_output()
137    save_output_to_file(output, when)
138    print "Emailing results to %s" % emails
139    if emails:
140        mail.mail(emails, 'Trac Billing - %s ' % date, output, html=True, fromEmail='trac-tickets@acceleration.net')
141    return output
142   
143   
144
145def add_bill_date(project, username="Timing and Estimation Plugin",  when=0):
146    now = time.time()
147    if not when:
148        when = now
149    when = int(when)
150    now = int(now)
151    sql = """
152    INSERT INTO bill_date (time, set_when, str_value)
153    VALUES (?, ?, strftime('%m/%d/%Y %H:%M:%S',?, 'unixepoch', 'localtime'))
154    """
155    db.executeNonQuery(project, sql, when, now, when)
156
157def mark_billing_date_in_all_projects(when=0 ):
158    print "Marking the bill date on all projects."
159    if not when:
160        when = time.time()
161    for project in db.projects:
162        try:
163            add_bill_date(project,  "Timing and Estimation Plugin",  when);
164            print "%s Succeeded." % project
165        except Exception, e:
166            print "* %s failed: %s" % (project , e.args)
167    print "Done marking bill dates"
168   
169
170
171             
172             
173       
Note: See TracBrowser for help on using the repository browser.