From 845a58212bf384ad1a07205cce3f89e0dff5340b Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 3 Aug 2022 12:55:27 +0200 Subject: [PATCH] Make samples in README work --- README.rst | 106 +++++++++++++++++++++++++++++----------- tests/samples/Empty.pdf | Bin 0 -> 7273 bytes tests/test_mininal.py | 66 +++++++++++++++++++++++++ tests/test_roundtrip.py | 3 +- 4 files changed, 145 insertions(+), 30 deletions(-) create mode 100644 tests/samples/Empty.pdf create mode 100644 tests/test_mininal.py diff --git a/README.rst b/README.rst index dbd5c06..50e00d1 100644 --- a/README.rst +++ b/README.rst @@ -15,48 +15,98 @@ format for sending digital invoices. ZUGFeRD XML files are to be attached to a P file. This library can be used to generate or parse the contents of this XML file as well as attach it to a PDF. We do not support parsing PDF files (for now). -By low-level, we mean that this library models the ZUGFeRD data model 1:1 without any further -abstractions or simplifications. You can set and parse all parameters defined in ZUGFeRD 2.1. +By low-level, we mean that this library tries to model the ZUGFeRD data model 1:1 without any +further abstractions or simplifications. You can set and parse all parameters defined in ZUGFeRD +2.2. -All output is validated against the official XSDs, but no validation of profile levels (basic, comfort, extended) is performed. +All output is validated against the official XSDs, but no validation of profile levels +(basic, comfort, extended) is performed. Usage ----- Parsing:: - >>> from drafthorse.models.document import Document - >>> samplexml = open("sample.xml", "rb").read() - >>> doc = Document.parse(samplexml) - >>> str(doc.trade.agreement.seller.name) - 'Lieferant GmbH' + from drafthorse.models.document import Document + samplexml = open("sample.xml", "rb").read() + doc = Document.parse(samplexml) + print(doc.trade.agreement.seller.name) Generating:: - >>> from datetime import date - >>> from drafthorse.models.document import Document - >>> from drafthorse.models.note import IncludedNote - - >>> doc = Document() - >>> doc.context.guideline_parameter.id = "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort" - >>> doc.header.id = "RE1337" - >>> doc.header.name = "RECHNUNG" - >>> doc.header.type_code = "380" - >>> doc.header.issue_date_time.value = date.today() - >>> doc.header.languages.add("de") - >>> note = IncludedNote() - >>> note.content.add("Test Node 1") - >>> doc.header.notes.add(n) - >>> doc.trade.agreement.seller.name = "Lieferant GmbH" - - >>> xml = doc.serialize() - >>> xml - b'>> new_pdf_bytes = attach_xml(original_pdf_bytes, xml, 'BASIC') + with open("input.pdf", "rb") as original_file: + new_pdf_bytes = attach_xml(original_file.read(), xml, 'EXTENDED') + + with open("output.pdf", "wb") as f: + f.write(new_pdf_bytes) Development diff --git a/tests/samples/Empty.pdf b/tests/samples/Empty.pdf new file mode 100644 index 0000000000000000000000000000000000000000..eae1b7af658dcd34586ad2b7ad7164e0b75ca4b7 GIT binary patch literal 7273 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