예제 #1
0
  def get_summary(self, req, fromdate = None, todate = None):
    def myformat_date(dte):
      if dte:
        return format_date(dte, '%e %b %Y')
      return 'No date set'
    def myformat_hours(hrs, fallback='No estimate available'):
      from math import floor
      if hrs:
        hrs = float(hrs)
        if 0 != hrs:
          neg = False
          if hrs < 0:
            neg = True
            hours *= -1
          mins = floor((hrs - floor(hrs)) * 60)
          str = ''
          if neg:
            str = '-'
          if hrs:
            str = "%s%sh" % (str, int(floor(hrs)))
          if mins:
            str = "%s %sm" % (str, int(mins))
          return str;
      return fallback

    client = self.client
    xml = etree.Element('clientsplugin')

    # Place basic client info here
    xclient = etree.SubElement(xml, 'client')
    etree.SubElement(xclient, 'name').text = client
    if fromdate:
      etree.SubElement(xclient, 'lastupdate').text = myformat_date(fromdate)

    # Information about milestones
    milestones = {}
    xmilestones = etree.SubElement(xml, 'milestones')

    db = self.env.get_read_db()
    have_data = False
    # Load in a summary of the client's tickets
    sql = ("""\
      SELECT t.id, t.summary, t.description, t.status, t.milestone,
        m.due, m.completed, m.description AS mdesc,
        tcust2.value AS estimatedhours, tcust3.value AS totalhours
      FROM ticket_custom AS tcust
      INNER JOIN ticket AS t ON tcust.ticket=t.id
      LEFT JOIN ticket_custom AS tcust2 ON t.id=tcust2.ticket AND tcust2.name='estimatedhours'
      LEFT JOIN ticket_custom AS tcust3 ON t.id=tcust3.ticket AND tcust3.name='totalhours'
      LEFT JOIN milestone m ON t.milestone=m.name
      WHERE tcust.name = 'client'
        AND tcust.value = %s
        AND t.milestone IN (
          SELECT DISTINCT st.milestone
          FROM ticket_custom AS stcust
          INNER JOIN ticket AS st ON stcust.ticket=st.id
          INNER JOIN milestone AS sm ON st.milestone=sm.name
          WHERE stcust.name = tcust.name
          AND stcust.value = tcust.value
          AND (sm.due > %s OR sm.completed > %s))
      ORDER BY m.due ASC
      """)
    cur2 = db.cursor()
    now = int(time.time()*1000000)
    cur2.execute(sql, (client, now, (now - (7*24*60*60*1000000))))
    xsummary = etree.SubElement(xml, 'summary')
    for tid, summary, description, status, milestone, due, completed, mdescription, estimatedhours, totalhours in cur2:
      have_data = True
      if milestone:
        if not milestones.has_key(milestone):
          xmilestone = etree.SubElement(xmilestones, 'milestone')
          etree.SubElement(xmilestone, 'name').text = milestone
          etree.SubElement(xmilestone, 'duetimestamp').text = str(due)
          etree.SubElement(xmilestone, 'due').text = myformat_date(due)
          if completed:
            etree.SubElement(xmilestone, 'completed').text = myformat_date(completed)
          if mdescription:
            xmilestone.append(etree.XML('<description>%s</description>' % wiki_to_html(extract_client_text(mdescription), self.env, req)))
          else:
            etree.SubElement(xmilestone, 'description').text = ''
          # Store for use
          milestones[milestone] = { 'hours': 0, 'xml': xmilestone }

        # Add hours to create a total.
        if estimatedhours:
          milestones[milestone]['hours'] += float(estimatedhours) 

      self.env.log.debug("  Summarising ticket #%s" % tid)
      ticket = etree.SubElement(xsummary, 'ticket')
      etree.SubElement(ticket, 'id').text = str(tid)
      etree.SubElement(ticket, 'summary').text = summary
      ticket.append(etree.XML('<description>%s</description>' % wiki_to_html(extract_client_text(description), self.env, req)))
      etree.SubElement(ticket, 'status').text = status
      etree.SubElement(ticket, 'milestone').text = milestone
      # For conveneince, put the date here too (keeps the XSLTs simpler)
      etree.SubElement(ticket, 'due').text = myformat_date(due)
      if estimatedhours:
        etree.SubElement(ticket, 'estimatedhours').text = myformat_hours(estimatedhours)

      if totalhours:
        etree.SubElement(ticket, 'totalhours').text = myformat_hours(totalhours, 'None')


    # Put the total hours into the milestone info
    for milestone in milestones:
      etree.SubElement(milestones[milestone]['xml'], 'estimatedhours').text = myformat_hours(milestones[milestone]['hours'])

    if self.debug:
      file = open('/tmp/send-client-email.xml', 'w')
      file.write(etree.tostring(xml, pretty_print=True))
      file.close()
      self.env.log.debug(" Wrote XML to /tmp/send-client-email.xml")

    if not have_data:
      return None

    return xml
예제 #2
0
  def get_summary(self, req, fromdate = None, todate = None):
    def myformat_date(dte):
      if dte:
        return format_date(dte, '%e %b %Y')
      return 'No date set'
    def myformat_hours(hrs, fallback='No estimate available'):
      from math import floor
      if hrs:
        hrs = float(hrs)
        if 0 != hrs:
          neg = False
          if hrs < 0:
            neg = True
            hours *= -1
          mins = floor((hrs - floor(hrs)) * 60)
          str = ''
          if neg:
            str = '-'
          if hrs:
            str = "%s%sh" % (str, int(floor(hrs)))
          if mins:
            str = "%s %sm" % (str, int(mins))
          return str;
      return fallback

    client = self.client
    xml = etree.Element('clientsplugin')

    # Place basic client info here
    xclient = etree.SubElement(xml, 'client')
    etree.SubElement(xclient, 'name').text = client
    if fromdate:
      etree.SubElement(xclient, 'lastupdate').text = myformat_date(fromdate)

    # Information about milestones
    months = {}
    xmonths = etree.SubElement(xml, 'months')

    db = self.env.get_read_db()
    have_data = False
    # Load in a summary of the client's tickets
    sql = ("""\
      SELECT t.id, t.summary, t.description, t.status,
        SUM(tchng.newvalue) AS totalhours, CONCAT(MONTHNAME(FROM_UNIXTIME(tchng.time/1000000)), " ", YEAR(FROM_UNIXTIME(tchng.time/1000000))) AS month
      FROM ticket_custom AS tcust
      INNER JOIN ticket AS t ON tcust.ticket=t.id
      INNER JOIN ticket_change AS tchng ON t.id=tchng.ticket AND tchng.field='hours' AND tchng.oldvalue=0
      WHERE tcust.name = 'client'
        AND tcust.value = %s
        AND tchng.time >= (UNIX_TIMESTAMP(PERIOD_ADD(EXTRACT(YEAR_MONTH FROM NOW()), -3)*100+1)*1000000)
      GROUP BY t.id, MONTH(FROM_UNIXTIME(tchng.time/1000000))
      ORDER BY tchng.time desc;
      """)
    cur2 = db.cursor()
    cur2.execute(sql, (client,))
    xsummary = etree.SubElement(xml, 'summary')
    for tid, summary, description, status, totalhours, month in cur2:
      have_data = True

      if not months.has_key(month):
        xmonth = etree.SubElement(xmonths, 'month')
        etree.SubElement(xmonth, 'name').text = month
        months[month] = { 'totalhours': 0, 'xml': xmonth }

      # Add hours to create a total.
      months[month]['totalhours'] += float(totalhours) 

      self.env.log.debug("  Summarising ticket #%s in %s" % (tid, month))
      ticket = etree.SubElement(xsummary, 'ticket')
      etree.SubElement(ticket, 'id').text = str(tid)
      etree.SubElement(ticket, 'summary').text = summary
      ticket.append(etree.XML('<description>%s</description>' % wiki_to_html(extract_client_text(description), self.env, req)))
      etree.SubElement(ticket, 'status').text = status
      etree.SubElement(ticket, 'month').text = month

      etree.SubElement(ticket, 'totalhours').text = myformat_hours(totalhours, 'None')


    # Put the total hours into the month info
    for month in months:
      etree.SubElement(months[month]['xml'], 'totalhours').text = myformat_hours(months[month]['totalhours'])

    if self.debug:
      file = open('/tmp/send-client-email.xml', 'w')
      file.write(etree.tostring(xml, pretty_print=True))
      file.close()
      self.env.log.debug(" Wrote XML to /tmp/send-client-email.xml")

    if not have_data:
      return None

    return xml
  def get_summary(self, req, fromdate = None, todate = None):
    def myformat_date(dte):
      if dte:
        return format_date(dte, '%e %b %Y')
      return 'No date set'
    def myformat_hours(hrs):
      from math import floor
      if hrs:
        hrs = float(hrs)
        if 0 != hrs:
          neg = False
          if hrs < 0:
            neg = True
            hours *= -1
          mins = floor((hrs - floor(hrs)) * 60)
          str = ''
          if neg:
            str = '-'
          if hrs:
            str = "%s%sh" % (str, int(floor(hrs)))
          if mins:
            str = "%s %sm" % (str, int(mins))
          return str;
      return 'No estimate available'

    client = self.client
    xml = etree.Element('clientsplugin')

    # Place basic client info here
    xclient = etree.SubElement(xml, 'client')
    etree.SubElement(xclient, 'name').text = client
    if fromdate:
      etree.SubElement(xclient, 'lastupdate').text = myformat_date(fromdate)

    db = self.env.get_read_db()
    have_data = False
    # Load in any changes that have happend
    sql = ("""\
      SELECT t.id, t.summary, t.description, t.status, t.resolution, t.milestone, m.due,
        tchng.field, tchng.oldvalue, tchng.newvalue
      FROM ticket_custom tcust
      INNER JOIN ticket AS t ON tcust.ticket=t.id
      INNER JOIN ticket_change AS tchng ON t.id=tchng.ticket
      LEFT JOIN milestone AS m ON t.milestone=m.name
      WHERE tcust.name = 'client'
        AND tcust.value = %s
        AND tchng.field IN ('comment', 'status', 'resolution', 'milestone')
        AND tchng.time >= %s
        AND tchng.time < %s
        AND t.milestone IN (
          SELECT DISTINCT st.milestone
          FROM ticket_custom AS stcust
          INNER JOIN ticket AS st ON stcust.ticket=st.id
          INNER JOIN milestone AS sm ON st.milestone=sm.name
          WHERE stcust.name = tcust.name
          AND stcust.value = tcust.value
          AND sm.due > 0)
      ORDER BY t.time
      """)
    cur2 = db.cursor()
    cur2.execute(sql, (client, fromdate*1000000, todate*1000000))
    changes = etree.SubElement(xml, 'changes')
    lasttid = 0
    for tid, summary, description, status, resolution, milestone, due, cgfield, oldvalue, newvalue in cur2:
      text = ''
      if 'status' == cgfield:
        text = 'Status changed from "%s" to "%s"' % (oldvalue, newvalue)
      elif 'milestone' == cgfield:
        text = 'Milestone changed from "%s" to "%s" - please check for revised delivery date.' % (oldvalue, newvalue)
      elif 'resolution' == cgfield:
        if oldvalue and not newvalue:
          text = 'Resolution removed'
        elif not oldvalue and newvalue:
          text = 'Resolution set to "%s"' % (newvalue)
        else:
          text = 'Resolution changed from "%s" to "%s"' % (oldvalue, newvalue)
      elif 'comment' == cgfield:
        # Todo - extract...
        text = extract_client_text(newvalue).strip()
        if '' == text:
          # No comments for the client here so ignore it.
          continue
        text = "''Comment for your information:''[[BR]][[BR]]" + text
      else:
        # Client should not know any more than this
        continue
      
      if self.debug:
        self.env.log.debug("  Change notification (%s) for ticket #%s" % (cgfield, tid))
      have_data = True
      if lasttid != tid:
        ticket = etree.SubElement(changes, 'ticket')
        etree.SubElement(ticket, 'id').text = str(tid)
        etree.SubElement(ticket, 'summary').text = summary
        ticket.append(etree.XML('<description>%s</description>' % wiki_to_html(extract_client_text(description), self.env, req)))
        etree.SubElement(ticket, 'status').text = status
        etree.SubElement(ticket, 'resolution').text = resolution
        etree.SubElement(ticket, 'milestone').text = milestone
        etree.SubElement(ticket, 'due').text = myformat_date(due)
        changelog = etree.SubElement(ticket, 'changelog')

      detail = etree.XML('<detail>%s</detail>' % wiki_to_html(text, self.env, req))
      detail.set('field', cgfield)
      if oldvalue:
        detail.set('oldvalue', oldvalue)
      if newvalue:
        detail.set('newvalue', newvalue)
      changelog.append(detail)
      lasttid = tid

    if self.debug:
      file = open('/tmp/send-client-email.xml', 'w')
      file.write(etree.tostring(xml, pretty_print=True))
      file.close()
      self.env.log.debug(" Wrote XML to /tmp/send-client-email.xml")

    if not have_data:
      return None

    return xml
    def get_summary(self, req, fromdate=None, todate=None):
        def myformat_date(dte):
            if dte:
                return format_date(dte, '%e %b %Y')
            return "No date set"

        def myformat_hours(hrs, fallback='No estimate available'):
            from math import floor
            if hrs:
                hrs = float(hrs)
                if 0 != hrs:
                    neg = False
                    if hrs < 0:
                        neg = True
                        hrs *= -1
                    mins = floor((hrs - floor(hrs)) * 60)
                    s = ''
                    if neg:
                        s = '-'
                    if hrs:
                        s = "%s%sh" % (s, int(floor(hrs)))
                    if mins:
                        s = "%s %sm" % (s, int(mins))
                    return s
            return fallback

        client = self.client
        xml = etree.Element('clientsplugin')

        # Place basic client info here
        xclient = etree.SubElement(xml, 'client')
        etree.SubElement(xclient, 'name').text = client
        if fromdate:
            etree.SubElement(xclient, 'lastupdate').text = \
                myformat_date(fromdate)

        # Information about milestones
        months = {}
        xmonths = etree.SubElement(xml, 'months')

        have_data = False
        # Load in a summary of the client's tickets
        sql = ("""\
          SELECT t.id, t.summary, t.description, t.status,
            SUM(tchng.newvalue) AS totalhours,
            CONCAT(MONTHNAME(FROM_UNIXTIME(tchng.time/1000000)),
            " ",
            YEAR(FROM_UNIXTIME(tchng.time/1000000))) AS month
          FROM ticket_custom AS tcust
          INNER JOIN ticket AS t ON tcust.ticket=t.id
          INNER JOIN ticket_change AS tchng
            ON t.id=tchng.ticket
              AND tchng.field='hours'
              AND tchng.oldvalue=0
          WHERE tcust.name = 'client'
            AND tcust.value = %s
            AND tchng.time >= (UNIX_TIMESTAMP(PERIOD_ADD(EXTRACT(YEAR_MONTH FROM NOW()), -3)*100+1)*1000000)
          GROUP BY t.id, MONTH(FROM_UNIXTIME(tchng.time/1000000))
          ORDER BY tchng.time DESC;
          """)
        xsummary = etree.SubElement(xml, 'summary')
        for tid, summary, description, status, totalhours, month \
                in self.env.db_query(sql, (client,)):
            have_data = True

            if month not in months:
                xmonth = etree.SubElement(xmonths, 'month')
                etree.SubElement(xmonth, 'name').text = month
                months[month] = {'totalhours': 0, 'xml': xmonth}

            # Add hours to create a total.
            months[month]['totalhours'] += float(totalhours)

            self.log.debug("  Summarising ticket #%s in %s", tid, month)
            ticket = etree.SubElement(xsummary, 'ticket')
            etree.SubElement(ticket, 'id').text = str(tid)
            etree.SubElement(ticket, 'summary').text = summary
            ticket.append(
                etree.XML('<description>%s</description>' %
                          format_to_html(self.env, web_context(req),
                                         extract_client_text(description))))
            etree.SubElement(ticket, 'status').text = status
            etree.SubElement(ticket, 'month').text = month

            etree.SubElement(ticket, 'totalhours').text = myformat_hours(
                totalhours, 'None')

        # Put the total hours into the month info
        for month in months:
            etree.SubElement(months[month]['xml'], 'totalhours').\
                text = myformat_hours(months[month]['totalhours'])

        if self.debug:
            with open('/tmp/send-client-email.xml', 'w') as file_:
                file_.write(etree.tostring(xml, pretty_print=True))
            self.log.debug(" Wrote XML to /tmp/send-client-email.xml")

        if not have_data:
            return None

        return xml