def report_for_account(account, now, send=True): '''Sends all overtime reports to the managers of an account for a given date.''' DAYS_SHORT = [element[0] for element in WORKING_CHOICES if element[0] != "SATUR"] + ["ROVER"] buff = StringIO() buff.write("\xef\xbb\xbf") csvout = UnicodeWriter(buff, delimiter=';') users = Tbluser.objects.filter(market=account, disabled=False).order_by("lastname") # generate the dates for this month c = calendar.Calendar() dates = filter( lambda date: date.month == now.month, c.itermonthdates(now.year, now.month) ) csvout.writerow( # write out the top heading ["Date"] + [user.rev_name() for user in users] ) csvout.writerow( # write out the settlement period row. ["Settlement Period"] + [user.job_code[-1] if user.job_code else "" for user in users] ) csvout.writerow( # write out the e-mail row. ["EmployeeID"] + [user.user_id for user in users] ) csvout.writerow( # write out the total balances. ["Balance"] + ['="'+str(user.get_total_balance(ret='flo', year=now.year,month=now.month))+'"' for user in users] ) for date in dates: current_line = [str(date)] for user in users: try: entry = TrackingEntry.objects.get( user_id=user.id, entry_date=date ) except TrackingEntry.DoesNotExist: current_line.append("") continue if entry.daytype not in DAYS_SHORT: current_line.append("") continue if entry.is_linked(): current_line.append("") continue # if the entry is a return for overtime entry, we display # the user's shiftlength as a negative value since that's # what the value should be. value = round_down(entry.time_difference() if entry.daytype != "ROVER" else -entry.total_working_time()) current_line.append('="'+str(value)+'"' if value != 0 else "") csvout.writerow(current_line) csvfile = buff.getvalue() if send: message = mail.EmailMessage(from_email="*****@*****.**") message.body = \ "Hi,\n\n" \ "Please see attached your month end overtime report for " \ "your team.\n\n" \ "If there are any errors, please inform the administrator " \ "of the timetracker immediately.\n\n" \ "Regards,\n" \ "Timetracker team" message.attach( "overtimereport.csv", csvfile, "application/octet-stream" ) message.to = ["*****@*****.**"] + \ Tbluser.administrator_emails_for_account(account) message.subject = "End of month Overtime Totals." message.send() else: response = HttpResponse(csvfile, mimetype="text/csv") response['Content-Disposition'] = \ 'attachment;filename=MEC_OT_Report_%s.csv' % now return response
def send_report_for_account(account, now): '''Sends all overtime reports to the managers of an account for a given date.''' message = mail.EmailMessage(from_email="*****@*****.**") message.body = \ "Hi,\n\n" \ "Please see attached your month end overtime report for " \ "your team.\n\n" \ "If there are any errors, please inform the administrator " \ "of the timetracker immediately.\n\n" \ "Regards,\n" \ "Timetracker team" buff = StringIO() buff.write("\xef\xbb\xbf") csvout = UnicodeWriter(buff, delimiter=';') users = filter( lambda user: user.get_total_balance(ret='num') == 0, Tbluser.objects.filter(market=account, disabled=False) ) # generate the dates for this month c = calendar.Calendar() dates = filter( lambda date: date.month == now.month, c.itermonthdates(now.year, now.month) ) csvout.writerow( # write out the top heading ["Date"] + [user.rev_name() for user in users] ) csvout.writerow( # write out the settlement period row. ["Settlement Period"] + [user.job_code[-1] if user.job_code else "" for user in users] ) csvout.writerow( # write out the e-mail row. ["EmployeeID"] + [user.user_id for user in users] ) csvout.writerow( # write out the total balances. ["Balance"] + [str(user.get_total_balance(ret='num')) for user in users] ) for date in dates: current_line = [str(date)] for user in users: try: entry = TrackingEntry.objects.get(user_id=user.id, entry_date=date) except TrackingEntry.DoesNotExist: current_line.append("") continue if entry.is_overtime(): current_line.append(0-entry.time_difference()) else: current_line.append("") csvout.writerow(current_line) csvfile = buff.getvalue() message.attach( "overtimereport.csv", csvfile, "application/octet-stream" ) message.to = ["*****@*****.**"] + \ Tbluser.administrator_emails_for_account(account) message.subject = "End of month Overtime Totals." message.send()
def report_for_account(account, now, send=True): '''Sends all overtime reports to the managers of an account for a given date.''' DAYS_SHORT = [ element[0] for element in WORKING_CHOICES if element[0] != "SATUR" ] + ["ROVER"] buff = StringIO() buff.write("\xef\xbb\xbf") csvout = UnicodeWriter(buff, delimiter=';') users = Tbluser.objects.filter(market=account, disabled=False).order_by("lastname") # generate the dates for this month c = calendar.Calendar() dates = filter(lambda date: date.month == now.month, c.itermonthdates(now.year, now.month)) csvout.writerow( # write out the top heading ["Date"] + [user.rev_name() for user in users]) csvout.writerow( # write out the settlement period row. ["Settlement Period"] + [user.job_code[-1] if user.job_code else "" for user in users]) csvout.writerow( # write out the e-mail row. ["EmployeeID"] + [user.user_id for user in users]) csvout.writerow( # write out the total balances. ["Balance"] + [ '="' + str( user.get_total_balance( ret='flo', year=now.year, month=now.month)) + '"' for user in users ]) for date in dates: current_line = [str(date)] for user in users: try: entry = TrackingEntry.objects.get(user_id=user.id, entry_date=date) except TrackingEntry.DoesNotExist: current_line.append("") continue if entry.daytype not in DAYS_SHORT: current_line.append("") continue if entry.is_linked(): current_line.append("") continue # if the entry is a return for overtime entry, we display # the user's shiftlength as a negative value since that's # what the value should be. value = round_down(entry.time_difference( ) if entry.daytype != "ROVER" else -entry.total_working_time()) current_line.append('="' + str(value) + '"' if value != 0 else "") csvout.writerow(current_line) csvfile = buff.getvalue() if send: message = mail.EmailMessage(from_email="*****@*****.**") message.body = \ "Hi,\n\n" \ "Please see attached your month end overtime report for " \ "your team.\n\n" \ "If there are any errors, please inform the administrator " \ "of the timetracker immediately.\n\n" \ "Regards,\n" \ "Timetracker team" message.attach("overtimereport.csv", csvfile, "application/octet-stream") message.to = ["*****@*****.**"] + \ Tbluser.administrator_emails_for_account(account) message.subject = "End of month Overtime Totals." message.send() else: response = HttpResponse(csvfile, mimetype="text/csv") response['Content-Disposition'] = \ 'attachment;filename=MEC_OT_Report_%s.csv' % now return response
def utilization_calculation(teams, year=None, month=None): if year is None: # pragma: no cover year = datetime.today().year if month is None: # pragma: no cover month = datetime.today().month cached_result = cache.get("utilization:%s%s%s" % (''.join(teams), year, month)) if cached_result: # pragma: no cover return cached_result # prevent circular imports from timetracker.utils.calendar_utils import working_days from timetracker.tracker.models import Tbluser, TrackingEntry entries, invalid = ActivityEntry.filterforyearmonth(teams, year, month) if len(entries) == 0: return { "util": { "percent": 0, "target": 65 }, "effi": { "percent": 0, "target": 85 }, "avai": { "percent": 0, "target": 80 }, "FTE": 0 } effi, util = (0, 0) users = set() losses = TrackingEntry.objects.filter(user__market__in=teams, daytype=["PUABS", "DAYOD", "HOLIS"], entry_date__year=year, # 460 is a single # industrial engineering # FTE in Minutes. entry_date__month=month).count() * 460 for entry in entries: if invalid(entry): # pragma: no cover continue time = entry.amount * entry.activity.time if entry.activity.group != "ALL": util += time else: # pragma: no cover losses += time effi += time # so we can see how many FTE's we had during this month. users.add(entry.user) available_time = (Tbluser.available_minutes(teams) * len(working_days(year, month))) utilization_percent = (100 * (Decimal(util) / Decimal(available_time))) efficiency_percent = (100 * (Decimal(util) / (Decimal(available_time) - Decimal(losses)))) availability_percent = (100 * (Decimal(available_time) - Decimal(losses)) / Decimal(available_time)) res = { "util": { "percent": utilization_percent, "target": 65 }, "effi": { "percent": efficiency_percent, "target": 85 }, "avai": { "percent": availability_percent, "target": 80 }, "FTE": len(users) } cache.set("utilization:%s%s%s" % (''.join(teams), year, month), res) return res