# -*- coding: utf-8 -*- # This file is part of the account-invoice-xrechnung-module # from m-ds for Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import zipfile from facturx import generate_from_binary from io import BytesIO from slugify import slugify from trytond.report import Report from trytond.pool import Pool from trytond.exceptions import UserError from trytond.i18n import gettext from trytond.transaction import Transaction from .wizard_runreport import edoc_versions class XReport(Report): 'eDocument Export' __name__ = 'account_invoice_xrechnung.export' @classmethod def compress_as_zip(cls, fname, data): """ compress """ content = BytesIO() with zipfile.ZipFile(content, 'w') as content_zip: content_zip.writestr(fname, data) return content.getvalue() @classmethod def execute(cls, ids, data): """ skip export-engine, run edocument-xml-convert """ def export_data(exp_content, fname, ext, data2): """ get tuple to return from report.execute, Args: exp_content (bytes or str): result data of report fname (str): file name ext (str): extension data2 (dict): data Returns: tuple: return value of report """ if data2['as_zip'] is True: return ( 'zip', cls.compress_as_zip( '%(fname)s.%(ext)s' % { 'fname': fname, 'ext': ext}, exp_content), False, file_name) else: return (ext, exp_content, False, fname) pool = Pool() IrDate = pool.get('ir.date') Invoice = pool.get('account.invoice') document_para = data['edocument'].split('-') EDocument = pool.get(document_para[0]) document_var = document_para[1] if len(document_para) > 1 else None invoice, = Invoice.browse([data['invoice']]) template = EDocument(invoice) invoice_xml = template.render(edoc_versions[data['edocument']]) file_name = slugify('%(date)s-%(descr)s' % { 'date': IrDate.today().isoformat().replace('-', ''), 'descr': invoice.rec_name}, max_length=100, word_boundary=True, save_order=True) if document_var and ( document_var == 'ferd') and ( EDocument.__name__ == 'edocument.facturxext.invoice'): # convert to zugferd invoice_pdf = cls.get_zugferd_pdf(invoice, invoice_xml) return export_data(invoice_pdf, file_name, 'pdf', data) else: return export_data(invoice_xml, file_name, 'xml', data) @classmethod def get_used_report(cls): """ get report to use from config Raises: UserError: if not report was found Returns: record: ir.action.report """ pool = Pool() Configuration = pool.get('account.configuration') ActionReport = pool.get('ir.action.report') cfg1 = Configuration.get_singleton() act_report = None if cfg1 and cfg1.xrechn_zugferd_report: act_report = cfg1.xrechn_zugferd_report else: # no report defined, use 1st found act_report = ActionReport.search([ ('model', '=', 'account.invoice'), ('extension', '=', 'pdf')], limit=1) if act_report: act_report = act_report[0] if not act_report: raise UserError(gettext( 'account_invoice_xrechnung.msg_no_report_found')) return act_report @classmethod def generate_pdf_data(cls, records): """ generate pdf of invoice using defined report Args: records (list): records of account.invoice Returns: list: dicts - {'content': , 'fname': 'file-name'} """ report_action = cls.get_used_report() RepInvoice = Pool().get(report_action.report_name, type='report') # run selected report on invoices w/o stored report-data data2 = {} data2['action_id'] = report_action.id data2['model'] = report_action.model result = [] for record in records: data2['id'] = record.id data2['ids'] = [record.id] with Transaction().set_context({'with_rec_name': False}): (ext, content, print1, fname) = RepInvoice.execute( [record.id], data2) result.append({ 'content': content, 'fname': fname}) return result @classmethod def get_zugferd_pdf(cls, invoice, invoice_xml): """ generate ZugFeRD-PDF Args: invoice (record): model account.invoice invoice_xml (str): xml-data """ # pdf was already stored to db, must be pdf if invoice.invoice_report_cache: if invoice.invoice_report_format != 'pdf': raise UserError(gettext( 'account_invoice_xrechnung.msg_invalid_cachecontent', invoice_name=invoice.rec_name)) pdf_data = invoice.invoice_report_cache else: # run report, could fail because we are in # readonly-transaction report_data = cls.generate_pdf_data([invoice]) if report_data: pdf_data = report_data[0]['content'] zugferd_pdf = generate_from_binary( pdf_file=pdf_data, xml=invoice_xml, check_xsd=True, pdf_metadata={ 'author': invoice.company.rec_name, 'keywords': 'Factur-X, Invoice, Tryton', 'title': invoice.number, 'subject': invoice.description}, lang='de-DE') return zugferd_pdf # end XReport