Exemple #1
0
 def __init__(self, period):
     self.month = "%s-01" % period
     self.date = DateModel(self.month)
     self.start = self.date.get_month_start()
     self.stop = self.date.get_month_stop()
     self.period = cfg['purple_heart'][int(period.split("-")[1])]
 def __init__(self, period):
   self.month = "%s-01" % period
   self.date = DateModel(self.month)
   self.start = self.date.get_month_start()
   self.stop = self.date.get_month_stop()
   self.period = cfg['purple_heart'][int(period.split("-")[1])]
Exemple #3
0
class MonthlyReport(object):
    def __init__(self, period):
        self.month = "%s-01" % period
        self.date = DateModel(self.month)
        self.start = self.date.get_month_start()
        self.stop = self.date.get_month_stop()
        self.period = cfg['purple_heart'][int(period.split("-")[1])]

    def get_report(self):
        "Return a string ready to be printed."

        total_time = 0
        total_billable = 0
        office_time = {}
        not_active = []  # Employees with no time entries at all
        incomplete = []  # Employees with some entries, but not enough

        result_header = "Billing report for %s to %s (%d days total)\n\n" % (
            self.start, self.stop,
            cfg['daysofmonth'][self.date.get_month_number()])
        result_stats = ""
        result_rpt = ""

        # x.name.encode('utf-8')
        employees = Employee.query.order_by(Employee.number)

        for employee in employees:
            entries = self._get_employee_entries(employee.name.encode("utf-8"))

            if len(entries.keys()) > 0:
                total = 0
                avail = 0
                billable = 0
                eno = -1
                if employee.number is not None:
                    eno = employee.number
                result_rpt += ":: %s (%d) ::\n\n- Reported time\n" % (
                    employee.name.encode("utf-8"), eno)
                for customer in entries.keys():
                    for project in entries[customer].keys():
                        for task in entries[customer][project].keys():
                            result_rpt += "\t* %s / %s / %s:%0.2f\n" % (
                                customer, project, task,
                                entries[customer][project][task])
                            if task in cfg["billable"]:
                                billable += entries[customer][project][task]

                            if task in cfg["absence"]:
                                avail -= entries[customer][project][task]

                            total += entries[customer][project][task]
                result_rpt += "\t* Total time reported: %0.2f\n" % total

                available = cfg['daysofmonth'][
                    self.date.get_month_number()] * 8
                if cfg['parttime'].has_key(employee.name.encode("utf-8")):
                    available = available * cfg['parttime'][
                        employee.name.encode("utf-8")]

                total_time += available + avail
                total_billable += billable

                office = "No office"
                if employee.office is not None:
                    office = employee.office.name.encode('utf-8')
                if not office_time.has_key(office):
                    office_time[office] = {"total": 0, "billable": 0}

                office_time[office]["total"] += available + avail
                office_time[office]["billable"] += billable

                if total < available:
                    incomplete.append((employee, (available - total)))

                pos = PurchaseOrder.query.filter(
                    PurchaseOrder.start <= self.stop)
                pos = pos.filter(PurchaseOrder.stop >= self.start)
                pos = pos.filter(PurchaseOrder.employee == employee)

                result_rpt += "\n- Purchase orders\n"
                if pos.first() is not None:

                    for po in pos:
                        result_rpt += "\t- %s (%s)\n" % (po.customer.encode(
                            "utf-8"), po.reference.encode("utf-8"))
                        result_rpt += "\t\t* PO-number: %s\n" % str(
                            po.number).encode("utf-8")
                        result_rpt += "\t\t* Period: %s to %s\n" % (po.start,
                                                                    po.stop)
                        result_rpt += "\t\t* Price: %0.2f SEK/hour\n" % (
                            po.price)
                else:
                    result_rpt += "\t * NO PURCHASE ORDERS FOUND!\n"

                result_rpt += "\n- Billing ratio\n"
                result_rpt += "\t* Billable hours: %0.2f\n" % billable
                result_rpt += "\t* Available hours: %0.2f\n" % (available +
                                                                avail)
                result_rpt += "\t* Ratio: %d percent\n" % (
                    (billable / (available + avail)) * 100)

                result_rpt += "\n- Salary information\n"
                purple_hearts = 0
                overtime = 0
                for week in self.period:
                    winfo = _getWeekDetails(week, 2009, 2)
                    weekstart = strftime("%Y-%m-%d", winfo[0])
                    weekstop = strftime("%Y-%m-%d", winfo[1])
                    result_rpt += "\t - Week %d from %s to %s\n" % (
                        week, weekstart, weekstop)

                    tasks = Task.query.filter(Task.date >= weekstart)
                    tasks = tasks.filter(Task.date <= weekstop)
                    tasks = tasks.filter(Task.employee == employee)

                    week_total = 0
                    week_billable = 0
                    for task in tasks:
                        if not task.name == "Kompledighet":
                            week_total += task.hours

                        if task.name.encode("utf-8") in cfg["billable"]:
                            week_billable += task.hours

                        if task.project.name == "Internal" and task.name != "Kompetensutveckling":
                            result_rpt += "\t\t * %s %s - %0.2f hours\n" % (
                                task.name.encode("utf-8"), task.date,
                                task.hours)

                        if task.name == "Komptid" or task.name == "Uttag av komp":
                            week_total = week_total - task.hours

                    normal_time = cfg['normal_time']
                    if cfg['parttime'].has_key(employee.name.encode("utf-8")):
                        normal_time = normal_time * cfg['parttime'][
                            employee.name.encode("utf-8")]

                    otime = week_total - normal_time
                    result_rpt += "\t\t * Övertid: %0.2f hours\n" % otime
                    overtime += otime

                    result_rpt += "\t\t * Purple Heart time - %0.2f hours\n" % (
                        week_billable)

                    if week_billable >= cfg["normal_time"]:
                        purple_hearts += 1

                    result_rpt += "\t\t * Weekly total: %0.2f hours\n\n" % (
                        week_total)

                result_rpt += "\t - Övertidsdelta: %0.2f hours\n\n" % (
                    overtime)
                extra = 1
                if purple_hearts == len(self.period):
                    extra = 2
                result_rpt += "\t - Purple Hearts: %d of %d = %d kr\n" % (
                    purple_hearts, len(self.period),
                    (purple_hearts * 350) * extra)

                result_rpt += "\n\n\n"
            else:
                not_active.append(employee.name.encode("utf-8"))

        result_stats = "- Billing ratio\n\t- Company total\n\t\t* Available time: %0.2f\n\t\t* Billable time: %0.2f\n\t\t* Ratio: %d percent\n" % (
            total_time, total_billable, ((total_billable / total_time) * 100))

        for office in office_time.keys():
            result_stats += "\t- %s\n\t\t* Available time: %0.2f\n\t\t* Billable time: %0.2f\n\t\t* Ratio: %d percent\n" % (
                office, office_time[office]["total"],
                office_time[office]["billable"],
                ((office_time[office]["billable"] /
                  office_time[office]["total"]) * 100))

        if len(incomplete) > 0:
            result_stats += "\n\n- Incomplete reports\n"
        for emp, hours in incomplete:
            result_stats += "\t* %s is missing %0.2f hours\n" % (
                emp.name.encode('utf-8'), hours)

        result_stats += "\n\n"

        return result_header + result_stats + result_rpt

    def _get_employee_entries(self, employee):
        tasks = Task.query.filter(Task.date >= self.start)
        tasks = tasks.filter(Task.date <= self.stop)
        tasks = tasks.filter(
            Task.employee.has(name=unicode(employee, "utf-8")))
        return self._aggregate_by_customer(tasks)

    def _aggregate_by_customer(self, tasks):
        result = {}
        for task in tasks:
            customer = task.project.customer.name.encode("utf-8")
            project = task.project.name.encode("utf-8")
            task_name = task.name.encode("utf-8")

            if not result.has_key(customer):
                result[customer] = {}

            if not result[customer].has_key(project):
                result[customer][project] = {}

            if not result[customer][project].has_key(task_name):
                result[customer][project][task_name] = 0

            result[customer][project][task_name] += task.hours
        return result
class MonthlyReport(object):
  def __init__(self, period):
    self.month = "%s-01" % period
    self.date = DateModel(self.month)
    self.start = self.date.get_month_start()
    self.stop = self.date.get_month_stop()
    self.period = cfg['purple_heart'][int(period.split("-")[1])]
          
  def get_report(self):
    "Return a string ready to be printed." 
    
    total_time = 0
    total_billable = 0
    office_time = {}
    not_active = []  # Employees with no time entries at all
    incomplete = []  # Employees with some entries, but not enough
    
    result_header = "Billing report for %s to %s (%d days total)\n\n" % (self.start, self.stop, cfg['daysofmonth'][self.date.get_month_number()])  
    result_stats = ""
    result_rpt = ""

    # x.name.encode('utf-8')
    employees = Employee.query.order_by(Employee.number)

    for employee in employees:
      entries = self._get_employee_entries(employee.name.encode("utf-8"))
      
      if len(entries.keys()) > 0:
        total = 0
        avail = 0
        billable = 0
        eno = -1
        if employee.number is not None:
          eno = employee.number
        result_rpt += ":: %s (%d) ::\n\n- Reported time\n" % (employee.name.encode("utf-8"), eno)
        for customer in entries.keys():
          for project in entries[customer].keys():
            for task in entries[customer][project].keys():
              result_rpt += "\t* %s / %s / %s:%0.2f\n" % (customer, project, task, entries[customer][project][task])
              if task in cfg["billable"]:
                billable += entries[customer][project][task]
              
              if task in cfg["absence"]:
                avail -=  entries[customer][project][task]
                
              total += entries[customer][project][task]
        result_rpt += "\t* Total time reported: %0.2f\n" % total
        
        
        available = cfg['daysofmonth'][self.date.get_month_number()] * 8
        if cfg['parttime'].has_key(employee.name.encode("utf-8")):
          available = available * cfg['parttime'][employee.name.encode("utf-8")]
        
        total_time += available + avail
        total_billable += billable
        
        office = "No office"
        if employee.office is not None:
          office = employee.office.name.encode('utf-8')
        if not office_time.has_key(office):
          office_time[office] = { "total": 0, "billable": 0 }
        
        office_time[office]["total"] += available + avail
        office_time[office]["billable"] += billable
        
          
        if total < available:
          incomplete.append((employee, (available-total)))
          
        pos = PurchaseOrder.query.filter(PurchaseOrder.start <= self.stop)
        pos = pos.filter(PurchaseOrder.stop >= self.start)
        pos = pos.filter(PurchaseOrder.employee == employee)
        
        result_rpt += "\n- Purchase orders\n"
        if pos.first() is not None:
          
          for po in pos:
             result_rpt += "\t- %s (%s)\n" % (po.customer.encode("utf-8"), po.reference.encode("utf-8"))  
             result_rpt += "\t\t* PO-number: %s\n" % str(po.number).encode("utf-8")
             result_rpt += "\t\t* Period: %s to %s\n" % (po.start, po.stop) 
             result_rpt += "\t\t* Price: %0.2f SEK/hour\n" % (po.price) 
        else:
           result_rpt +=  "\t * NO PURCHASE ORDERS FOUND!\n"
        
        result_rpt += "\n- Billing ratio\n"
        result_rpt += "\t* Billable hours: %0.2f\n" % billable
        result_rpt += "\t* Available hours: %0.2f\n" % (available + avail)
        result_rpt += "\t* Ratio: %d percent\n" % ((billable/(available+avail))*100)
        
        result_rpt += "\n- Salary information\n"
        purple_hearts = 0
        overtime = 0
        for week in self.period:
          winfo = _getWeekDetails(week, 2009, 2)
          weekstart = strftime("%Y-%m-%d", winfo[0])                     
          weekstop = strftime("%Y-%m-%d", winfo[1])
          result_rpt += "\t - Week %d from %s to %s\n" % (week, weekstart, weekstop)
          
          tasks = Task.query.filter(Task.date >= weekstart) 
          tasks = tasks.filter(Task.date <= weekstop)
          tasks = tasks.filter(Task.employee == employee)
          
          week_total = 0
          week_billable = 0
          for task in tasks:
            if not task.name == "Kompledighet":
              week_total += task.hours
            
            if task.name.encode("utf-8") in cfg["billable"]:
               week_billable += task.hours            
            
            if task.project.name == "Internal" and task.name != "Kompetensutveckling":
              result_rpt += "\t\t * %s %s - %0.2f hours\n" % (task.name.encode("utf-8"), task.date, task.hours)
            
            if task.name == "Komptid" or task.name == "Uttag av komp":
              week_total = week_total - task.hours
          
          normal_time = cfg['normal_time']
          if cfg['parttime'].has_key(employee.name.encode("utf-8")):
            normal_time = normal_time * cfg['parttime'][employee.name.encode("utf-8")]
          
          otime = week_total - normal_time
          result_rpt += "\t\t * Övertid: %0.2f hours\n" %  otime
          overtime += otime   
            
          result_rpt += "\t\t * Purple Heart time - %0.2f hours\n" % (week_billable)
            
          if week_billable >= cfg["normal_time"]:
            purple_hearts += 1
          
          result_rpt +=  "\t\t * Weekly total: %0.2f hours\n\n" % (week_total)
        
        result_rpt += "\t - Övertidsdelta: %0.2f hours\n\n" % (overtime)
        extra = 1
        if purple_hearts == len(self.period):
          extra = 2
        result_rpt += "\t - Purple Hearts: %d of %d = %d kr\n" % (purple_hearts, len(self.period), (purple_hearts*350) * extra )   
        
        result_rpt += "\n\n\n"
      else:
        not_active.append(employee.name.encode("utf-8"))
      
    result_stats = "- Billing ratio\n\t- Company total\n\t\t* Available time: %0.2f\n\t\t* Billable time: %0.2f\n\t\t* Ratio: %d percent\n" %  (total_time, total_billable, ((total_billable/total_time)*100))
    
    for office in office_time.keys():
      result_stats += "\t- %s\n\t\t* Available time: %0.2f\n\t\t* Billable time: %0.2f\n\t\t* Ratio: %d percent\n" % (office, office_time[office]["total"], office_time[office]["billable"], ((office_time[office]["billable"]/office_time[office]["total"])*100))
    
    if len(incomplete) > 0:
      result_stats += "\n\n- Incomplete reports\n"
    for emp, hours in incomplete:
      result_stats += "\t* %s is missing %0.2f hours\n" % (emp.name.encode('utf-8'), hours)
    
    result_stats += "\n\n"
    
    return result_header + result_stats + result_rpt

  def _get_employee_entries(self,employee):
    tasks = Task.query.filter(Task.date >= self.start)
    tasks = tasks.filter(Task.date <= self.stop)
    tasks = tasks.filter(Task.employee.has(name=unicode(employee,"utf-8")))
    return self._aggregate_by_customer(tasks)

  def _aggregate_by_customer(self, tasks):
    result = {}
    for task in tasks:
      customer =  task.project.customer.name.encode("utf-8")
      project =  task.project.name.encode("utf-8")
      task_name = task.name.encode("utf-8")

      if not result.has_key(customer):
        result[customer] = {}

      if not result[customer].has_key(project):
        result[customer][project] = {}

      if not result[customer][project].has_key(task_name):
        result[customer][project][task_name] = 0

      result[customer][project][task_name] += task.hours
    return result