Skip to content

Commit f4f4f19

Browse files
authored
Add support for prefixed UBL invoice and credit note XML (#8)
* Add support for prefixed UBL invoice and credit note XML
1 parent f8d05bf commit f4f4f19

File tree

6 files changed

+176
-17
lines changed

6 files changed

+176
-17
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
currentVersion=0.1.4
1+
currentVersion=0.1.5
22
mainClassName=io.github.easybill.xrviz.App

src/main/java/io/github/easybill/xrviz/XslTransformer.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.easybill.xrviz;
22

3+
import net.sf.saxon.regex.RegularExpression;
34
import org.apache.fop.apps.FOPException;
45
import org.apache.fop.apps.Fop;
56
import org.apache.fop.apps.FopFactory;
@@ -23,13 +24,16 @@
2324
import java.util.Optional;
2425
import java.util.logging.Level;
2526
import java.util.logging.Logger;
27+
import java.util.regex.Matcher;
28+
import java.util.regex.Pattern;
2629

2730
public class XslTransformer {
2831
static final Logger logger = Logger.getGlobal();
2932
static final String BASE_PATH = Config.getValue(Config.Keys.DATA_PATH);
30-
public static final String CII_VALIDATION_STRING = "<rsm:CrossIndustryInvoice";
31-
public static final String UBL_I_VALIDATION_STRING = "<Invoice";
32-
public static final String UBL_C_VALIDATION_STRING = "<CreditNote";
33+
public static final String CII_VALIDATION_STRING = "CrossIndustryInvoice";
34+
public static final String UBL_I_VALIDATION_STRING = "Invoice";
35+
public static final String UBL_C_VALIDATION_STRING = "CreditNote";
36+
public static final Pattern REGEX = Pattern.compile("[<:](CrossedustryInvoice|Invoice|CreditNote)");
3337

3438
enum DocumentType {
3539
CII("cii-xr.xsl"),
@@ -51,15 +55,18 @@ public static Optional<DocumentType> detectDocumentType(String xmlContent) {
5155
return Optional.empty();
5256
}
5357

54-
if (xmlContent.contains(CII_VALIDATION_STRING)) {
55-
return Optional.of(CII);
56-
} else if (xmlContent.contains(UBL_I_VALIDATION_STRING)) {
57-
return Optional.of(UBL_I);
58-
} else if (xmlContent.contains(UBL_C_VALIDATION_STRING)) {
59-
return Optional.of(UBL_C);
58+
final Matcher matcher = REGEX.matcher(xmlContent);
59+
if (!matcher.find()) {
60+
return Optional.empty();
6061
}
6162

62-
return Optional.empty();
63+
return switch (matcher.group(1)) {
64+
case CII_VALIDATION_STRING -> Optional.of(CII);
65+
case UBL_I_VALIDATION_STRING -> Optional.of(UBL_I);
66+
case UBL_C_VALIDATION_STRING -> Optional.of(UBL_C);
67+
default -> Optional.empty();
68+
};
69+
6370
}
6471
}
6572

src/main/java/io/github/easybill/xrviz/handler/XmlRequestExtractor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
import java.net.HttpURLConnection;
1010
import java.util.logging.Logger;
11+
import java.util.regex.Pattern;
1112

1213
import static io.github.easybill.xrviz.XslTransformer.*;
1314

1415
public abstract class XmlRequestExtractor {
1516
static final Logger logger = Logger.getGlobal();
17+
static final Pattern REGEX = Pattern.compile("[<:](CrossedustryInvoice|Invoice|CreditNote)");
1618

1719
Optional<String> validate(HttpExchange exchange) throws IOException {
1820
if (!exchange.getRequestMethod().equalsIgnoreCase("POST")) {
@@ -40,8 +42,6 @@ String getLanguage(HttpExchange exchange) {
4042
}
4143

4244
private boolean isXMLValid(String xml) {
43-
return !xml.isBlank() && (xml.contains(CII_VALIDATION_STRING) ||
44-
xml.contains(UBL_I_VALIDATION_STRING) ||
45-
xml.contains(UBL_C_VALIDATION_STRING));
45+
return !xml.isBlank() && (REGEX.matcher(xml).find());
4646
}
4747
}

src/test/http/api-test.http

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ Accept-Language: de
1717

1818
< ./ubl-invoice.xml
1919

20+
### Generate a HTML file from a prefixed UBL Invoice file
21+
POST {{baseUrl}}/convert.html
22+
Content-Type: application/xml
23+
Accept-Language: de
24+
25+
< ./ubl-invoice-prefix.xml
26+
2027
### Generate a HTML file from a UBL CreditNote file
2128
POST {{baseUrl}}/convert.html
2229
Content-Type: application/xml

src/test/http/ubl-invoice-prefix.xml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
3+
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
4+
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
5+
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0</cbc:CustomizationID>
6+
<cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
7+
<cbc:ID>123456XX</cbc:ID>
8+
<cbc:IssueDate>2016-04-04</cbc:IssueDate>
9+
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
10+
<cbc:Note>#ADU#Es gelten unsere Allgem. Geschäftsbedingungen, die Sie unter […] finden.</cbc:Note>
11+
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
12+
<cbc:BuyerReference>04011000-12345-03</cbc:BuyerReference>
13+
<cac:AccountingSupplierParty>
14+
<cac:Party>
15+
<cbc:EndpointID schemeID="EM">[email protected]</cbc:EndpointID>
16+
<cac:PartyName>
17+
<cbc:Name>[Seller trading name]</cbc:Name>
18+
</cac:PartyName>
19+
<cac:PostalAddress>
20+
<cbc:StreetName>[Seller address line 1]</cbc:StreetName>
21+
<cbc:CityName>[Seller city]</cbc:CityName>
22+
<cbc:PostalZone>12345</cbc:PostalZone>
23+
<cac:Country>
24+
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
25+
</cac:Country>
26+
</cac:PostalAddress>
27+
<cac:PartyTaxScheme>
28+
<cbc:CompanyID>DE 123456789</cbc:CompanyID>
29+
<cac:TaxScheme>
30+
<cbc:ID>VAT</cbc:ID>
31+
</cac:TaxScheme>
32+
</cac:PartyTaxScheme>
33+
<cac:PartyLegalEntity>
34+
<cbc:RegistrationName>[Seller name]</cbc:RegistrationName>
35+
<cbc:CompanyID>[HRA-Eintrag]</cbc:CompanyID>
36+
<cbc:CompanyLegalForm>123/456/7890, HRA-Eintrag in […]</cbc:CompanyLegalForm>
37+
</cac:PartyLegalEntity>
38+
<cac:Contact>
39+
<cbc:Name>nicht vorhanden</cbc:Name>
40+
<cbc:Telephone>+49 1234-5678</cbc:Telephone>
41+
<cbc:ElectronicMail>[email protected]</cbc:ElectronicMail>
42+
</cac:Contact>
43+
</cac:Party>
44+
</cac:AccountingSupplierParty>
45+
<cac:AccountingCustomerParty>
46+
<cac:Party>
47+
<cbc:EndpointID schemeID="EM">[email protected]</cbc:EndpointID>
48+
<cac:PartyIdentification>
49+
<cbc:ID>[Buyer identifier]</cbc:ID>
50+
</cac:PartyIdentification>
51+
<cac:PostalAddress>
52+
<cbc:StreetName>[Buyer address line 1]</cbc:StreetName>
53+
<cbc:CityName>[Buyer city]</cbc:CityName>
54+
<cbc:PostalZone>12345</cbc:PostalZone>
55+
<cac:Country>
56+
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
57+
</cac:Country>
58+
</cac:PostalAddress>
59+
<cac:PartyLegalEntity>
60+
<cbc:RegistrationName>[Buyer name]</cbc:RegistrationName>
61+
</cac:PartyLegalEntity>
62+
</cac:Party>
63+
</cac:AccountingCustomerParty>
64+
<cac:PaymentMeans>
65+
<cbc:PaymentMeansCode>58</cbc:PaymentMeansCode>
66+
<cac:PayeeFinancialAccount>
67+
<!-- dies ist eine nicht existerende aber valide IBAN als test dummy -->
68+
<cbc:ID>DE75512108001245126199</cbc:ID>
69+
</cac:PayeeFinancialAccount>
70+
</cac:PaymentMeans>
71+
<cac:PaymentTerms>
72+
<cbc:Note>Zahlbar sofort ohne Abzug.</cbc:Note>
73+
</cac:PaymentTerms>
74+
<cac:TaxTotal>
75+
<cbc:TaxAmount currencyID="EUR">22.04</cbc:TaxAmount>
76+
<cac:TaxSubtotal>
77+
<cbc:TaxableAmount currencyID="EUR">314.86</cbc:TaxableAmount>
78+
<cbc:TaxAmount currencyID="EUR">22.04</cbc:TaxAmount>
79+
<cac:TaxCategory>
80+
<cbc:ID>S</cbc:ID>
81+
<cbc:Percent>7</cbc:Percent>
82+
<cac:TaxScheme>
83+
<cbc:ID>VAT</cbc:ID>
84+
</cac:TaxScheme>
85+
</cac:TaxCategory>
86+
</cac:TaxSubtotal>
87+
</cac:TaxTotal>
88+
<cac:LegalMonetaryTotal>
89+
<cbc:LineExtensionAmount currencyID="EUR">314.86</cbc:LineExtensionAmount>
90+
<cbc:TaxExclusiveAmount currencyID="EUR">314.86</cbc:TaxExclusiveAmount>
91+
<cbc:TaxInclusiveAmount currencyID="EUR">336.9</cbc:TaxInclusiveAmount>
92+
<cbc:PayableAmount currencyID="EUR">336.9</cbc:PayableAmount>
93+
</cac:LegalMonetaryTotal>
94+
<cac:InvoiceLine>
95+
<cbc:ID>Zeitschrift [...]</cbc:ID>
96+
<cbc:Note>Die letzte Lieferung im Rahmen des abgerechneten Abonnements erfolgt in 12/2016 Lieferung erfolgt / erfolgte direkt vom Verlag</cbc:Note>
97+
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
98+
<cbc:LineExtensionAmount currencyID="EUR">288.79</cbc:LineExtensionAmount>
99+
<cac:InvoicePeriod>
100+
<cbc:StartDate>2016-01-01</cbc:StartDate>
101+
<cbc:EndDate>2016-12-31</cbc:EndDate>
102+
</cac:InvoicePeriod>
103+
<cac:OrderLineReference>
104+
<cbc:LineID>6171175.1</cbc:LineID>
105+
</cac:OrderLineReference>
106+
<cac:Item>
107+
<cbc:Description>Zeitschrift Inland</cbc:Description>
108+
<cbc:Name>Zeitschrift [...]</cbc:Name>
109+
<cac:SellersItemIdentification>
110+
<cbc:ID>246</cbc:ID>
111+
</cac:SellersItemIdentification>
112+
<cac:CommodityClassification>
113+
<cbc:ItemClassificationCode listID="IB">0721-880X</cbc:ItemClassificationCode>
114+
</cac:CommodityClassification>
115+
<cac:ClassifiedTaxCategory>
116+
<cbc:ID>S</cbc:ID>
117+
<cbc:Percent>7</cbc:Percent>
118+
<cac:TaxScheme>
119+
<cbc:ID>VAT</cbc:ID>
120+
</cac:TaxScheme>
121+
</cac:ClassifiedTaxCategory>
122+
</cac:Item>
123+
<cac:Price>
124+
<cbc:PriceAmount currencyID="EUR">288.79</cbc:PriceAmount>
125+
</cac:Price>
126+
</cac:InvoiceLine>
127+
<cac:InvoiceLine>
128+
<cbc:ID>Porto + Versandkosten</cbc:ID>
129+
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
130+
<cbc:LineExtensionAmount currencyID="EUR">26.07</cbc:LineExtensionAmount>
131+
<cac:Item>
132+
<cbc:Name>Porto + Versandkosten</cbc:Name>
133+
<cac:ClassifiedTaxCategory>
134+
<cbc:ID>S</cbc:ID>
135+
<cbc:Percent>7</cbc:Percent>
136+
<cac:TaxScheme>
137+
<cbc:ID>VAT</cbc:ID>
138+
</cac:TaxScheme>
139+
</cac:ClassifiedTaxCategory>
140+
</cac:Item>
141+
<cac:Price>
142+
<cbc:PriceAmount currencyID="EUR">26.07</cbc:PriceAmount>
143+
</cac:Price>
144+
</cac:InvoiceLine>
145+
</ubl:Invoice>

version-badge.svg

Lines changed: 3 additions & 3 deletions
Loading

0 commit comments

Comments
 (0)