예제 #1
0
def latex_address(address1, address2, postal_code, city, country_code):
    address2_latex = ''
    if len(address2) > 0:
        address2_latex = '\\linebreak '
        address2_latex += unicode(TexTools.escape(address2)).encode('utf-8')
    return LATEX_ADDRESS.format(
        address1_latex=unicode(TexTools.escape(address1)).encode('utf-8'),
        address2_latex=address2_latex,
        postal_code_latex=unicode(
            TexTools.escape(postal_code)).encode('utf-8'),
        city=unicode(TexTools.escape(city)).encode('utf-8'),
        country_code=unicode(TexTools.escape(country_code)).encode('utf-8'))
예제 #2
0
def latex_membership_loss(membership_loss_date, membership_loss_type):
    membership_loss = u''
    if membership_loss_date is not None:
        membership_loss += membership_loss_date.strftime('%d.%m.%Y')
    if membership_loss_type is not None:
        membership_loss += '\\linebreak '
        membership_loss += unicode(TexTools.escape(
            membership_loss_type)).encode('utf-8')
    return membership_loss
예제 #3
0
 def test_escape(self):
     """
     Test method TexTools.escape
     """
     unescaped = u'&%$#_{}~^\\<>℅°ß'
     escaped = TexTools.escape(unescaped)
     expected = u'\\&\\%\\$\\#\\_\\{\}\\textasciitilde{}\\^{}' + \
                u'\\textbackslash{}\\textless{}\\textgreater{}c/o\\degree{}\\ss{}'
     self.assertEqual(escaped, expected)
예제 #4
0
 def test_escape(self):
     """
     Test method TexTools.escape
     """
     unescaped = u'&%$#_{}~^\\<>℅°ß'
     escaped = TexTools.escape(unescaped)
     expected = u'\\&\\%\\$\\#\\_\\{\}\\textasciitilde{}\\^{}' + \
                u'\\textbackslash{}\\textless{}\\textgreater{}c/o\\degree{}\\ss{}'
     self.assertEqual(escaped, expected)
예제 #5
0
def create_pdf(tex_vars, tpl_tex, invoice):
    """
    Create the invoice PDF
    """
    receipt_pdf = tempfile.NamedTemporaryFile(suffix='.pdf')

    (path, filename) = os.path.split(receipt_pdf.name)
    filename = os.path.splitext(filename)[0]

    # generate tex command for pdflatex
    tex_cmd = u''
    for key, val in tex_vars.iteritems():
        tex_cmd += '\\newcommand{\\%s}{%s}' % (key, TexTools.escape(val))
    tex_cmd += '\\input{%s}' % tpl_tex
    tex_cmd = u'"'+tex_cmd+'"'

    # make latex show ß correctly in pdf:
    tex_cmd = tex_cmd.replace(u'ß', u'\\ss{}')

    subprocess.call(
        [
            'pdflatex',
            '-jobname', filename,
            '-output-directory', path,
            '-interaction', 'nonstopmode',
            '-halt-on-error',
            tex_cmd.encode('latin_1')
        ],
        stdout=open(os.devnull, 'w'),  # hide output
        stderr=subprocess.STDOUT,
        cwd=PDFLATEX_DIR
    )

    # cleanup
    aux = os.path.join(path, filename + '.aux')
    if os.path.isfile(aux):
        os.unlink(aux)

    archive_dues19_invoice(receipt_pdf, invoice)

    return receipt_pdf
예제 #6
0
def member_list_date_pdf_view(request):
    """
    The membership list *for a given date* for printout as PDF.
    The date is supplied in and parsed from the URL, e.g.
    http://0.0.0.0:6543/aml-2014-12-31.pdf

    The PDF is generated using pdflatex.

    If the date is not parseable, an error message is shown.
    """
    try:
        _date_m = request.matchdict['date']
        _date = datetime.strptime(_date_m, '%Y-%m-%d').date()
    except (KeyError, ValueError):
        request.session.flash(
            "Invalid date! '{}' does not compute! "
            "try again, please! (YYYY-MM-DD)".format(
                _date_m),
            'message_to_user'
        )
        return HTTPFound(request.route_url('error_page'))

    """
    All member entries are loaded.
    """
    # query the database
    _order_by = 'lastname'
    _num = C3sMember.get_number()
    _all_members = C3sMember.member_listing(
        _order_by, how_many=_num, offset=0, order=u'asc')

    # prepare variables
    _members = []  # the members, filtered
    _count_members = 0  # count those members
    _count_shares = 0  # count their shares
    _count_shares_printed = 0  # cross-check...

    """
    ...and filtered for

    * active members (membership_accepted)
    * with membership numbers (cross-check)
    * who have become members before the given date.

    They are added to a list and counted.
    Their shares (those acquired before the date) are counted as well.
    """
    # filter and count memberships and shares
    for item in _all_members:
        if (
                (item.membership_number is not None) and
                item.is_member(_date)):
            # add this item to the filtered list of members
            _members.append(item)
            _count_members += 1
            # also count their shares iff acquired in the timespan
            for share in item.shares:
                if (date(
                        share.date_of_acquisition.year,
                        share.date_of_acquisition.month,
                        share.date_of_acquisition.day,
                ) <= _date):
                    _count_shares += share.number

    """
    The list of members is then sorted by

    * their given name
    * their last name,

    using locale.strcoll with german locale.
    This achieves a sort order like in phone books.
    """

    # sort members alphabetically
    import locale
    locale.setlocale(locale.LC_ALL, "de_DE.UTF-8")
    # ...by fist name
    _members.sort(key=lambda x: x.firstname, cmp=locale.strcoll)
    # ...and then by their last name
    _members.sort(key=lambda x: x.lastname, cmp=locale.strcoll)

    """
    Then a LaTeX file is constructed...
    """
    here = os.path.dirname(__file__)
    latex_header_tex = os.path.abspath(
        os.path.join(here, '../membership_list_pdflatex/header'))
    latex_footer_tex = os.path.abspath(
        os.path.join(here, '../membership_list_pdflatex/footer'))

    # a temporary directory for the latex run
    _tempdir = tempfile.mkdtemp()
    # now we prepare a .tex file to be pdflatex'ed
    latex_file = tempfile.NamedTemporaryFile(
        suffix='.tex',
        dir=_tempdir,
        delete=False,  # directory will be deleted anyways
    )
    # and where to store the output
    pdf_file = tempfile.NamedTemporaryFile(
        dir=_tempdir,
        delete=False,  # directory will be deleted anyways
    )
    pdf_file.name = latex_file.name.replace('.tex', '.pdf')

    # construct latex data: header + variables
    latex_data = '''
\\input{%s}
\\def\\numMembers{%s}
\\def\\numShares{%s}
\\def\\sumShares{%s}
\\def\\today{%s}
    ''' % (
        latex_header_tex,
        _count_members,
        _count_shares,
        _count_shares * 50,
        _date.strftime('%d.%m.%Y'),
    )

    # add to the latex document
    latex_data += '''
\\input{%s}''' % latex_footer_tex

    # print '*' * 70
    # print latex_data
    # print '*' * 70
    latex_file.write(latex_data.encode('utf-8'))

    # make table rows per member
    for member in _members:
        _address = '''\\scriptsize{}'''
        _address += '''{}'''.format(
            unicode(TexTools.escape(member.address1)).encode('utf-8'))

        # check for contents of address2:
        if len(member.address2) > 0:
            _address += '''\\linebreak {}'''.format(
                unicode(TexTools.escape(member.address2)).encode('utf-8'))
        # add more...
        _address += ''' \\linebreak {} '''.format(
            unicode(TexTools.escape(member.postcode)).encode('utf-8'))
        _address += '''{}'''.format(
            unicode(TexTools.escape(member.city)).encode('utf-8'))
        _address += ''' ({})'''.format(
            unicode(TexTools.escape(member.country)).encode('utf-8'))

        # check shares acquired until $date
        _acquired_shares_until_date = 0
        for share in member.shares:
            if date(
                    share.date_of_acquisition.year,
                    share.date_of_acquisition.month,
                    share.date_of_acquisition.day) <= _date:
                _acquired_shares_until_date += share.number
                _count_shares_printed += share.number

        membership_loss = u''
        if member.membership_loss_date is not None:
            membership_loss += \
                member.membership_loss_date.strftime('%d.%m.%Y') + \
                '\\linebreak '
        if member.membership_loss_type is not None:
            membership_loss += member.membership_loss_type
        latex_file.write(
            ''' {0} & {1} & {2} & {3} & {4} & {5} & {6}  \\\\\\hline %
            '''.format(
                TexTools.escape(member.lastname).encode('utf-8'),  # 0
                ' \\footnotesize ' + TexTools.escape(
                    member.firstname).encode('utf-8'),  # 1
                ' \\footnotesize ' + TexTools.escape(
                    str(member.membership_number)),  # 2
                _address,  # 3
                ' \\footnotesize ' + member.membership_date.strftime(
                    '%d.%m.%Y'),  # 4
                ' \\footnotesize ' + membership_loss + ' ',  # 5
                ' \\footnotesize ' + str(_acquired_shares_until_date)  # 6
            ))

    latex_file.write('''
%\\end{tabular}%
\\end{longtable}%
\\label{LastPage}
\\end{document}
''')
    latex_file.seek(0)  # rewind

    # pdflatex latex_file to pdf_file
    fnull = open(os.devnull, 'w')  # hide output
    pdflatex_output = subprocess.call(
        [
            'pdflatex',
            '-output-directory=%s' % _tempdir,
            latex_file.name
        ],
        stdout=fnull, stderr=subprocess.STDOUT  # hide output
    )
    if DEBUG:  # pragma: no cover
        print("the output of pdflatex run: %s" % pdflatex_output)

    # if run was a success, run X times more...
    if pdflatex_output == 0:
        for i in range(2):
            pdflatex_output = subprocess.call(
                [
                    'pdflatex',
                    '-output-directory=%s' % _tempdir,
                    latex_file.name
                ],
                stdout=fnull, stderr=subprocess.STDOUT  # hide output
            )
            if DEBUG:  # pragma: no cover
                print("run #{} finished.".format(i+1))

    # sanity check: did we print exactly as many shares as calculated?
    assert(_count_shares == _count_shares_printed)

    # return a pdf file
    response = Response(content_type='application/pdf')
    response.app_iter = open(pdf_file.name, "r")
    shutil.rmtree(_tempdir, ignore_errors=True)  # delete temporary directory
    return response
예제 #7
0
def generate_membership_list_pdf(effective_date, members):
    template_path = os.path.join(
        os.path.dirname(__file__),
        '../../../membership_list_pdflatex')
    latex_dir = tempfile.mkdtemp()
    latex_file = tempfile.NamedTemporaryFile(
        suffix='.tex',
        dir=latex_dir,
        delete=False,
    )

    shares_count = sum([member['shares_count'] for member in members])

    latex_file.write(
        LATEX_HEADER.format(
            header_file=os.path.abspath(
                os.path.join(
                    template_path,
                    'header')),
            footer_file=os.path.abspath(
                os.path.join(
                    template_path,
                    'footer')),
            members_count=len(members),
            shares_count=shares_count,
            shares_value=shares_count * 50,
            effective_date=effective_date.strftime('%d.%m.%Y'),
        ).encode('utf-8'))

    # make table rows per member
    for member in members:
        latex_file.write(
            LATEX_MEMBER_ROW.format(
                lastname=TexTools.escape(member['lastname']).encode('utf-8'),
                firstname=TexTools.escape(member['firstname']).encode('utf-8'),
                membership_number=TexTools.escape(
                    str(member['membership_number'])),
                address=latex_address(
                    member['address1'],
                    member['address2'],
                    member['postcode'],
                    member['city'],
                    member['country']),
                membership_approval=member['membership_date'].strftime(
                    '%d.%m.%Y'),
                membership_loss=latex_membership_loss(
                    member['membership_loss_date'],
                    member['membership_loss_type']),
                shares=str(member['shares_count'])))

    latex_file.write(LATEX_FOOTER)
    latex_file.close()

    # generate file three times in order to make sure all back references like
    # the number of total pages are properly calculated
    for i in range(3):
        subprocess.call(
            [
                'pdflatex',
                '-output-directory={0}'.format(latex_dir),
                latex_file.name
            ],
            stdout=open(os.devnull, 'w'),
            stderr=subprocess.STDOUT,
        )

    pdf_file = open(latex_file.name.replace('.tex', '.pdf'), "r")
    shutil.rmtree(latex_dir, ignore_errors=True)
    return pdf_file
예제 #8
0
def member_list_date_pdf_view(request):
    """
    The membership list *for a given date* for printout as PDF.
    The date is supplied in and parsed from the URL, e.g.
    http://0.0.0.0:6543/aml-2014-12-31.pdf

    The PDF is generated using pdflatex.

    If the date is not parseable, an error message is shown.
    """
    effective_date_string = ''
    try:
        effective_date_string = request.matchdict['date']
        effective_date = datetime.strptime(effective_date_string, '%Y-%m-%d') \
            .date()
    except (KeyError, ValueError):
        request.session.flash(
            "Invalid date! '{}' does not compute! "
            "try again, please! (YYYY-MM-DD)".format(
                effective_date_string),
            'message_to_user'
        )
        return HTTPFound(request.route_url('error_page'))

    shares_count_printed = 0

    # TODO: repositories are data layer and must only be used by the business
    # layer. Introduce business layer logic which uses the repositories and can
    # be accessed by this view via the request.
    shares_count = request.registry.share_information.get_share_count(
        effective_date)

    member_information = request.registry.member_information
    members_count = member_information.get_accepted_members_count(
        effective_date)
    members = member_information.get_accepted_members_sorted(
        effective_date)

    """
    Then a LaTeX file is constructed...
    """
    here = os.path.dirname(__file__)
    latex_header_tex = os.path.abspath(
        os.path.join(here, '../membership_list_pdflatex/header'))
    latex_footer_tex = os.path.abspath(
        os.path.join(here, '../membership_list_pdflatex/footer'))

    # a temporary directory for the latex run
    tempdir = tempfile.mkdtemp()
    # now we prepare a .tex file to be pdflatex'ed
    latex_file = tempfile.NamedTemporaryFile(
        suffix='.tex',
        dir=tempdir,
        delete=False,  # directory will be deleted anyways
    )
    # and where to store the output
    pdf_file = tempfile.NamedTemporaryFile(
        dir=tempdir,
        delete=False,  # directory will be deleted anyways
    )
    pdf_file.name = latex_file.name.replace('.tex', '.pdf')

    # construct latex data: header + variables
    latex_data = '''
\\input{%s}
\\def\\numMembers{%s}
\\def\\numShares{%s}
\\def\\sumShares{%s}
\\def\\today{%s}
    ''' % (
        latex_header_tex,
        members_count,
        shares_count,
        shares_count * 50,
        effective_date.strftime('%d.%m.%Y'),
    )

    # add to the latex document
    latex_data += '''
\\input{%s}''' % latex_footer_tex

    # print '*' * 70
    # print latex_data
    # print '*' * 70
    latex_file.write(latex_data.encode('utf-8'))

    # make table rows per member
    for member in members:
        address = '''\\scriptsize{}'''
        address += '''{}'''.format(
            unicode(TexTools.escape(member.address1)).encode('utf-8'))

        # check for contents of address2:
        if len(member.address2) > 0:
            address += '''\\linebreak {}'''.format(
                unicode(TexTools.escape(member.address2)).encode('utf-8'))
        # add more...
        address += ''' \\linebreak {} '''.format(
            unicode(TexTools.escape(member.postcode)).encode('utf-8'))
        address += '''{}'''.format(
            unicode(TexTools.escape(member.city)).encode('utf-8'))
        address += ''' ({})'''.format(
            unicode(TexTools.escape(member.country)).encode('utf-8'))

        member_share_count = \
            request.registry.share_information.get_member_share_count(
                member.membership_number,
                effective_date)
        shares_count_printed += member_share_count

        membership_loss = u''
        if member.membership_loss_date is not None:
            membership_loss += \
                member.membership_loss_date.strftime('%d.%m.%Y') + \
                '\\linebreak '
        if member.membership_loss_type is not None:
            membership_loss += unicode(TexTools.escape(
                member.membership_loss_type)).encode('utf-8')
        latex_file.write(
            ''' {0} & {1} & {2} & {3} & {4} & {5} & {6}  \\\\\\hline %
            '''.format(
                TexTools.escape(member.lastname).encode('utf-8'),  # 0
                ' \\footnotesize ' + TexTools.escape(
                    member.firstname).encode('utf-8'),  # 1
                ' \\footnotesize ' + TexTools.escape(
                    str(member.membership_number)),  # 2
                address,  # 3
                ' \\footnotesize ' + member.membership_date.strftime(
                    '%d.%m.%Y'),  # 4
                ' \\footnotesize ' + membership_loss + ' ',  # 5
                ' \\footnotesize ' + str(member_share_count)  # 6
            ))

    latex_file.write('''
%\\end{tabular}%
\\end{longtable}%
\\label{LastPage}
\\end{document}
''')
    latex_file.seek(0)  # rewind

    # pdflatex latex_file to pdf_file
    fnull = open(os.devnull, 'w')  # hide output
    pdflatex_output = subprocess.call(
        [
            'pdflatex',
            '-output-directory=%s' % tempdir,
            latex_file.name
        ],
        stdout=fnull, stderr=subprocess.STDOUT  # hide output
    )
    if DEBUG:  # pragma: no cover
        print("the output of pdflatex run: %s" % pdflatex_output)

    # if run was a success, run X times more...
    if pdflatex_output == 0:
        for i in range(2):
            pdflatex_output = subprocess.call(
                [
                    'pdflatex',
                    '-output-directory=%s' % tempdir,
                    latex_file.name
                ],
                stdout=fnull, stderr=subprocess.STDOUT  # hide output
            )
            if DEBUG:  # pragma: no cover
                print("run #{} finished.".format(i+1))

    # sanity check: did we print exactly as many shares as calculated?
    assert(shares_count == shares_count_printed)

    # return a pdf file
    response = Response(content_type='application/pdf')
    response.app_iter = open(pdf_file.name, "r")
    shutil.rmtree(tempdir, ignore_errors=True)  # delete temporary directory
    return response
예제 #9
0
def gen_cert(member):
    '''
    Utility function: create a membership certificate PDF file using pdflatex
    '''
    certificate_path = os.path.join(
        os.path.dirname(__file__),
        '../../../certificate')

    if 'de' in member.locale:
        latex_background_image = os.path.abspath(
            os.path.join(certificate_path, 'Urkunde_Hintergrund_blank.pdf'))
        # latex header and footer
        latex_header_tex = os.path.abspath(
            os.path.join(certificate_path, 'urkunde_header_de.tex'))
        latex_footer_tex = os.path.abspath(
            os.path.join(certificate_path, 'urkunde_footer_de.tex'))
    else:
        latex_background_image = os.path.abspath(
            os.path.join(certificate_path, 'Urkunde_Hintergrund_blank.pdf'))
        # latex header and footer
        latex_header_tex = os.path.abspath(
            os.path.join(certificate_path, 'urkunde_header_en.tex'))
        latex_footer_tex = os.path.abspath(
            os.path.join(certificate_path, 'urkunde_footer_en.tex'))

    sign_meik = os.path.abspath(
        os.path.join(certificate_path, 'sign_meik.png'))
    sign_julian = os.path.abspath(
        os.path.join(certificate_path, 'sign_julian.png'))

    # a temporary directory for the latex run
    tempdir = tempfile.mkdtemp()

    latex_file = tempfile.NamedTemporaryFile(
        suffix='.tex',
        dir=tempdir,
        delete=False,  # directory will be deleted anyways
    )

    # using tempfile
    pdf_file = tempfile.NamedTemporaryFile(
        dir=tempdir,
        delete=False,  # directory will be deleted anyways
    )
    pdf_file.name = latex_file.name.replace('.tex', '.pdf')

    is_founder = True if 'dungHH_' in member.email_confirm_code else False
    # prepare the certificate text
    if member.locale == 'de':  # german
        hereby_confirmed = u'Hiermit wird bestätigt, dass'
        is_member = u'Mitglied der Cultural Commons Collecting Society SCE ' \
                    u'mit beschränkter Haftung (C3S SCE) ist'
        one_more_share = u' und einen weiteren Geschäftsanteil übernommen hat'
        several_shares = u' weitere Geschäftsanteile übernommen hat'
        and_block = u' und '
        if is_founder:
            confirm_date = (
                u'Der Beitritt erfolgte im Rahmen der Gründung am 25.09.2013')
        else:
            confirm_date = u'Der Beitritt wurde am {} zugelassen'.format(
                datetime.strftime(member.membership_date, '%d.%m.%Y'))
        mship_num = u'Die Mitgliedsnummer lautet {}.'.format(
            member.membership_number
        )
        mship_num_text = u'Mitgliedsnummer {}'.format(
            member.membership_number
        )
        exec_dir = u'Geschäftsführender Direktor'

    else:  # default fallback is english
        hereby_confirmed = u'This is to certify that'
        is_member = u'is a member of the >>Cultural Commons Collecting ' \
                    u'Society SCE mit beschränkter Haftung (C3S SCE)<<'
        one_more_share = u' and has subscribed to one additional share'
        several_shares = u'additional shares'
        and_block = u' and has subscribed to'
        if is_founder:
            confirm_date = (
                u'Membership was acquired as a founding member '
                'on the 25th of September 2013')
        else:
            confirm_date = u'Registered on the {}'.format(
                datetime.strftime(member.membership_date, '%Y-%m-%d'))
        mship_num = u'The membership number is {}.'.format(
            member.membership_number
        )
        mship_num_text = u'membership number {}'.format(
            member.membership_number
        )
        exec_dir = u'Executive Director'

    # construct latex_file
    latex_data = '''
\\input{%s}
\\def\\backgroundImage{%s}
\\def\\txtBlkHerebyConfirmed{%s}
\\def\\firstName{%s}
\\def\\lastName{%s}
\\def\\addressOne{%s}
\\def\\postCode{%s}
\\def\\city{%s}
\\def\\numShares{%s}
\\def\\numAddShares{%s}
\\def\\txtBlkIsMember{%s}
\\def\\txtBlkMembershipNumber{%s}
\\def\\txtBlkConfirmDate{%s}
\\def\\signDate{%s}
\\def\\signMeik{%s}
\\def\\signJulian{%s}
\\def\\txtBlkCEO{%s}
\\def\\txtBlkMembershipNum{%s}
    ''' % (
        latex_header_tex,
        latex_background_image,
        hereby_confirmed,
        TexTools.escape(member.firstname),
        TexTools.escape(member.lastname),
        TexTools.escape(member.address1),
        TexTools.escape(member.postcode),
        TexTools.escape(member.city),
        member.num_shares,
        member.num_shares-1,
        is_member,
        TexTools.escape(mship_num),
        confirm_date,
        (
            datetime.strftime(date.today(), "%d.%m.%Y")
            if member.locale == 'de'
            else date.today()),
        sign_meik,
        sign_julian,
        exec_dir,
        mship_num_text
    )
    if member.is_legalentity:
        latex_data += '\n\\def\\company{%s}' % TexTools.escape(member.lastname)
    if member.address2 is not u'':  # add address part 2 iff exists
        latex_data += '\n\\def\\addressTwo{%s}' % TexTools.escape(
            member.address2)
    if member.num_shares > 1:  # how many shares?
        if member.num_shares == 2:  # iff member has exactely two shares...
            latex_data += '\n\\def\\txtBlkAddShares{%s.}' % one_more_share
        if member.num_shares > 2:  # iff more than two
            latex_data += '\n\\def\\txtBlkAddShares{%s %s %s.}' % (
                and_block,
                member.num_shares-1,
                several_shares
            )
    else:  # iff member has exactely one share..
        latex_data += '\n\\def\\txtBlkAddShares{.}'

    # finish the latex document
    latex_data += '\n\\input{%s}' % latex_footer_tex

    latex_file.write(latex_data.encode('utf-8'))
    latex_file.seek(0)  # rewind

    # pdflatex latex_file to pdf_file
    # pdflatex_output =
    subprocess.call(
        [
            'pdflatex',
            '-output-directory=%s' % tempdir,
            latex_file.name
        ],
        stdout=open(os.devnull, 'w'),
        stderr=subprocess.STDOUT  # hide output
    )

    # return a pdf file
    response = Response(content_type='application/pdf')
    response.app_iter = open(pdf_file.name, "r")
    shutil.rmtree(tempdir, ignore_errors=True)  # delete temporary directory
    return response
def gen_cert(member):
    '''
    Utility function: create a membership certificate PDF file using pdflatex
    '''
    here = os.path.dirname(__file__)

    if 'de' in member.locale:
        latex_background_image = os.path.abspath(
            os.path.join(here, '../certificate/Urkunde_Hintergrund_blank.pdf'))
        # latex header and footer
        latex_header_tex = os.path.abspath(
            os.path.join(here, '../certificate/urkunde_header_de.tex'))
        latex_footer_tex = os.path.abspath(
            os.path.join(here, '../certificate/urkunde_footer_de.tex'))
    else:
        latex_background_image = os.path.abspath(
            os.path.join(here, '../certificate/Urkunde_Hintergrund_blank.pdf'))
        # latex header and footer
        latex_header_tex = os.path.abspath(
            os.path.join(here, '../certificate/urkunde_header_en.tex'))
        latex_footer_tex = os.path.abspath(
            os.path.join(here, '../certificate/urkunde_footer_en.tex'))

    sign_meik = os.path.abspath(
        os.path.join(here, '../certificate/sign_meik.png'))
    sign_julian = os.path.abspath(
        os.path.join(here, '../certificate/sign_julian.png'))

    # a temporary directory for the latex run
    tempdir = tempfile.mkdtemp()

    latex_file = tempfile.NamedTemporaryFile(
        suffix='.tex',
        dir=tempdir,
        delete=False,  # directory will be deleted anyways
    )

    # using tempfile
    pdf_file = tempfile.NamedTemporaryFile(
        dir=tempdir,
        delete=False,  # directory will be deleted anyways
    )
    pdf_file.name = latex_file.name.replace('.tex', '.pdf')

    is_founder = True if 'dungHH_' in member.email_confirm_code else False
    # prepare the certificate text
    if member.locale == 'de':  # german
        hereby_confirmed = u'Hiermit wird bestätigt, dass'
        is_member = u'Mitglied der Cultural Commons Collecting Society SCE ' \
                    u'mit beschränkter Haftung (C3S SCE) ist'
        one_more_share = u' und einen weiteren Geschäftsanteil übernommen hat'
        several_shares = u' weitere Geschäftsanteile übernommen hat'
        and_block = u' und '
        if is_founder:
            confirm_date = (
                u'Der Beitritt erfolgte im Rahmen der Gründung am 25.09.2013')
        else:
            confirm_date = u'Der Beitritt wurde am {} zugelassen'.format(
                datetime.strftime(member.membership_date, '%d.%m.%Y'))
        mship_num = u'Die Mitgliedsnummer lautet {}.'.format(
            member.membership_number)
        mship_num_text = u'Mitgliedsnummer {}'.format(member.membership_number)
        exec_dir = u'Geschäftsführender Direktor'

    else:  # default fallback is english
        hereby_confirmed = u'This is to certify that'
        is_member = u'is a member of the >>Cultural Commons Collecting ' \
                    u'Society SCE mit beschränkter Haftung (C3S SCE)<<'
        one_more_share = u' and has subscribed to one additional share'
        several_shares = u'additional shares'
        and_block = u' and has subscribed to'
        if is_founder:
            confirm_date = (u'Membership was acquired as a founding member '
                            'on the 25th of September 2013')
        else:
            confirm_date = u'Registered on the {}'.format(
                datetime.strftime(member.membership_date, '%Y-%m-%d'))
        mship_num = u'The membership number is {}.'.format(
            member.membership_number)
        mship_num_text = u'membership number {}'.format(
            member.membership_number)
        exec_dir = 'Executive Director'

    # construct latex_file
    latex_data = '''
\\input{%s}
\\def\\backgroundImage{%s}
\\def\\txtBlkHerebyConfirmed{%s}
\\def\\firstName{%s}
\\def\\lastName{%s}
\\def\\addressOne{%s}
\\def\\postCode{%s}
\\def\\city{%s}
\\def\\numShares{%s}
\\def\\numAddShares{%s}
\\def\\txtBlkIsMember{%s}
\\def\\txtBlkMembershipNumber{%s}
\\def\\txtBlkConfirmDate{%s}
\\def\\signDate{%s}
\\def\\signMeik{%s}
\\def\\signJulian{%s}
\\def\\txtBlkCEO{%s}
\\def\\txtBlkMembershipNum{%s}
    ''' % (latex_header_tex, latex_background_image, hereby_confirmed,
           TexTools.escape(member.firstname), TexTools.escape(member.lastname),
           TexTools.escape(member.address1), TexTools.escape(member.postcode),
           TexTools.escape(member.city), member.num_shares, member.num_shares -
           1, is_member, TexTools.escape(mship_num), confirm_date,
           (datetime.strftime(date.today(), "%d.%m.%Y")
            if member.locale == 'de' else date.today()), sign_meik,
           sign_julian, exec_dir, mship_num_text)
    if DEBUG:  # pragma: no cover
        print('#' * 60)
        print(member.is_legalentity)
        print(member.lastname)
        print('#' * 60)
    if member.is_legalentity:
        latex_data += '\n\\def\\company{%s}' % TexTools.escape(member.lastname)
    if member.address2 is not u'':  # add address part 2 iff exists
        latex_data += '\n\\def\\addressTwo{%s}' % TexTools.escape(
            member.address2)
    if member.num_shares > 1:  # how many shares?
        if member.num_shares == 2:  # iff member has exactely two shares...
            latex_data += '\n\\def\\txtBlkAddShares{%s.}' % one_more_share
        if member.num_shares > 2:  # iff more than two
            latex_data += '\n\\def\\txtBlkAddShares{%s %s %s.}' % (
                and_block, member.num_shares - 1, several_shares)
    else:  # iff member has exactely one share..
        latex_data += '\n\\def\\txtBlkAddShares{.}'

    # finish the latex document
    latex_data += '\n\\input{%s}' % latex_footer_tex

    if DEBUG:  # pragma: no cover
        print '*' * 70
        print('*' * 30, 'latex data: ', '*' * 30)
        print '*' * 70
        print latex_data
        print '*' * 70
    latex_file.write(latex_data.encode('utf-8'))
    latex_file.seek(0)  # rewind

    # pdflatex latex_file to pdf_file
    # pdflatex_output =
    subprocess.call(
        ['pdflatex',
         '-output-directory=%s' % tempdir, latex_file.name],
        stdout=open(os.devnull, 'w'),
        stderr=subprocess.STDOUT  # hide output
    )

    # return a pdf file
    response = Response(content_type='application/pdf')
    response.app_iter = open(pdf_file.name, "r")
    shutil.rmtree(tempdir, ignore_errors=True)  # delete temporary directory
    return response
예제 #11
0
def gen_cert(member):
    """
    Utility function: create a membership certificate PDF file using pdflatex
    """
    here = os.path.dirname(__file__)

    if "de" in member.locale:
        latex_background_image = os.path.abspath(os.path.join(here, "../certificate/Urkunde_Hintergrund_blank.pdf"))
        # latex header and footer
        latex_header_tex = os.path.abspath(os.path.join(here, "../certificate/urkunde_header_de.tex"))
        latex_footer_tex = os.path.abspath(os.path.join(here, "../certificate/urkunde_footer_de.tex"))
    else:
        latex_background_image = os.path.abspath(os.path.join(here, "../certificate/Urkunde_Hintergrund_blank.pdf"))
        # latex header and footer
        latex_header_tex = os.path.abspath(os.path.join(here, "../certificate/urkunde_header_en.tex"))
        latex_footer_tex = os.path.abspath(os.path.join(here, "../certificate/urkunde_footer_en.tex"))

    sign_meik = os.path.abspath(os.path.join(here, "../certificate/sign_meik.png"))
    sign_max = os.path.abspath(os.path.join(here, "../certificate/sign_max.png"))

    # a temporary directory for the latex run
    tempdir = tempfile.mkdtemp()

    latex_file = tempfile.NamedTemporaryFile(
        suffix=".tex", dir=tempdir, delete=False  # directory will be deleted anyways
    )

    # using tempfile
    pdf_file = tempfile.NamedTemporaryFile(dir=tempdir, delete=False)  # directory will be deleted anyways
    pdf_file.name = latex_file.name.replace(".tex", ".pdf")

    is_founder = True if "dungHH_" in member.email_confirm_code else False
    # prepare the certificate text
    if member.locale == "de":  # german
        hereby_confirmed = u"Hiermit wird bestätigt, dass"
        is_member = u"Mitglied der Cultural Commons Collecting Society SCE " u"mit beschränkter Haftung (C3S SCE) ist"
        one_more_share = u" und einen weiteren Geschäftsanteil übernommen hat"
        several_shares = u" weitere Geschäftsanteile übernommen hat"
        and_block = u" und "
        if is_founder:
            confirm_date = u"Der Beitritt erfolgte im Rahmen der Gründung am 25.09.2013"
        else:
            confirm_date = u"Der Beitritt wurde am {} zugelassen".format(
                datetime.strftime(member.membership_date, "%d.%m.%Y")
            )
        mship_num = u"Die Mitgliedsnummer lautet {}.".format(member.membership_number)
        mship_num_text = u"Mitgliedsnummer {}".format(member.membership_number)
        exec_dir = u"Geschäftsführender Direktor"

    else:  # default fallback is english
        hereby_confirmed = u"This is to certify that"
        is_member = (
            u"is a member of the >>Cultural Commons Collecting " u"Society SCE mit beschränkter Haftung (C3S SCE)<<"
        )
        one_more_share = u" and has subscribed to one additional share"
        several_shares = u"additional shares"
        and_block = u" and has subscribed to"
        if is_founder:
            confirm_date = u"Membership was aquired as a founding member " "on the 25th of September 2013"
        else:
            confirm_date = u"Registered on the {}".format(datetime.strftime(member.membership_date, "%Y-%m-%d"))
        mship_num = u"The membership number is {}.".format(member.membership_number)
        mship_num_text = u"membership number {}".format(member.membership_number)
        exec_dir = "Executive Director"

    # construct latex_file
    latex_data = """
\\input{%s}
\\def\\backgroundImage{%s}
\\def\\txtBlkHerebyConfirmed{%s}
\\def\\firstName{%s}
\\def\\lastName{%s}
\\def\\addressOne{%s}
\\def\\postCode{%s}
\\def\\city{%s}
\\def\\numShares{%s}
\\def\\numAddShares{%s}
\\def\\txtBlkIsMember{%s}
\\def\\txtBlkMembershipNumber{%s}
\\def\\txtBlkConfirmDate{%s}
\\def\\signDate{%s}
\\def\\signMeik{%s}
\\def\\signMax{%s}
\\def\\txtBlkCEO{%s}
\\def\\txtBlkMembershipNum{%s}
    """ % (
        latex_header_tex,
        latex_background_image,
        hereby_confirmed,
        TexTools.escape(member.firstname),
        TexTools.escape(member.lastname),
        TexTools.escape(member.address1),
        TexTools.escape(member.postcode),
        TexTools.escape(member.city),
        member.num_shares,
        member.num_shares - 1,
        is_member,
        TexTools.escape(mship_num),
        confirm_date,
        (datetime.strftime(date.today(), "%d.%m.%Y") if member.locale == "de" else date.today()),
        sign_meik,
        sign_max,
        exec_dir,
        mship_num_text,
    )
    if DEBUG:  # pragma: no cover
        print ("#" * 60)
        print (member.is_legalentity)
        print (member.lastname)
        print ("#" * 60)
    if member.is_legalentity:
        latex_data += "\n\\def\\company{%s}" % TexTools.escape(member.lastname)
    if member.address2 is not u"":  # add address part 2 iff exists
        latex_data += "\n\\def\\addressTwo{%s}" % TexTools.escape(member.address2)
    if member.num_shares > 1:  # how many shares?
        if member.num_shares == 2:  # iff member has exactely two shares...
            latex_data += "\n\\def\\txtBlkAddShares{%s.}" % one_more_share
        if member.num_shares > 2:  # iff more than two
            latex_data += "\n\\def\\txtBlkAddShares{%s %s %s.}" % (and_block, member.num_shares - 1, several_shares)
    else:  # iff member has exactely one share..
        latex_data += "\n\\def\\txtBlkAddShares{.}"

    # finish the latex document
    latex_data += "\n\\input{%s}" % latex_footer_tex

    if DEBUG:  # pragma: no cover
        print "*" * 70
        print ("*" * 30, "latex data: ", "*" * 30)
        print "*" * 70
        print latex_data
        print "*" * 70
    latex_file.write(latex_data.encode("utf-8"))
    latex_file.seek(0)  # rewind

    # pdflatex latex_file to pdf_file
    # pdflatex_output =
    subprocess.call(
        ["pdflatex", "-output-directory=%s" % tempdir, latex_file.name],
        stdout=open(os.devnull, "w"),
        stderr=subprocess.STDOUT,  # hide output
    )

    # return a pdf file
    response = Response(content_type="application/pdf")
    response.app_iter = open(pdf_file.name, "r")
    shutil.rmtree(tempdir, ignore_errors=True)  # delete temporary directory
    return response
def make_reversal_pdf_pdflatex(member, invoice=None):
    """
    This function uses pdflatex to create a PDF
    as reversal invoice: cancel and balance out a former invoice.
    """

    dues17_archive_invoice = get_dues17_archive_invoice(invoice)
    if dues17_archive_invoice is not None:
        return dues17_archive_invoice

    pdflatex_dir = os.path.abspath(
        os.path.join(os.path.dirname(os.path.abspath(__file__)),
                     '../../certificate/'))
    # pdf backgrounds
    pdf_backgrounds = {
        'blank': pdflatex_dir + '/' + 'Urkunde_Hintergrund_blank.pdf',
    }

    # latex templates
    latex_templates = {
        'generic': pdflatex_dir + '/' + 'dues17_storno_de.tex',
        'generic_en': pdflatex_dir + '/' + 'dues17_storno_en.tex',
    }

    # choose background and template
    background = 'blank'
    template_name = 'generic' if 'de' in member.locale else 'generic_en'

    # pick background and template
    bg_pdf = pdf_backgrounds[background]
    tpl_tex = latex_templates[template_name]

    # pick temporary file for pdf
    receipt_pdf = tempfile.NamedTemporaryFile(prefix='storno_', suffix='.pdf')

    (path, filename) = os.path.split(receipt_pdf.name)
    filename = os.path.splitext(filename)[0]

    invoice_no = str(invoice.invoice_no).zfill(4) + '-S'
    invoice_date = invoice.invoice_date.strftime('%d. %m. %Y')
    # set variables for tex command
    tex_vars = {
        'personalFirstname':
        member.firstname,
        'personalLastname':
        member.lastname,
        'personalAddressOne':
        member.address1,
        'personalAddressTwo':
        member.address2,
        'personalPostCode':
        member.postcode,
        'personalCity':
        member.city,
        'personalMShipNo':
        unicode(member.membership_number),
        'invoiceNo':
        invoice_no,
        'invoiceDate':
        invoice_date,
        'duesAmount':
        unicode(invoice.invoice_amount),
        'origInvoiceRef':
        ('C3S-dues2017-' + str(invoice.preceding_invoice_no).zfill(4)),
        'lang':
        'de',
        'pdfBackground':
        bg_pdf,
    }

    # generate tex command for pdflatex
    tex_cmd = u''
    for key, val in tex_vars.iteritems():
        tex_cmd += '\\newcommand{\\%s}{%s}' % (key, TexTools.escape(val))
    tex_cmd += '\\input{%s}' % tpl_tex
    tex_cmd = u'"' + tex_cmd + '"'

    # XXX: try to find out, why utf-8 doesn't work on debian
    subprocess.call(
        [
            'pdflatex', '-jobname', filename, '-output-directory', path,
            '-interaction', 'nonstopmode', '-halt-on-error',
            tex_cmd.encode('latin_1')
        ],
        stdout=open(os.devnull, 'w'),  # hide output
        stderr=subprocess.STDOUT,
        cwd=pdflatex_dir)

    # cleanup
    aux = os.path.join(path, filename + '.aux')
    if os.path.isfile(aux):
        os.unlink(aux)

    archive_dues17_invoice(receipt_pdf, invoice)

    return receipt_pdf
def make_invoice_pdf_pdflatex(member, invoice=None):
    """
    This function uses pdflatex to create a PDF
    as receipt for the members membership dues.

    default output is the current invoice.
    if i_no is suplied, the relevant invoice number is produced
    """

    dues17_archive_invoice = get_dues17_archive_invoice(invoice)
    if dues17_archive_invoice is not None:
        return dues17_archive_invoice

    # directory of pdf and tex files
    pdflatex_dir = os.path.abspath(
        os.path.join(os.path.dirname(os.path.abspath(__file__)),
                     '../../certificate/'))

    # pdf backgrounds
    pdf_backgrounds = {
        'blank': pdflatex_dir + '/' + 'Urkunde_Hintergrund_blank.pdf',
    }

    # latex templates
    latex_templates = {
        # 'generic': pdflatex_dir + '/' + 'membership_dues_receipt.tex',
        'generic': pdflatex_dir + '/' + 'dues17_invoice_de.tex',
        'generic_en': pdflatex_dir + '/' + 'dues17_invoice_en.tex',
    }

    # choose background and template
    background = 'blank'
    template_name = 'generic' if 'de' in member.locale else 'generic_en'

    # pick background and template
    bg_pdf = pdf_backgrounds[background]
    tpl_tex = latex_templates[template_name]

    # pick temporary file for pdf
    receipt_pdf = tempfile.NamedTemporaryFile(prefix='invoice_', suffix='.pdf')

    (path, filename) = os.path.split(receipt_pdf.name)
    filename = os.path.splitext(filename)[0]

    # on invoice, print start quarter or "reduced". prepare string:
    if (not invoice.is_reversal and invoice.is_altered
            and invoice.preceding_invoice_no is not None):
        is_altered_str = u'angepasst' if ('de'
                                          in member.locale) else u'altered'

    if invoice is not None:
        # use invoice no from URL
        invoice_no = str(invoice.invoice_no).zfill(4)
        invoice_date = invoice.invoice_date.strftime('%d. %m. %Y')
    else:  # pragma: no cover
        # this branch is deprecated, because we always supply an invoice number
        # use invoice no from member record
        invoice_no = str(member.dues17_invoice_no).zfill(4)
        invoice_date = member.dues17_invoice_date

    # set variables for tex command
    tex_vars = {
        'personalFirstname': member.firstname,
        'personalLastname': member.lastname,
        'personalAddressOne': member.address1,
        'personalAddressTwo': member.address2,
        'personalPostCode': member.postcode,
        'personalCity': member.city,
        'personalMShipNo': unicode(member.membership_number),
        'invoiceNo': str(invoice_no).zfill(4),  # leading zeroes!
        'invoiceDate': invoice_date,
        'account': unicode(-member.dues15_balance - member.dues16_balance \
            - member.dues17_balance),
        'duesStart':  is_altered_str if (
            invoice.is_altered) else string_start_quarter_dues17(member),
        'duesAmount': unicode(invoice.invoice_amount),
        'lang': 'de',
        'pdfBackground': bg_pdf,
    }

    # generate tex command for pdflatex
    tex_cmd = u''
    for key, val in tex_vars.iteritems():
        tex_cmd += '\\newcommand{\\%s}{%s}' % (key, TexTools.escape(val))
    tex_cmd += '\\input{%s}' % tpl_tex
    tex_cmd = u'"' + tex_cmd + '"'

    # make latex show ß correctly in pdf:
    tex_cmd = tex_cmd.replace(u'ß', u'\\ss{}')

    # XXX: try to find out, why utf-8 doesn't work on debian
    subprocess.call(
        [
            'pdflatex', '-jobname', filename, '-output-directory', path,
            '-interaction', 'nonstopmode', '-halt-on-error',
            tex_cmd.encode('latin_1')
        ],
        stdout=open(os.devnull, 'w'),  # hide output
        stderr=subprocess.STDOUT,
        cwd=pdflatex_dir)

    # cleanup
    aux = os.path.join(path, filename + '.aux')
    if os.path.isfile(aux):
        os.unlink(aux)

    archive_dues17_invoice(receipt_pdf, invoice)

    return receipt_pdf
예제 #14
0
def make_reversal_pdf_pdflatex(member, invoice=None):
    """
    This function uses pdflatex to create a PDF
    as reversal invoice: cancel and balance out a former invoice.
    """

    dues16_archive_invoice = get_dues16_archive_invoice(invoice)
    if dues16_archive_invoice is not None:
        return dues16_archive_invoice

    pdflatex_dir = os.path.abspath(
        os.path.join(
            os.path.dirname(os.path.abspath(__file__)),
            '../../../certificate/'
        ))
    # pdf backgrounds
    pdf_backgrounds = {
        'blank': pdflatex_dir + '/' + 'Urkunde_Hintergrund_blank.pdf',
    }

    # latex templates
    latex_templates = {
        'generic': pdflatex_dir + '/' + 'dues16_storno_de.tex',
        'generic_en': pdflatex_dir + '/' + 'dues16_storno_en.tex',
    }

    # choose background and template
    background = 'blank'
    template_name = 'generic' if 'de' in member.locale else 'generic_en'

    # pick background and template
    bg_pdf = pdf_backgrounds[background]
    tpl_tex = latex_templates[template_name]

    # pick temporary file for pdf
    receipt_pdf = tempfile.NamedTemporaryFile(prefix='storno_', suffix='.pdf')

    (path, filename) = os.path.split(receipt_pdf.name)
    filename = os.path.splitext(filename)[0]

    invoice_no = str(invoice.invoice_no).zfill(4) + '-S'
    invoice_date = invoice.invoice_date.strftime('%d. %m. %Y')
    # set variables for tex command
    tex_vars = {
        'personalFirstname': member.firstname,
        'personalLastname': member.lastname,
        'personalAddressOne': member.address1,
        'personalAddressTwo': member.address2,
        'personalPostCode': member.postcode,
        'personalCity': member.city,
        'personalMShipNo': unicode(member.membership_number),
        'invoiceNo': invoice_no,
        'invoiceDate': invoice_date,
        'duesAmount': unicode(invoice.invoice_amount),
        'origInvoiceRef': ('C3S-dues2016-' +
                           str(invoice.preceding_invoice_no).zfill(4)),
        'lang': 'de',
        'pdfBackground': bg_pdf,
    }

    # generate tex command for pdflatex
    tex_cmd = u''
    for key, val in tex_vars.iteritems():
        tex_cmd += '\\newcommand{\\%s}{%s}' % (key, TexTools.escape(val))
    tex_cmd += '\\input{%s}' % tpl_tex
    tex_cmd = u'"'+tex_cmd+'"'

    # XXX: try to find out, why utf-8 doesn't work on debian
    subprocess.call(
        [
            'pdflatex',
            '-jobname', filename,
            '-output-directory', path,
            '-interaction', 'nonstopmode',
            '-halt-on-error',
            tex_cmd.encode('latin_1')
        ],
        stdout=open(os.devnull, 'w'),  # hide output
        stderr=subprocess.STDOUT,
        cwd=pdflatex_dir
    )

    # cleanup
    aux = os.path.join(path, filename + '.aux')
    if os.path.isfile(aux):
        os.unlink(aux)

    archive_dues16_invoice(receipt_pdf, invoice)

    return receipt_pdf
예제 #15
0
def make_invoice_pdf_pdflatex(member, invoice=None):
    """
    This function uses pdflatex to create a PDF
    as receipt for the members membership dues.

    default output is the current invoice.
    if i_no is suplied, the relevant invoice number is produced
    """

    dues16_archive_invoice = get_dues16_archive_invoice(invoice)
    if dues16_archive_invoice is not None:
        return dues16_archive_invoice

    # directory of pdf and tex files
    pdflatex_dir = os.path.abspath(
        os.path.join(
            os.path.dirname(os.path.abspath(__file__)),
            '../../../certificate/'
        ))

    # pdf backgrounds
    pdf_backgrounds = {
        'blank': pdflatex_dir + '/' + 'Urkunde_Hintergrund_blank.pdf',
    }

    # latex templates
    latex_templates = {
        # 'generic': pdflatex_dir + '/' + 'membership_dues_receipt.tex',
        'generic': pdflatex_dir + '/' + 'dues16_invoice_de.tex',
        'generic_en': pdflatex_dir + '/' + 'dues16_invoice_en.tex',
    }

    # choose background and template
    background = 'blank'
    template_name = 'generic' if 'de' in member.locale else 'generic_en'

    # pick background and template
    bg_pdf = pdf_backgrounds[background]
    tpl_tex = latex_templates[template_name]

    # pick temporary file for pdf
    receipt_pdf = tempfile.NamedTemporaryFile(prefix='invoice_', suffix='.pdf')

    (path, filename) = os.path.split(receipt_pdf.name)
    filename = os.path.splitext(filename)[0]

    # on invoice, print start quarter or "reduced". prepare string:
    if (
            not invoice.is_reversal and
            invoice.is_altered and
            invoice.preceding_invoice_no is not None):
        is_altered_str = u'angepasst' if (
            'de' in member.locale) else u'altered'

    if invoice is not None:
        # use invoice no from URL
        invoice_no = str(invoice.invoice_no).zfill(4)
        invoice_date = invoice.invoice_date.strftime('%d. %m. %Y')
    else:  # pragma: no cover
        # this branch is deprecated, because we always supply an invoice number
        # use invoice no from member record
        invoice_no = str(invoice.invoice_no).zfill(4)
        invoice_date = invoice.invoice_date

    dues15_balance = D('0.0')
    dues16_balance = D('0.0')

    if not math.isnan(member.dues15_balance):
        dues15_balance = member.dues15_balance
    if not math.isnan(member.dues16_balance):
        dues16_balance = member.dues16_balance

    # set variables for tex command
    tex_vars = {
        'personalFirstname': member.firstname,
        'personalLastname': member.lastname,
        'personalAddressOne': member.address1,
        'personalAddressTwo': member.address2,
        'personalPostCode': member.postcode,
        'personalCity': member.city,
        'personalMShipNo': unicode(member.membership_number),
        'invoiceNo': str(invoice_no).zfill(4),  # leading zeroes!
        'invoiceDate': invoice_date,
        'account': unicode(-dues15_balance - dues16_balance),
        'duesStart':  is_altered_str if (
            invoice.is_altered) else string_start_quarter_dues16(member),
        'duesAmount': unicode(invoice.invoice_amount),
        'lang': 'de',
        'pdfBackground': bg_pdf,
    }

    # generate tex command for pdflatex
    tex_cmd = u''
    for key, val in tex_vars.iteritems():
        tex_cmd += '\\newcommand{\\%s}{%s}' % (key, TexTools.escape(val))
    tex_cmd += '\\input{%s}' % tpl_tex
    tex_cmd = u'"'+tex_cmd+'"'

    # make latex show ß correctly in pdf:
    tex_cmd = tex_cmd.replace(u'ß', u'\\ss{}')

    # XXX: try to find out, why utf-8 doesn't work on debian
    # TODO: Handle any return code not equal to zero
    subprocess.call(
        [
            'pdflatex',
            '-jobname', filename,
            '-output-directory', path,
            '-interaction', 'nonstopmode',
            '-halt-on-error',
            tex_cmd.encode('latin_1')
        ],
        stdout=open(os.devnull, 'w'),  # hide output
        stderr=subprocess.STDOUT,
        cwd=pdflatex_dir
    )

    # cleanup
    aux = os.path.join(path, filename + '.aux')
    if os.path.isfile(aux):
        os.unlink(aux)

    archive_dues16_invoice(receipt_pdf, invoice)

    return receipt_pdf