def get(self, request, pk: int, *args, **kwargs) -> http.HttpResponse: student = get_object_or_404(Student, pk=pk) document = pdfs.create_statement(student) filename = strings.normalize( f'Statement_{student.firstname}_{student.surname}.pdf') return http.HttpResponse( document, content_type='application/pdf', headers={'Content-Disposition': f'inline;filename={filename}'})
def get(self, request, pk: int, *args, **kwargs) -> http.HttpResponse: invoice = get_object_or_404(models.Invoice, pk=pk) document = pdfs.create_invoice(invoice) filename = strings.normalize( f'Invoice_{invoice}{invoice.invoiced_to}.pdf').replace(' ', '_') return http.HttpResponse( document, content_type='application/pdf', headers={'Content-Disposition': f'inline;filename={filename}'})
def get(self, request, allocation: int, enrolment_id: int, *args, **kwargs) -> http.HttpResponse: enrolment = get_object_or_404(Enrolment, pk=enrolment_id) student = enrolment.qa.student document = pdfs.create_receipt(allocation=allocation, student=student) filename = strings.normalize( f'Receipt_{allocation}_{student.firstname}_{student.surname}.pdf') return http.HttpResponse( document, content_type='application/pdf', headers={'Content-Disposition': f'inline;filename={filename}'})
def _render_statement(enrolment: models.Enrolment, student: Student, address: Address, fees: list[Ledger]) -> bytes: module = enrolment.module pdf = ContedPDF() pdf.bottom_left_text = ( f"In the event of a query please contact: {module.phone or ''} " # todo: remove '' once phone null=False f"({module.email or '*****@*****.**'})") # Creating name and address information on the left pdf.set_font_size(12) name = f"{student.title or ''} {student.firstname} {student.surname}".strip( ) pdf.cell(30, 4, name) pdf.cell(0, 4, date.today().strftime(DATE_FORMAT), 0, 1, 'R') pdf.address_block(FormattedAddress(address)) # Invoice specific text above tables pdf.ln(40) pdf.multi_cell(0, 4, f'Statement for course: {module.title} ({module.code})', align='L') if module.start_date: pdf.set_font_size(9) pdf.cell(0, 10, f'Starts {module.start_date.strftime(DATE_FORMAT)}', ln=1) pdf.set_font_size(10) # Stripy colors fill = cycle([True, False]) pdf.set_fill_color(231, 231, 231) # Bootstrap-like striped-table grey # Create the table header, data array and column widths to pass to the table function pdf.set_widths([100, 40, 30]) pdf.set_aligns(['L', 'L', 'R']) for fee in fees: data = [fee.narrative, fee.type.description, f'£{fee.amount:.2f}'] pdf.improved_multi_cell_table(data=data, draw_border=False, fill=next(fill)) footer = ['Remaining', f'£{enrolment.get_balance():.2f}'] pdf.set_widths([150, 20]) pdf.improved_multi_cell_table(footer=footer, footer_border=False) pdf.set_title(normalize(f'Statement: {module.code} - {student.surname}')) return pdf.output(dest='S').encode('latin-1')
def render_document(*, contract: models.Contract) -> str: surname = normalize(contract.tutor_module.tutor.student.surname) context = { **contract.options, 'identifier': f'{contract.tutor_module.module.code}-{surname.upper()}-{contract.id}', 'preview_class': '' if contract.is_signed else 'highlight', 'is_signed': contract.is_signed, 'signatory': settings.CONTRACT_SIGNATORY, 'signature_image': settings.CONTRACT_SIGNATURE_IMAGE, } template_map: dict[str, str] = { models.Types.CASUAL_TEACHING: 'contract/pdfs/casual_teaching_contract.html', models.Types.GUEST_SPEAKER: 'contract/pdfs/guest_speaker_letter.html', } view = template_map[contract.type] return render_to_string(view, context)
def get(self, request, pk: int, *args, **kwargs) -> http.HttpResponse: contract = get_object_or_404(models.Contract, pk=pk) html_doc = self.render_document(contract=contract) font_config = FontConfiguration( ) # Makes @font-face and google fonts @import work output = HTML( string=html_doc, # Used fetch static images. Could be done with system file paths, but this'll work for HTML or PDF base_url=settings.CANONICAL_URL, ).write_pdf( stylesheets=[ CSS(Path(__file__).parent / 'static/css/tutor_contract.css', font_config=font_config) ], font_config=font_config, ) filename = normalize( f"contract_{contract.options['full_name']}_{contract.tutor_module.module.code}.pdf" ) return http.HttpResponse( output, content_type='application/pdf', headers={'Content-Disposition': f'filename="{filename}"'})
def _render_transcript( *, student: Student, address_lines: list[str], enrolments: list[Enrolment], level: str, header: bool, ) -> bytes: """Legacy routine: produces a transcript of all credit at a given level level takes 'undergraduate' and 'postgraduate' for undergraduate and postgraduate """ pdf = TranscriptPDF(print_header=header, level=level) pdf.set_font('', 'B', 12) name = f"{student.title or ''} {student.firstname} {student.surname}".strip( ) pdf.cell(30, 4, name, ln=1) pdf.address_block(address_lines) pdf.ln(-8) pdf.set_font('', 'B', 10) pdf.cell(140, 4, 'Date ', align='R') pdf.set_font('', '', 10) pdf.cell(0, 4, datetime.now().strftime(DATE_FORMAT), ln=1) pdf.set_font('', 'B', 10) pdf.cell(140, 4, 'Registration ', align='R') pdf.set_font('', '', 10) pdf.cell(0, 4, str(student.husid).zfill(13), ln=1) pdf.ln(15) pdf.set_font('', 'B', 14) pdf.cell(0, 10, 'Record of CATS Points', ln=1, align='C') # And now a lovely table pdf.set_widths([24, 58, 20, 12, 22, 22, 12]) def table_header(): pdf.improved_multi_cell_table( header=[ 'Module', 'Title', 'Result', 'FHEQ', 'Start date', 'End date', 'Points' ], header_border=0, header_align='L', ) table_header() pdf.set_aligns(['L', 'L', 'L', 'C', 'L', 'L', 'R']) # Stripy colors fill = cycle([True, False]) pdf.set_fill_color(231, 231, 231) # Bootstrap-like striped-table grey pdf.set_font('', '', 9) for enrolment in enrolments: # Handle multi_cells' inability to next-page in tables properly if pdf.y + 10 > pdf.page_break_trigger: pdf.add_page() table_header() pdf.set_font('', '', 9) pdf.improved_multi_cell_table( data=[ enrolment.module.code, enrolment.module.title, str(enrolment.mark or '') if level == 'postgraduate' else 'Passed', str(enrolment.module.points_level.fheq_level), enrolment.module.start_date.strftime(DATE_FORMAT), enrolment.module.end_date.strftime(DATE_FORMAT), str(enrolment.points_awarded), ], draw_border=False, fill=next(fill), ) pdf.set_widths([130, 25, 15]) pdf.improved_multi_cell_table( header=[ '', 'Total', str(sum(enrolment.points_awarded for enrolment in enrolments)) ], header_border=0, header_align='R', ) pdf.set_title( strings.normalize( f'{level.upper()} transcript: {student.firstname} {student.surname}' )) return pdf.output(dest='S').encode('latin-1')
def _render_statement(*, student: models.Student, address: models.Address, enrolments: list[Enrolment]) -> bytes: pdf = ContedPDF() pdf.bottom_left_text = 'In the event of a query please contact: [email protected]' pdf.set_font_size(12) name = f"{student.title or ''} {student.firstname} {student.surname}".strip( ) pdf.cell(30, 4, name) pdf.cell(0, 4, date.today().strftime(DATE_FORMAT), 0, 1, 'R') for line in FormattedAddress(address): pdf.cell(30, 5, line, ln=1) pdf.ln(24) pdf.set_font('', 'B', 14) pdf.multi_cell( 0, 4, f'Financial statement for {student.firstname} {student.surname}', align='L') pdf.ln(8) pdf.set_fill_color(231, 231, 231) # Bootstrap-like striped-table grey # Create the table header, data array and column widths to pass to the table function pdf.set_widths([25, 89, 16, 18, 22]) pdf.set_aligns(['L', 'L', 'L', 'L', 'R']) for enrolment in enrolments: fill = cycle([True, False]) pdf.set_font('', 'B', 11) pdf.multi_cell( 170, 4, f'{enrolment.module.title} ({enrolment.module.code}) ({enrolment.status})' ) pdf.set_font('', '', 9) for fee in enrolment.ledger_set.all(): data = [ fee.timestamp.strftime(DATE_FORMAT), fee.narrative or '', str(fee.invoice_ledger.invoice) if hasattr( fee, 'invoice_ledger') else '', fee.type.description, f'£{fee.amount:.2f}', ] pdf.improved_multi_cell_table(data=data, draw_border=False, fill=next(fill)) # Balance footer for each table pdf.set_font('', 'B', 9) enrolment.total = sum(fee.amount for fee in enrolment.ledger_set.all()) pdf.improved_multi_cell_table( data=['', '', '', 'Balance', f'£{enrolment.total:.2f}'], draw_border=False, ) pdf.ln(4) pdf.ln(4) pdf.set_font('', 'B', 12) pdf.cell(114) pdf.cell(34, 4, 'Total balance') total = sum(enrolment.total for enrolment in enrolments) pdf.cell(22, 4, f'£{total:.2f}', align='R', ln=1) pdf.set_title( strings.normalize( f'Financial statement for {student.firstname} {student.surname}')) return pdf.output(dest='S').encode('latin-1')