예제 #1
0
def generate_record(record: Record) -> str:
    """
    Generates the PDF for a given record; returns the path to the record PDF.
    """
    _buffer = BytesIO()
    doc = get_default_document(
        _buffer, footer=EventSettings.objects.get().report_footer)
    style = get_paragraph_style()

    # Header: info text and qr code
    title_str = '[{}] {}beleg'.format(
        EventSettings.objects.get().short_name,
        'Einnahme' if record.type == 'inflow' else 'Ausgabe')
    title = Paragraph(title_str, style['Heading1'])
    tz = timezone.get_current_timezone()
    datetime = record.datetime.astimezone(tz)
    logo = scale_image(get_qr_image(record), 100)
    header = Table(
        data=[
            [[
                title,
            ], logo],
        ],
        colWidths=[doc.width / 2] * 2,
        style=TableStyle([
            ('ALIGN', (0, 0), (0, 0), 'LEFT'),
            ('ALIGN', (1, 0), (1, 0), 'RIGHT'),
            ('VALIGN', (0, 0), (1, 0), 'TOP'),
        ]),
    )
    info = [['Datum', datetime.strftime('%Y-%m-%d, %H:%M')],
            ['Von' if record.type == 'inflow' else 'Nach',
             str(record.entity)], ['Betrag',
                                   CURRENCY.format(record.amount)]]
    info = [[
        Paragraph(line[0], style['Heading3']),
        Paragraph(line[1], style['Normal'])
    ] for line in info]

    info_table = Table(
        data=info,
        colWidths=[90, doc.width - 90],
        style=TableStyle([]),
    )

    # Signatures
    col_width = (doc.width - 35) / 2
    signature1 = Table(
        data=[[
            'Bearbeiter/in: {}'.format(record.backoffice_user.get_full_name()),
            '', ''
        ]],
        colWidths=[col_width, 35, col_width],
        style=TableStyle([
            ('FONTSIZE', (0, 0), (0, 0), FONTSIZE),
            ('LINEABOVE', (0, 0), (0, 0), 1.2, colors.black),
            ('VALIGN', (0, 0), (0, 0), 'TOP'),
        ]),
    )
    if record.carrier:
        signature2 = Table(
            data=[[
                '{}: {}'.format(
                    'Einlieferer/in' if record.type == 'inflow' else
                    'Emfpänger/in', record.carrier), '', ''
            ]],
            colWidths=[col_width, 35, col_width],
            style=TableStyle([
                ('FONTSIZE', (0, 0), (0, 0), FONTSIZE),
                ('LINEABOVE', (0, 0), (0, 0), 1.2, colors.black),
                ('VALIGN', (0, 0), (0, 0), 'TOP'),
            ]),
        )

    story = [
        header,
        Spacer(1, 15 * mm),
        info_table,
        Spacer(1, 40 * mm),
        signature1,
    ]
    if record.carrier:
        story.append(Spacer(1, 40 * mm))
        story.append(signature2)
    doc.build(story)

    _buffer.seek(0)
    stored_name = default_storage.save(record.get_new_record_path(),
                                       ContentFile(_buffer.read()))
    return stored_name
예제 #2
0
def generate_report(session: CashdeskSession) -> str:
    """
    Generates a closing report for a CashdeskSession; returns the path to the
    report PDF.
    """
    _buffer = BytesIO()
    doc = get_default_document(
        _buffer, footer=EventSettings.objects.get().report_footer)
    style = get_paragraph_style()

    # Header: info text and qr code
    title_str = '[{}] Kassenbericht #{}'.format(
        EventSettings.objects.get().short_name, session.pk)
    title = Paragraph(title_str, style['Heading1'])
    tz = timezone.get_current_timezone()
    text = """{user} an {cashdesk}<br/>{start} – {end}""".format(
        user=session.user.get_full_name(),
        cashdesk=session.cashdesk,
        start=session.start.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S'),
        end=session.end.astimezone(tz).strftime('%Y-%m-%d %H:%M:%S'),
    )
    info = Paragraph(text, style['Normal'])
    logo = scale_image(get_qr_image(session), 100)

    header = Table(
        data=[
            [[title, info], logo],
        ],
        colWidths=[doc.width / 2] * 2,
        style=TableStyle([
            ('ALIGN', (0, 0), (0, 0), 'LEFT'),
            ('ALIGN', (1, 0), (1, 0), 'RIGHT'),
            ('VALIGN', (0, 0), (1, 0), 'TOP'),
        ]),
    )

    # Sales table
    sales_heading = Paragraph('Tickets', style['Heading3'])
    data = [
        ['Ticket', 'Einzelpreis', 'Presale', 'Verkauf', 'Stornos', 'Gesamt'],
    ]
    sales_raw_data = session.get_product_sales()
    sales = [[
        p['product'].name,
        CURRENCY.format(p['value_single']), p['presales'], p['sales'],
        p['reversals'],
        CURRENCY.format(p['value_total'])
    ] for p in sales_raw_data]
    data += sales
    data += [[
        '', '', '', '', '',
        CURRENCY.format(sum([p['value_total'] for p in sales_raw_data]))
    ]]
    last_row = len(data) - 1
    sales = Table(
        data=data,
        colWidths=[120] + [(doc.width - 120) / 5] * 5,
        style=TableStyle([
            ('FONTSIZE', (0, 0), (5, last_row), FONTSIZE),
            # TODO: register bold font and use here: ('FACE', (0,0), (3,0), 'boldfontname'),
            ('ALIGN', (0, 0), (0, last_row), 'LEFT'),
            ('ALIGN', (1, 0), (5, last_row), 'RIGHT'),
            ('LINEABOVE', (0, 1), (5, 1), 1.0, colors.black),
            ('LINEABOVE', (5, last_row), (5, last_row), 1.2, colors.black),
        ]),
    )

    # Items table
    items_heading = Paragraph('Auszählung', style['Heading3'])
    data = [
        ['', 'Einzählung', 'Umsatz', 'Auszählung', 'Differenz'],
    ]

    # geld immer decimal mit € und nachkommastellen
    cash_transactions = session.get_cash_transaction_total()
    cash = [
        [
            'Bargeld',
            CURRENCY.format(session.cash_before),
            CURRENCY.format(cash_transactions),
            CURRENCY.format(session.cash_after),
            CURRENCY.format(session.cash_before + cash_transactions -
                            session.cash_after)
        ],
    ]
    items = [[
        d['item'].name, d['movements'], d['transactions'],
        abs(d['final_movements']), d['total']
    ] for d in session.get_current_items()]
    last_row = len(items) + 1
    items = Table(
        data=data + cash + items,
        colWidths=[120] + [(doc.width - 120) / 4] * 4,
        style=TableStyle([
            ('FONTSIZE', (0, 0), (4, last_row), FONTSIZE),
            # TODO: register bold font and use here: ('FACE', (0,0), (3,0), 'boldfontname'),
            ('ALIGN', (0, 0), (0, last_row), 'LEFT'),
            ('ALIGN', (1, 0), (4, last_row), 'RIGHT'),
            ('LINEABOVE', (0, 1), (4, 1), 1.0, colors.black),
        ]),
    )

    # Signatures
    col_width = (doc.width - 35) / 2
    signatures = Table(
        data=[[
            'Kassierer/in: {}'.format(session.user.get_full_name()), '',
            'Ausgezählt durch {}'.format(
                session.backoffice_user_after.get_full_name())
        ]],
        colWidths=[col_width, 35, col_width],
        style=TableStyle([
            ('FONTSIZE', (0, 0), (2, 0), FONTSIZE),
            ('LINEABOVE', (0, 0), (0, 0), 1.2, colors.black),
            ('LINEABOVE', (2, 0), (2, 0), 1.2, colors.black),
            ('VALIGN', (0, 0), (2, 0), 'TOP'),
        ]),
    )

    story = [
        header,
        Spacer(1, 15 * mm),
        sales_heading,
        sales,
        Spacer(1, 10 * mm),
        items_heading,
        items,
        Spacer(1, 30 * mm),
        signatures,
    ]
    doc.build(story)

    _buffer.seek(0)
    stored_name = default_storage.save(session.get_new_report_path(),
                                       ContentFile(_buffer.read()))
    return stored_name
예제 #3
0
def generate_invoice(transaction: Transaction, address: str) -> str:
    path = transaction.get_invoice_path()
    if path:
        return path

    _buffer = BytesIO()
    settings = EventSettings.objects.get()
    doc = get_default_document(_buffer, footer=settings.invoice_footer)
    style = get_paragraph_style()

    # Header
    our_address = settings.invoice_address.replace('\n', '<br />')
    our_address = Paragraph(our_address, style['Normal'])
    our_title = Paragraph(_('Invoice from'), style['Heading5'])

    their_address = address.replace('\n', '<br />')
    their_address = Paragraph(their_address, style['Normal'])
    their_title = Paragraph(_('Invoice to'), style['Heading5'])

    data = [[their_title, '', our_title], [their_address, '', our_address]]
    header = Table(
        data=data,
        colWidths=[doc.width * 0.3, doc.width * 0.3, doc.width * 0.4],
        style=TableStyle([
            ('FONTSIZE', (0, 0), (2, 1), FONTSIZE),
            ('VALIGN', (0, 0), (2, 1), 'TOP'),
        ]),
    )
    date = Table(
        data=[[now().strftime('%Y-%m-%d')]],
        colWidths=[doc.width],
        style=TableStyle([
            ('ALIGN', (0, 0), (0, 0), 'RIGHT'),
        ]),
    )
    invoice_title = Paragraph(
        _('Invoice for receipt {}').format(transaction.receipt_id),
        style['Heading1'])

    data = [
        [_('Product'), _('Tax rate'),
         _('Net'), _('Gross')],
    ]
    total_tax = 0
    for position in transaction.positions.all():
        total_tax += position.tax_value
        data.append([
            position.product.name, '{} %'.format(position.tax_rate),
            CURRENCY.format(position.value - position.tax_value, ),
            CURRENCY.format(position.value)
        ])
    data.append([_('Included taxes'), '', '', CURRENCY.format(total_tax)])
    data.append(
        [_('Invoice total'), '', '',
         CURRENCY.format(transaction.value)])
    last_row = len(data) - 1

    transaction_table = Table(
        data=data,
        colWidths=[doc.width * 0.5] + [doc.width * 0.5 / 3] * 3,
        style=TableStyle([
            ('FONTSIZE', (0, 0), (3, last_row), FONTSIZE),
            # TODO: register bold font and use here: ('FACE', (0,0), (3,0), 'boldfontname'),
            ('ALIGN', (0, 0), (1, last_row), 'LEFT'),
            ('ALIGN', (2, 0), (3, last_row), 'RIGHT'),
            ('LINEABOVE', (0, 1), (3, 1), 1.0, colors.black),
            ('LINEABOVE', (3, last_row - 1), (3, last_row - 1), 1.0,
             colors.black),
            ('LINEABOVE', (3, last_row), (3, last_row), 1.2, colors.black),
        ]),
    )
    disclaimer_text = _('This invoice is only valid with receipt #{}.').format(
        transaction.receipt_id)
    disclaimer_text += _('The invoice total has already been paid.')
    disclaimer = Paragraph(disclaimer_text, style['Normal'])

    story = [
        header,
        Spacer(1, 15 * mm), date, invoice_title,
        Spacer(1, 25 * mm), transaction_table,
        Spacer(1, 25 * mm), disclaimer
    ]
    doc.build(story)
    _buffer.seek(0)
    stored_name = default_storage.save(
        transaction.get_invoice_path(allow_nonexistent=True),
        ContentFile(_buffer.read()))
    return stored_name