Skip to content

Commit

Permalink
Merge pull request #4 from Skulli/feature_export_to_zugferd
Browse files Browse the repository at this point in the history
Modul zum Konvertieren von PDF/A1 zu PDF/A2 und zum Erzeugen…
  • Loading branch information
Skulli authored Jun 28, 2024
2 parents dc33831 + 617a01a commit 3943aa0
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/secretariat/export.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Secretariat
module Export
end
end
Binary file not shown.
92 changes: 92 additions & 0 deletions lib/secretariat/export/zugferd.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
module Secretariat
module Export
module Zugferd
require "tmpdir"
require "logger"
require "open3"

JAR_PATH = Secretariat.file_path("/lib/secretariat/export/bin/jar/Mustang-CLI-2.11.0.jar")

def self.logger
log_directory = File.expand_path("../../../../log", __FILE__)
FileUtils.mkdir_p(log_directory) unless Dir.exist?(log_directory)

@@logger ||= Logger.new(File.join(log_directory, "export.log"))
end

def self.convert_a1_to_a3_params(pdf_a1, output_file_path)
"--action a3only --source #{pdf_a1} --out #{output_file_path}"
end

def self.combine_pdf_and_xml_params(source_pdf, source_xml, output_file_path, attachments_pathlist: '\"\"')
"--action combine --source #{source_pdf} --source-xml #{source_xml} --out #{output_file_path} --format zf --version 2 --profile E --attachments #{attachments_pathlist}"
end

def self.call_jar(params)
command = "java -Xmx1G -Dfile.encoding=UTF-8 -jar #{JAR_PATH} #{params}"

logger.info("Executing command: #{command}")

stdout, stderr, status = Open3.capture3(command)

if status.success?
logger.info("Command executed successfully")
else
logger.error("Command failed with error: #{stderr}")
logger.error("Standard output: #{stdout}")
end

status.success?
end

def self.convert_to_a3(source_pdf:, output_filename: output_filename_with_suffix(source_pdf, "_a3"), output_dir: Dir.mktmpdir)
output_file_path = File.join(output_dir, output_filename)

begin
result = call_jar(convert_a1_to_a3_params(source_pdf, output_file_path))

unless result
logger.error("Failed to convert pdf")
raise "Failed to convert pdf"
end

logger.info("Successfully converted PDF to PDFA/3: #{output_file_path}")

output_file_path
rescue => e
logger.error("Error during file conversion: #{e.message}")
raise e
ensure
File.delete(output_file_path) if output_dir == Dir.tmpdir && File.exist?(output_file_path)
end
end

def self.combine_files(source_pdf:, source_xml:, output_filename: output_filename_with_suffix(source_pdf, "_zugferd"), output_dir: Dir.mktmpdir)
output_file_path = File.join(output_dir, output_filename)

begin
result = call_jar(combine_pdf_and_xml_params(source_pdf, source_xml, output_file_path))

unless result
logger.error("Failed to combine files")
raise "Failed to combine files"
end

logger.info("Successfully combined files into #{output_file_path}")

output_file_path
rescue => e
logger.error("Error during file combination: #{e.message}")
raise e
ensure
File.delete(output_file_path) if output_dir == Dir.tmpdir && File.exist?(output_file_path)
end
end

def self.output_filename_with_suffix(source_file, suffix)
ext = File.extname(source_file)
File.basename(source_file, ext) + suffix + ext
end
end
end
end
208 changes: 208 additions & 0 deletions spec/fixtures/zugferd_2/test-x.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>

<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
<rsm:ExchangedDocumentContext>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>RE-20190610/507</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20190610</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Design (hours): Of a sample invoice</ram:Name>
<ram:Description/>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>160.0000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>160.0000</ram:ChargeAmount>
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="HUR">1.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>160.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>2</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Ballons: various colors, ~2000ml</ram:Name>
<ram:Description/>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.7900</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.7900</ram:ChargeAmount>
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">400.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>316.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>3</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Hot air „heiße Luft“ (litres)</ram:Name>
<ram:Description/>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:GrossPriceProductTradePrice>
<ram:ChargeAmount>0.0250</ram:ChargeAmount>
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
</ram:GrossPriceProductTradePrice>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>0.0250</ram:ChargeAmount>
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="LTR">800.0000</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>20.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>AB321</ram:BuyerReference>
<ram:SellerTradeParty>
<ram:Name>Bei Spiel GmbH</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID schemeID="9930">DE136695976</ram:ID>
<ram:TradingBusinessName>Bei Spiel GmbH</ram:TradingBusinessName>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Ingmar N. Fo</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>++49(0)237823</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>[email protected]</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:LineOne>Ecke 12</ram:LineOne>
<ram:CityName>Stadthausen</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="FC">22/815/0815/4</ram:ID>
</ram:SpecifiedTaxRegistration>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE136695976</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Theodor Est</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>88802</ram:PostcodeCode>
<ram:LineOne>Bahnstr. 42</ram:LineOne>
<ram:CityName>Spielkreis</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE999999999</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20190610</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:PaymentReference>RE-20190610/507</ram:PaymentReference>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>42</ram:TypeCode>
<ram:Information>Überweisung</ram:Information>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE88 2008 0000 0970 3757 00</ram:IBANID>
<ram:ProprietaryID>44421800</ram:ProprietaryID>
</ram:PayeePartyCreditorFinancialAccount>
<ram:PayeeSpecifiedCreditorFinancialInstitution>
<ram:BICID>COBADEFFXXX</ram:BICID>
</ram:PayeeSpecifiedCreditorFinancialInstitution>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>11.20</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>160.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>63.84</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>336.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Zahlbar ohne Abzug bis 01.07.2019</ram:Description>
<ram:DueDateDateTime>
<udt:DateTimeString format="102">20190701</udt:DateTimeString>
</ram:DueDateDateTime>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>496.00</ram:LineTotalAmount>
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
<ram:TaxBasisTotalAmount>496.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount>
<ram:GrandTotalAmount>571.04</ram:GrandTotalAmount>
<ram:DuePayableAmount>571.04</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>
Binary file added spec/fixtures/zugferd_2/test_a1.pdf
Binary file not shown.
52 changes: 52 additions & 0 deletions spec/lib/secretariat/export/zugferd_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require "spec_helper"
require "./lib/secretariat"
require "./lib/secretariat/export"
require "./lib/secretariat/export/zugferd"

RSpec.describe Secretariat::Export::Zugferd, type: :module do
let(:source_pdf) { Secretariat.file_path("spec/fixtures/zugferd_2/test_a1.pdf") }
let(:source_xml) { Secretariat.file_path("spec/fixtures/zugferd_2/test-x.xml") }
let(:output_dir) { Dir.mktmpdir }
let(:output_filename2) { "output2.pdf" }
let(:output_file_path) { File.join(output_dir, "test_a1_a3.pdf") }
let(:output_file_path2) { File.join(output_dir, output_filename2) }
let(:attachments_pathlist) { "" }

after(:each) do
FileUtils.remove_entry(output_dir) if File.exist?(output_dir)
end

describe "convert_file" do
it "converts a1 to a3" do
result = Secretariat::Export::Zugferd.convert_to_a3(
source_pdf: source_pdf,
output_dir: output_dir
)

expect(result).to eq(output_file_path)
expect(File.exist?(result)).to be(true)
end

after do
File.delete(output_file_path) if File.exist?(output_file_path)
end
end

describe "combine_files" do
it "combines PDF and XML files" do
result = Secretariat::Export::Zugferd.combine_files(
source_pdf: source_pdf,
source_xml: source_xml,
output_filename: output_filename2,
output_dir: output_dir
)

expect(result).to eq(output_file_path2)
expect(File.exist?(result)).to be(true)
end

after do
File.delete(output_file_path2) if File.exist?(output_file_path2)
end
end
end

0 comments on commit 3943aa0

Please sign in to comment.