source: timingandestimationplugin/branches/trac0.10/timingandestimationplugin/ticket_daemon.py

Last change on this file was 4233, checked in by Russ Tyndall, 15 years ago

fixes #3646

There were a couple of flaws in the logic of recording ticket times.
I cleaned that up a bit, and verified that it correctly records times and estimations

File size: 5.3 KB
RevLine 
[1119]1from trac.ticket import ITicketChangeListener, Ticket
2from trac.core import *
[1710]3import datetime
[1119]4
[1710]5def identity(x):
6    return x;
7
[2015]8try:
9    import trac.util.datefmt
10    to_timestamp = trac.util.datefmt.to_timestamp
11except Exception:
12    to_timestamp = identity
[1710]13
[2015]14
[1119]15def save_custom_field_value( db, ticket_id, field, value ):
16    cursor = db.cursor();
17    cursor.execute("SELECT * FROM ticket_custom " 
18                   "WHERE ticket=%s and name=%s", (ticket_id, field))
19    if cursor.fetchone():
20        cursor.execute("UPDATE ticket_custom SET value=%s "
21                       "WHERE ticket=%s AND name=%s",
22                       (value, ticket_id, field))
23    else:
[1578]24        cursor.execute("INSERT INTO ticket_custom (ticket,name, "
[1119]25                       "value) VALUES(%s,%s,%s)",
[1578]26                       (ticket_id, field, value))
[4069]27    db.commit()
[4168]28   
29DONTUPDATE = "DONTUPDATE"
30
31def save_ticket_change( db, ticket_id, author, change_time, field, oldvalue, newvalue, log, dontinsert=False):
[4233]32    """tries to save a ticket change,
33 
34       dontinsert means do not add the change if it didnt already exist
35    """
[1710]36    if type(change_time) == datetime.datetime:
37        change_time = to_timestamp(change_time)
[1119]38    cursor = db.cursor();
[1710]39    sql = """SELECT * FROM ticket_change 
40             WHERE ticket=%s and author=%s and time=%s and field=%s""" 
41                   
42    cursor.execute(sql, (ticket_id, author, change_time, field))
[1119]43    if cursor.fetchone():
[4168]44        if oldvalue == DONTUPDATE:
45            cursor.execute("""UPDATE ticket_change  SET  newvalue=%s 
[1710]46                       WHERE ticket=%s and author=%s and time=%s and field=%s""",
[4168]47                           ( newvalue, ticket_id, author, change_time, field))
48
49        else:
50            cursor.execute("""UPDATE ticket_change  SET oldvalue=%s, newvalue=%s 
51                       WHERE ticket=%s and author=%s and time=%s and field=%s""",
52                           (oldvalue, newvalue, ticket_id, author, change_time, field))
[1119]53    else:
[4168]54        if oldvalue == DONTUPDATE:
55            oldvalue = '0'
56        if not dontinsert:
57            cursor.execute("""INSERT INTO ticket_change  (ticket,time,author,field, oldvalue, newvalue)
[1710]58                        VALUES(%s, %s, %s, %s, %s, %s)""",
[4168]59                           (ticket_id, change_time, author, field, oldvalue, newvalue))
[4069]60    db.commit()
[1119]61
62class TimeTrackingTicketObserver(Component):
63    implements(ITicketChangeListener)
64    def __init__(self):
65        pass
66
67    def watch_hours(self, ticket):
[4168]68       
[1119]69        def readTicketValue(name, tipe, default=0):
70            if ticket.values.has_key(name):       
71                return tipe(ticket.values[name] or default)
72            else:
73                cursor = self.env.get_db_cnx().cursor()
[1840]74                cursor.execute("SELECT * FROM ticket_custom where ticket=%s and name=%s" , (ticket.id, name))
[1119]75                val = cursor.fetchone()
76                if val:
77                    return tipe(val[2] or default)
78                return default
[4233]79
[4158]80        #some european countries use , as the decimal separator
[4170]81        convertfloat = lambda x: float(str(x).replace(',','.'))
[4158]82        hours = readTicketValue("hours", convertfloat)
83        totalHours = readTicketValue("totalhours", convertfloat)
[1627]84
[4168]85        db = self.env.get_db_cnx()
86        ticket_id = ticket.id
87        cl = ticket.get_changelog()
[4233]88       
89        self.log.debug("found hours: "+str(hours ));
[4168]90        #self.log.debug("Dir_ticket:"+str(dir(ticket)))
91        #self.log.debug("ticket.values:"+str(ticket.values))
[4233]92        #self.log.debug("changelog:"+str(cl))
93   
[4168]94        most_recent_change = None
95        if cl:
96            most_recent_change = cl[-1];
97            change_time = most_recent_change[0]
98            author = most_recent_change[1]
99        else:
100            change_time = ticket.time_created
101            author = ticket.values["reporter"]
102           
[4233]103
104        ## SAVE estimated hour
105        estimatedhours = readTicketValue("estimatedhours", convertfloat)       
106        self.log.debug("found Estimated hours:"+str(estimatedhours))
[4168]107        db = self.env.get_db_cnx()
[4233]108        save_ticket_change( db, ticket_id, author, change_time, "estimatedhours", DONTUPDATE, str(estimatedhours), self.log, True)
[4168]109        save_custom_field_value( db, ticket.id, "estimatedhours", str(estimatedhours))
110        db.commit();
[4233]111        #######################
[4168]112
[4233]113
114        ## If our hours changed
[4168]115        if not hours == 0:               
[1119]116            newtotal = str(totalHours+hours)
[4233]117            save_ticket_change( db, ticket_id, author, change_time, "hours", '0.0', str(hours), self.log)
[1710]118            save_ticket_change( db, ticket_id, author, change_time, "totalhours", str(totalHours), str(newtotal), self.log)
[1119]119            save_custom_field_value( db, ticket_id, "hours", '0')
[1667]120            save_custom_field_value( db, ticket_id, "totalhours", str(newtotal) )           
[4233]121        ########################
[1119]122
[4233]123    # END of watch_hours
124
[1119]125    def ticket_created(self, ticket):
126        """Called when a ticket is created."""
127        self.watch_hours(ticket)
128                               
129
[1286]130    def ticket_changed(self, ticket, comment, author, old_values):
[1119]131        """Called when a ticket is modified.
132       
133        `old_values` is a dictionary containing the previous values of the
134        fields that have changed.
135        """
136        self.watch_hours(ticket)
137
138    def ticket_deleted(self, ticket):
139        """Called when a ticket is deleted."""
Note: See TracBrowser for help on using the repository browser.