generate zugferd-pdf

This commit is contained in:
Frederik Jaeckel 2024-12-06 14:04:35 +01:00
parent 26388d3816
commit 7f433d9b80
5 changed files with 171 additions and 29 deletions

View file

@ -3,6 +3,22 @@ msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
##############
# ir.message #
##############
msgctxt "model:ir.message,text:msg_invoice_must_posted"
msgid "Invoice '%(invname)s' must be posted."
msgstr "Rechnung '%(invname)s' muß festgeschrieben sein."
msgctxt "model:ir.message,text:msg_no_report_found"
msgid "No report found for invoices in PDF format."
msgstr "Kein Report für Rechnungen im PDF-Format gefunden."
msgctxt "model:ir.message,text:msg_invalid_cachecontent"
msgid "No PDF has yet been generated for the invoice '%(invoice_name)s' or the saved document has an incorrect format."
msgstr "Für die Rechnung '%(invoice_name)s' wurde noch keine PDF erzeugt oder das gespeicherte Dokument hat ein falsches Format."
#############
# ir.action #
#############

View file

@ -2,6 +2,18 @@
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "model:ir.message,text:msg_invoice_must_posted"
msgid "Invoice '%(invname)s' must be posted."
msgstr "Invoice '%(invname)s' must be posted."
msgctxt "model:ir.message,text:msg_no_report_found"
msgid "No report found for invoices in PDF format."
msgstr "No report found for invoices in PDF format."
msgctxt "model:ir.message,text:msg_invalid_cachecontent"
msgid "No PDF has yet been generated for the invoice '%(invoice_name)s' or the saved document has an incorrect format."
msgstr "No PDF has yet been generated for the invoice '%(invoice_name)s' or the saved document has an incorrect format."
msgctxt "model:ir.action,name:act_wizard_report"
msgid "eDocument Export"
msgstr "eDocument Export"

View file

@ -8,6 +8,12 @@
<record model="ir.message" id="msg_invoice_must_posted">
<field name="text">Invoice '%(invname)s' must be posted.</field>
</record>
<record model="ir.message" id="msg_no_report_found">
<field name="text">No report found for invoices in PDF format.</field>
</record>
<record model="ir.message" id="msg_invalid_cachecontent">
<field name="text">No PDF has yet been generated for the invoice '%(invoice_name)s' or the saved document has an incorrect format.</field>
</record>
</data>
</tryton>

View file

@ -78,14 +78,48 @@ class RunXRechnungReport(Wizard):
pool = Pool()
Invoice = pool.get('account.invoice')
WizRepStart = pool.get('account_invoice_xrechnung.runrep.start')
Configuration = pool.get('account.configuration')
cfg1 = Configuration.get_singleton()
invoice = Invoice.browse([context.get('active_id', -1)])
result = {
'edocument': WizRepStart.default_edocument(),
'invoice': context.get('active_id', -1),
'state': invoice[0].state if invoice else ''}
if cfg1 and cfg1.xrechn_default:
result['edocument'] = cfg1.xrechn_default
return result
def generate_invoice_reports(self, data):
""" generate missing reports and store to db
Args:
data (dict): report-data
"""
pool = Pool()
Invoice = pool.get('account.invoice')
XReport = pool.get('account_invoice_xrechnung.export', type='report')
invoices = Invoice.search([
('id', '=', data['invoice']),
('type', '=', 'out')])
to_generate = [x.id for x in invoices if not x.invoice_report_cache]
if to_generate:
report_action = XReport.get_used_report()
# run selected report on invoices w/o stored report-data
data2 = {}
data2.update(data)
data2['action_id'] = report_action.id
data2['model'] = report_action.model
data2['id'] = to_generate[0]
data2['ids'] = to_generate
RepInvoice = pool.get(report_action.report_name, type='report')
with Transaction().set_context({'with_rec_name': False}):
RepInvoice.execute(to_generate, data2)
def do_export(self, action):
""" run export
"""
@ -93,9 +127,17 @@ class RunXRechnungReport(Wizard):
raise UserError(gettext(
'account_invoice_xrechnung.msg_invoice_must_posted',
invname=self.start.invoice.rec_name))
return action, {
data = {
'invoice': self.start.invoice.id,
'edocument': self.start.edocument,
'as_zip': self.start.as_zip}
# if zugferd - generate missing report-cache-items
if data['edocument'] == 'edocument.facturxext.invoice-ferd':
# pdf is stored to db
self.generate_invoice_reports(data)
return action, data
# end RunXRechnungReport

View file

@ -6,9 +6,11 @@
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 slugify import slugify
from trytond.exceptions import UserError
from trytond.i18n import gettext
from .wizard_runreport import edoc_versions
@ -29,12 +31,37 @@ class XReport(Report):
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 = pool.get(data['edocument'].split('-')[0])
EDocument = document_para[0]
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']])
@ -46,31 +73,70 @@ class XReport(Report):
'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
# pdf_data = generate_from_binary(
# pdf_file='pdf_content',
# xml=invoice_xml,
# check_xsd=True,
# pdf_metadata={
# 'author': invoice.company.rec_name,
# 'keywords': 'Factur-X, Invoice',
# 'title': invoice.number,
# 'subject': invoice.description},
# lang='de-DE')
if data['as_zip'] is True:
return (
'zip',
cls.compress_as_zip('%(fname)s.%(ext)s' % {
'fname': file_name,
'ext': 'xml',
}, invoice_xml),
False,
file_name)
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 ('xml', invoice_xml, False, file_name)
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 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
if not (invoice.invoice_report_cache and (
invoice.invoice_report_format == 'pdf')):
raise UserError(gettext(
'account_invoice_xrechnung.msg_invalid_cachecontent',
invoice_name=invoice.rec_name))
zugferd_pdf = generate_from_binary(
pdf_file=invoice.invoice_report_cache,
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