"""Export Mahjong Rankings as excel files.""" import os from datetime import date, time, datetime import openpyxl from django.conf import settings from django.core.management.base import BaseCommand from django.utils import timezone from django.utils.dateparse import parse_date from django.core.mail import EmailMessage from mahjong_ranking.models import SeasonRanking, KyuDanRanking THIN_BORDER = openpyxl.styles.Side(style='thin', color="d3d7cf") HEADING_STYLE = openpyxl.styles.NamedStyle(name="heading") HEADING_STYLE.font = openpyxl.styles.Font(name='Philosopher', size=11, bold=True, color='ffffff') HEADING_STYLE.fill = openpyxl.styles.PatternFill(fill_type='solid', start_color='a40000', end_color='a40000') DEFAULT_STYLE = openpyxl.styles.NamedStyle(name='content') DEFAULT_STYLE.font = openpyxl.styles.Font(name='Philosopher', size=10, bold=False, color='000000') DEFAULT_STYLE.border = openpyxl.styles.Border(bottom=THIN_BORDER, top=THIN_BORDER) INT_STYLE = openpyxl.styles.NamedStyle(name='int') INT_STYLE.font = DEFAULT_STYLE.font INT_STYLE.border = DEFAULT_STYLE.border INT_STYLE.number_format = '#,##0' FLOAT_STYLE = openpyxl.styles.NamedStyle(name='float') FLOAT_STYLE.font = DEFAULT_STYLE.font FLOAT_STYLE.border = DEFAULT_STYLE.border FLOAT_STYLE.number_format = '#,##0.00' DATE_STYLE = openpyxl.styles.NamedStyle(name='date') DATE_STYLE.font = DEFAULT_STYLE.font DATE_STYLE.border = DEFAULT_STYLE.border DATE_STYLE.number_format = 'dd.mm.yyyy' MAIL_BODY = """ Hallo! Ich bin's dein Server. Ich habe gerade die Mahjong Rankings als Excel exportiert und dachte mir das ich sie dir am besten gleich schicke. Bitte versuche nicht auf diese E-Mail zu antworten. Ich bin nur ein dummes Programm. mit lieben Grüßen Der Kasu Server """ def geneate_excel(): """Generate an excel .xlsx spreadsheet from json data of the kyu/dan rankings. :param json_data: The ladder ranking as JSON export.""" workbook = openpyxl.Workbook() workbook.add_named_style(HEADING_STYLE) workbook.add_named_style(DEFAULT_STYLE) workbook.add_named_style(INT_STYLE) workbook.add_named_style(FLOAT_STYLE) workbook.add_named_style(DATE_STYLE) for sheet in workbook.worksheets: workbook.remove(sheet) return workbook def generate_sheet(workbook, title, columns_settings, json_data): row = 1 ws = workbook.create_sheet() ws.title = title ws.syncHorizontal = True ws.filterMode = True # setup print orientation ws.page_setup.orientation = ws.ORIENTATION_PORTRAIT ws.page_setup.paperSize = ws.PAPERSIZE_A4 ws.page_setup.fitToWidth = True ws.print_options.horizontalCentered = True # setup page header ws.oddHeader.left.text = title ws.oddHeader.left.size = 14 ws.oddHeader.left.font = "Amerika Sans" ws.oddHeader.left.color = "000000" ws.oddHeader.right.text = str(date.today()) ws.oddHeader.right.size = 14 ws.oddHeader.right.font = "Amerika Sans" ws.oddHeader.right.color = "000000" # write table header for column, data in enumerate(columns_settings, 1): cell = ws.cell(column=column, row=row, value=data['title']) cell.style = 'heading' # write the table content for line in json_data: row += 1 for column, settings in enumerate(columns_settings, 1): cell = ws.cell(column=column, row=row, value=line[settings['attr']]) cell.style = settings['style'] # set column widths for settings in columns_settings: ws.column_dimensions[settings['col']].width = settings['width'] def export_season_rankings(workbook, until): SeasonRanking.objects.update(until=until) json_data = SeasonRanking.objects.json_data() title = "Mahjong Ladder - {}".format(until.year) columns_settings = ( {'col': 'A', 'title': 'Rang', 'attr': 'placement', 'style': 'int', 'width': 8}, {'col': 'B', 'title': 'Spitzname', 'attr': 'username', 'style': 'content', 'width': 25}, {'col': 'C', 'title': '⌀ Platz', 'attr': 'avg_placement', 'style': 'float', 'width': 8}, {'col': 'D', 'title': '⌀ Punkte', 'attr': 'avg_score', 'style': 'float', 'width': 12}, {'col': 'E', 'title': 'Hanchans', 'attr': 'hanchan_count', 'style': 'int', 'width': 10}, {'col': 'F', 'title': 'Gut', 'attr': 'good_hanchans', 'style': 'int', 'width': 5}, {'col': 'G', 'title': 'Gewonnen', 'attr': 'won_hanchans', 'style': 'int', 'width': 10}, ) generate_sheet( workbook=workbook, title=title, columns_settings=columns_settings, json_data=json_data) def export_kyu_dan_rankings(workbook, until): KyuDanRanking.objects.update(until=until) json_data = KyuDanRanking.objects.json_data() title = "Kyū & Dan Rankings" columns_settings = ( {'col': 'A', 'title': 'Spitzname', 'attr': 'username', 'style': 'content', 'width': 14}, {'col': 'B', 'title': 'Voller Name', 'attr': 'full_name', 'style': 'content', 'width': 20}, {'col': 'C', 'title': 'Rang', 'attr': 'rank', 'style': 'content', 'width': 8}, {'col': 'D', 'title': 'Punkte', 'attr': 'points', 'style': 'int', 'width': 8}, {'col': 'E', 'title': 'Hanchans', 'attr': 'hanchan_count', 'style': 'int', 'width': 10}, {'col': 'F', 'title': 'Gut', 'attr': 'good_hanchans', 'style': 'int', 'width': 5}, {'col': 'G', 'title': 'Gewonnen', 'attr': 'won_hanchans', 'style': 'int', 'width': 8}, {'col': 'H', 'title': 'letzte Hanchan', 'attr': 'last_hanchan_date', 'style': 'date', 'width': 16}, ) generate_sheet( workbook=workbook, title=title, columns_settings=columns_settings, json_data=json_data) class Command(BaseCommand): """Exports the SeasonRankings""" filename = str() until = datetime def add_arguments(self, parser): parser.add_argument( '--until', nargs='?', type=parse_date, default=date.today(), metavar='YYYY-MM-DD', help='Calculate and export rankings until the given date.') parser.add_argument( '--mail', nargs='*', type=str, metavar='user@example.com', help='Send the spreadsheet via eMail to the given recipient.') def handle(self, *args, **options): """Exports the current ladder ranking in a spreadsheet. This is useful as a backup in form of a hardcopy.""" self.until = timezone.make_aware(datetime.combine( options['until'], time(23, 59, 59) )) self.filename = os.path.join( settings.RANKING_EXPORT_PATH, 'mahjong_rankings_{:%Y-%m-%d}.xlsx'.format(self.until) ) workbook = geneate_excel() export_season_rankings(workbook, until=self.until) export_kyu_dan_rankings(workbook, until=self.until) os.makedirs(settings.RANKING_EXPORT_PATH, exist_ok=True) workbook.save(self.filename) if options['mail']: self.send_mail(options['mail']) def send_mail(self, recipients): mail = EmailMessage( subject='Mahjong Rankings vom {:%d.%m.%Y}'.format(self.until), body=MAIL_BODY, from_email=settings.DEFAULT_FROM_EMAIL, to=recipients) mail.attach_file(self.filename) mail.send()