Changeset 3019

Show
Ignore:
Timestamp:
01/10/08 14:23:12 (1 year ago)
Author:
bobbysmith007
Message:

Got estimates saving and loading

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • estimatorplugin/0.11/estimatorplugin/api.py

    r3013 r3019  
    4848            success &= dbhelper.execute_in_trans( 
    4949                ("""CREATE TABLE estimate( 
    50                      id integer
     50                     id integer PRIMARY KEY
    5151                     rate DECIMAL, 
    5252                     variability DECIMAL, 
    53                      communication_overhead DECIMAL, 
    54                      ticket_id integer 
     53                     communication DECIMAL, 
     54                     tickets VARCHAR(512) 
    5555                 )""",[]), 
    5656                ("""CREATE TABLE estimate_line_item( 
    57                      id integer
     57                     id integer PRIMARY KEY
    5858                     estimate_id integer, 
    5959                     description VARCHAR(2048), 
    60                      low_hours DECIMAL, 
    61                      high_hours DECIMAL 
     60                     low DECIMAL, 
     61                     high DECIMAL 
    6262                )""",[])) 
    6363        # SHOULD BE LAST IN THIS FUNCTION 
  • estimatorplugin/0.11/estimatorplugin/dbhelper.py

    r3014 r3019  
    168168    def json_out(self): 
    169169        return "[%s]" % ','. join( 
    170             [("{%s}" % ','.join(["'%s':%r" %(key, self.value(val, row)) 
    171                                  for (key, val) in columnMap.items()])) 
    172              for row in rows]) 
     170            [("{%s}" % ','.join(["'%s':%r" %(key, str(self.value(val, row))) 
     171                                 for (key, val) in self.columnMap.items()])) 
     172             for row in self.rows]) 
  • estimatorplugin/0.11/estimatorplugin/htdocs/estimate.css

    r3014 r3019  
    66  margin:5px; 
    77} 
     8 
     9.numberCell{  
     10  text-align:right; 
     11  border:1px solid blue; 
     12} 
     13 
     14.fieldLabel{  
     15  font-weight:bold; 
     16  text-align:right; 
     17} 
  • estimatorplugin/0.11/estimatorplugin/htdocs/estimate.js

    r3013 r3019  
    1414      else return ""; 
    1515   } 
    16    var $$ = document.getElementById; 
     16 
    1717   var tr = cn('tr', {}, 
    1818             cn('td', {}, 
    19                 cn('textarea', {id:uid("description"), rows:2, cols:30}, 
     19                cn('textarea', {id:uid("description"), name:uid("description"), cols:30, style:"height: 34px;"}, 
    2020                   valFn('description'))), 
    2121             cn('td', { valign:'top'}, 
    22                 cn('input', {id:uid('low'), type:'text', style:"width:80px;",  
     22                cn('input', {id:uid('low'),name:uid('low'), type:'text', style:"width:80px;",  
    2323                         value: valFn('low'), onkeyup:'runCalculation()'})), 
    2424             cn('td', {valign:'top'}, 
    25                 cn('input', {id:uid('high'), type:'text', style:"width:80px;" 
     25                cn('input', {id:uid('high'), name:uid('high'),type:'text', style:"width:80px;" 
    2626                         , value: valFn('high'), onkeyup:'runCalculation()'})), 
    27              cn('td', {id:uid('ave'), valign:'top', style:"width:80px;"}), 
     27             cn('td', {id:uid('ave'), 'class':"numberCell", valign:'top', style:"width:80px;"}), 
    2828             cn('td', {id:uid('buttons'),valign:'top'}, 
    2929                cn('button',{onclick:'removeLineItem(this);return false;'},'remove'))); 
     
    4242} 
    4343 
    44 function makeMultiplierAccessor(id){ 
     44function makeNumberAccessor(id, def){ 
    4545   return function(){ 
    4646      var str = $$(id).value.trim(); 
    47       if (str.length == 0) return 1
     47      if (str.length == 0) return def
    4848      var val = Number(str); 
    49       if (isNaN(val)) return 1
     49      if (isNaN(val)) return def
    5050      return val; 
    5151   } 
    5252} 
    5353 
    54 var rate = makeMultiplierAccessor('rate'); 
    55 var variability = makeMultiplierAccessor('variability'); 
    56 var communication = makeMultiplierAccessor('communication'); 
     54var rate = makeNumberAccessor('rate', 1); 
     55var variability = makeNumberAccessor('variability', 1); 
     56var communication = makeNumberAccessor('communication', 1); 
    5757 
    58 var lineItemValue 
     58var ave_no_zero = function (x, y){ 
     59   if(x!=0 && y!=0){ 
     60      var val = (x+y)/2; 
     61      return Math.round(val * 1000)/1000; 
     62   } 
     63   else if (x !=0) return x; 
     64   else return y; 
     65
     66 
     67 
    5968function runCalculation(){ 
    6069   var item, lowTotal=0, highTotal=0, lowAdjusted, highAdjusted, 
     
    6574      } 
    6675      var valFn = function(str){ 
    67          var str = $$(uid(str)).value.trim(); 
    68          if (str.length == 0) return 0; 
    69          var val = Number(str); 
    70          if (isNaN(val)) return 0; 
    71          return val; 
     76         return makeNumberAccessor(uid(str), 0)(); 
    7277      } 
    7378      var low = valFn('low'); 
     
    7681      lowTotal+=low; 
    7782      highTotal+=high; 
    78       $$(uid('ave')).innerHTML = (low+high)/2
     83      $$(uid('ave')).innerHTML = ave_no_zero(low, high)
    7984   } 
    80    lowAdjusted = variability() * communication() * lowTotal ; 
    81    highAdjusted = variability() * communication() * highTotal ; 
    82    lowCost = rate() * lowAdjusted; 
    83    highCost = rate() * highAdjusted; 
     85   var adjust = function(num){ 
     86      return Math.round(num*1000)/1000; 
     87   } 
     88   lowTotal = adjust(lowTotal); 
     89   highTotal = adjust(highTotal); 
     90   lowAdjusted = adjust(variability() * communication() * lowTotal); 
     91   highAdjusted = adjust(variability() * communication() * highTotal); 
     92   lowCost = adjust(rate() * lowAdjusted); 
     93   highCost = adjust(rate() * highAdjusted); 
    8494   $$('lowTotal').innerHTML = lowTotal; 
    8595   $$('highTotal').innerHTML = highTotal; 
    86    $$('aveTotal').innerHTML = (lowTotal+highTotal) / 2
     96   $$('aveTotal').innerHTML = ave_no_zero(lowTotal, highTotal)
    8797   $$('lowAdjusted').innerHTML = lowAdjusted; 
    8898   $$('highAdjusted').innerHTML = highAdjusted; 
    89    $$('aveAdjusted').innerHTML = (lowAdjusted+highAdjusted) / 2
     99   $$('aveAdjusted').innerHTML = ave_no_zero(lowAdjusted, highAdjusted)
    90100   $$('lowCost').innerHTML = lowCost; 
    91101   $$('highCost').innerHTML = highCost; 
    92    $$('aveCost').innerHTML = (lowCost+highCost) / 2
     102   $$('aveCost').innerHTML = ave_no_zero(lowCost, highCost)
    93103}; 
    94104 
     
    97107   lineItems.removeItem(row.item);    
    98108   row.parentNode.removeChild(row); 
     109   runCalculation(); 
    99110} 
    100111 
  • estimatorplugin/0.11/estimatorplugin/templates/estimate.html

    r3014 r3019  
    99       
    1010  <head> 
    11         <title>Time Tracking Management for Trac.11</title> 
     11        <title>Advanced Estimations for Trac.11</title> 
    1212        <script type="text/javascript" src="${chrome.htdocs_location}js/wikitoolbar.js"></script> 
    1313        <script type="text/javascript" py:choose=""> 
     
    2020      <body> 
    2121        <form method="post" action="${estimate.href}" > 
    22  
     22          <input type="hidden" name="id" value="${estimate.id}"/> 
     23           
    2324          <div id="content" class="estimate"> 
    2425            <div id="messages" > 
     
    3031        <table border="0" cellpadding="3" cellspacing="0" > 
    3132          <tr> 
    32             <td ><label for="tickets">Ticket Numbers:</label></td> 
    33             <td><input id="tickets" type="text" /></td> 
     33            <td class="fieldLabel" ><label for="tickets">Ticket Numbers:</label></td> 
     34            <td><input id="tickets" name="tickets" type="text" 
     35                      value="${estimate.tickets}" /></td> 
    3436          </tr> 
    3537          <tr> 
    36             <td ><label for="rate">Rate</label></td> 
    37             <td><input id="rate" type="text" onkeyup="runCalculation()" value="${estimate.rate}" /></td> 
     38            <td class="fieldLabel" ><label for="rate">Rate:</label></td> 
     39            <td><input id="rate" name="rate" type="text" onkeyup="runCalculation()" 
     40                      value="${estimate.rate}" /></td> 
    3841          </tr> 
    3942          <tr> 
    40             <td ><label for="variability">Variability</label></td> 
    41             <td><input id="variability" type="text" onkeyup="runCalculation()" value="${estimate.variability}" /></td> 
     43            <td class="fieldLabel" ><label for="variability">Variability:</label></td> 
     44            <td><input id="variability" name="variability" type="text" onkeyup="runCalculation()" 
     45                      value="${estimate.variability}" /></td> 
    4246          </tr> 
    4347          <tr> 
    44             <td ><label for="communication">Communication</label></td> 
    45             <td><input id="communication" type="text" onkeyup="runCalculation()" value="${estimate.communication}" /></td> 
     48            <td class="fieldLabel" ><label for="communication">Communication:</label></td> 
     49            <td><input id="communication" name="communication" type="text" onkeyup="runCalculation()" 
     50                      value="${estimate.communication}" /></td> 
    4651          </tr> 
    4752        </table> 
    4853 
    4954 
    50         <table border="0" cellpadding="3" cellspacing="0" > 
    51           <tr id="header"
     55        <table border="0" cellpadding="3" cellspacing="1" > 
     56          <tr id="lineItemheader"
    5257            <th>Description</th> 
    5358            <th>Low </th> 
     
    6065 
    6166          <tr id="lineItemFooter"> 
    62             <th>Total:</th> 
    63             <td id="lowTotal" ></td> 
    64             <td id="highTotal"></td> 
    65             <td id="aveTotal"></td> 
     67            <th class="fieldLabel" >Total:</th> 
     68            <td id="lowTotal" class="numberCell" ></td> 
     69            <td id="highTotal" class="numberCell"></td> 
     70            <td id="aveTotal" class="numberCell"></td> 
    6671            <td>&nbsp; </td> 
    6772          </tr> 
    6873          <tr> 
    69             <th>Adjusted Hours:</th> 
    70             <td id="lowAdjusted"></td> 
    71             <td id="highAdjusted"></td> 
    72             <td id="aveAdjusted"></td> 
     74            <th class="fieldLabel">Adjusted Hours:</th> 
     75            <td id="lowAdjusted" class="numberCell" ></td> 
     76            <td id="highAdjusted" class="numberCell" ></td> 
     77            <td id="aveAdjusted" class="numberCell" ></td> 
    7378            <td>&nbsp; </td> 
    7479          </tr> 
    7580          <tr> 
    76             <th>Cost:</th> 
    77             <td id="lowCost"></td> 
    78             <td id="highCost"></td> 
    79             <td id="aveCost"></td> 
     81            <th class="fieldLabel">Cost:</th> 
     82            <td id="lowCost" class="numberCell" ></td> 
     83            <td id="highCost" class="numberCell" ></td> 
     84            <td id="aveCost" class="numberCell" ></td> 
    8085            <td>&nbsp; </td> 
    8186          </tr> 
     
    8388        <script language="javascript" > 
    8489           var lineItems = ${estimate.lineItems}; 
    85            loadLineItems( ); 
     90           loadLineItems(); 
    8691           newLineItem(); 
    8792        </script > 
  • estimatorplugin/0.11/estimatorplugin/webui.py

    r3014 r3019  
    88     INavigationContributor, ITemplateProvider 
    99from trac.web.href import Href 
     10from estimator import * 
     11 
    1012 
    1113class EstimationsPage(Component): 
     
    1315    def __init__(self): 
    1416        pass 
     17    def load(self, req, addMessage, data): 
     18        try: 
     19            id = int(req.args['id']) 
     20            data["estimate"]["id"] = id 
     21            estimate_rs = getEstimateResultSet(id) 
     22            if estimate_rs: 
     23                data["estimate"]["id"] = id 
     24                data["estimate"]["rate"] = estimate_rs.value("rate", 0) 
     25                data["estimate"]["tickets"] = estimate_rs.value("tickets", 0) 
     26                data["estimate"]["variability"] = estimate_rs.value("variability", 0) 
     27                data["estimate"]["communication"] = estimate_rs.value("communication", 0) 
     28                rs = getEstimateLineItemsResultSet(id) 
     29                if rs: 
     30                    data["estimate"]["lineItems"] = rs.json_out() 
     31            else: 
     32                addMessage('Cant Find Estimate Id: %s' % id) 
     33        except Exception, e: 
     34            addMessage('Invalid Id: %s' % req.args['id']) 
     35            addMessage('Error: %s' % e) 
     36    def line_item_hash_from_args(self, args): 
     37        not_line_items=['__FORM_TOKEN','tickets','variability','communication','rate', 'id'] 
     38        itemReg = re.compile(r"(\D+)(\d+)") 
     39        lineItems = {} 
     40        def lineItemHasher( value, name, id ): 
     41            if not lineItems.has_key(id): 
     42                lineItems[id] = {} 
     43            lineItems[id][name] = value 
     44        [lineItemHasher( item[1], *itemReg.match( item[0] ).groups()) 
     45         for item in args.items() 
     46         if not(not_line_items.__contains__(item[0]))] 
     47        return lineItems 
     48         
     49    def save_from_form (self, args, addMessage): 
     50        #try: 
     51            tickets = args["tickets"] 
     52            id = args["id"] 
     53            if id == None or id == '' : 
     54                sql = estimateInsert 
     55                id = nextEstimateId () 
     56            else: 
     57                sql = estimateUpdate 
    1558 
     59            estimate_args = [args['rate'], args['variability'], args['communication'], tickets, id] 
     60            saveEstimate = (sql, estimate_args) 
     61            saveLineItems = [] 
     62            newLineItemId = nextEstimateLineItemId () 
     63 
     64            # we want to delete any rows that were not included in the form request 
     65            # we will not use -1 as a valid id, so this will allow us to use the same sql reguardless of anything else 
     66            ids = ['-1']  
     67            lineItems = self.line_item_hash_from_args(args).items() 
     68            lineItems.sort() 
     69            for item in lineItems: 
     70                itemId = item[0] 
     71                if int(itemId) < 400000000:# new ids on the HTML are this number and above 
     72                    ids.append(str(itemId)) 
     73                    sql = lineItemUpdate 
     74                else: 
     75                    itemId = newLineItemId 
     76                    newLineItemId += 1 
     77                    sql = lineItemInsert 
     78                itemargs = [id, 
     79                            item[1]['description'], 
     80                            item[1]['low'], 
     81                            item[1]['high'], 
     82                            itemId] 
     83                saveLineItems.append((sql, itemargs)) 
     84 
     85            sql = removeLineItemsNotInListSql % ','.join(ids) 
     86            addMessage("Deleting NonExistant Estimate Rows: %r - %s" % (sql , id)) 
     87            result = dbhelper.execute_in_trans(saveEstimate, 
     88                                               (sql, id), 
     89                                               *saveLineItems) 
     90            if not result: 
     91                addMessage("Failed to save!") 
     92            else: 
     93                addMessage("Estimate Saved!") 
     94             
     95        #except Exception, e: 
     96        #    raise e 
     97        #    addMessage("Error Saving Estimate: %s" % e) 
     98             
     99    
    16100    # INavigationContributor methods 
    17101    def get_active_navigation_item(self, req): 
     
    30114    def match_request(self, req): 
    31115        return req.path_info.startswith('/Estimate') 
    32  
    33     def load(self, req, addMessage, data): 
    34         try: 
    35             id = int(req.args['id']) 
    36             data["estimate"]["id"] = id 
    37             estimate_rs = dbhelper.get_result_set("SELECT * FROM estimate WHERE estimate_id=%s", id) 
    38             if estimate_rs: 
    39                 data["estimate"]["rate"] = estimate_rs.get_value("rate", 0) 
    40                 data["estimate"]["variability"] = estimate_rs.get_value("variability", 0) 
    41                 data["estimate"]["communication"] = estimate_rs.get_value("communication", 0) 
    42                 rs = dbhelper.get_result_set("SELECT * FROM estimate_line_item WHERE estimate_id=%s", id) 
    43                 if rs: 
    44                     data["estimate"]["lineItems"] = rs.json_out() 
    45             else: 
    46                 addMessage('Cant Find Estimate Id: %s' % id) 
    47         except Exception, e: 
    48             addMessage('Invalid Id: %s' % id) 
    49             addMessage('Error: %s' % e) 
    50          
     116      
    51117    def process_request(self, req): 
    52118        messages = [] 
    53119        def addMessage(s): 
    54120            messages.extend([s]); 
     121        addMessage("Post Args: %s"% req.args.items()) 
    55122        if req.method == 'POST': 
    56             pass 
     123            self.save_from_form(req.args, addMessage) 
    57124        data = {} 
    58         data["estimate"]={"href":       req.href.Estimate(), 
    59                           "messages":   messages, 
    60                           "lineItems": '[]', 
    61                           "rate": self.config.get( 'estimator','default_rate') or 200, 
    62                           "variability": self.config.get( 'estimator','default_variability') or 1, 
    63                           "communication": self.config.get( 'estimator','default_communication') or 1, 
    64                           } 
     125        data["estimate"]={ 
     126            "href":       req.href.Estimate(), 
     127            "messages":   messages, 
     128            "id": None, 
     129            "lineItems": '[]', 
     130            "tickets": '', 
     131            "rate": self.config.get( 'estimator','default_rate') or 200, 
     132            "variability": self.config.get( 'estimator','default_variability') or 1, 
     133            "communication": self.config.get( 'estimator','default_communication') or 1, 
     134            } 
    65135         
    66         if req.args.has_key('id')
     136        if req.args.has_key('id') and req.args['id'].strip() != ''
    67137            self.load(req, addMessage, data) 
    68138 
     
    88158        rtn = [resource_filename(__name__, 'templates')] 
    89159        return rtn 
     160