account_invoice_xrechnung/xreport.py
2024-12-12 12:37:56 +01:00

180 lines
6 KiB
Python

# -*- 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')], count=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': <pdf-data>, '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