Merge branch 'master' of github.com:ZUGFeRD/mustangproject

This commit is contained in:
jstaerk
2024-09-20 11:53:41 +02:00
10 changed files with 503 additions and 15 deletions

View File

@@ -41,7 +41,7 @@ public class Invoice implements IExportableTransaction {
protected String documentName = null, documentCode = null, number = null, ownOrganisationFullPlaintextInfo = null, referenceNumber = null, shipToOrganisationID = null, shipToOrganisationName = null, shipToStreet = null, shipToZIP = null, shipToLocation = null, shipToCountry = null, buyerOrderReferencedDocumentID = null, invoiceReferencedDocumentID = null, buyerOrderReferencedDocumentIssueDateTime = null, ownForeignOrganisationID = null, ownOrganisationName = null, currency = null, paymentTermDescription = null;
protected Date issueDate = null, dueDate = null, deliveryDate = null;
protected TradeParty sender = null, recipient = null, deliveryAddress = null;
protected TradeParty sender = null, recipient = null, deliveryAddress = null, payee = null;
protected ArrayList<CashDiscount> cashDiscounts = null;
@JsonDeserialize(contentAs = Item.class)
protected ArrayList<IZUGFeRDExportableItem> ZFItems = null;
@@ -577,6 +577,22 @@ public class Invoice implements IExportableTransaction {
this.deliveryAddress = deliveryAddress;
return this;
}
@Override
public TradeParty getPayee() {
return this.payee;
}
/***
* if the payee is not the seller, it can be specified here
* @param payee the payment receiving organisation
* @return fluent setter
*/
public Invoice setPayee(TradeParty payee) {
this.payee = payee;
return this;
}
/***
* Adds a cash discount (skonto)
* @param c the CashDiscount percent/period combination

View File

@@ -450,11 +450,19 @@ public interface IExportableTransaction {
*
* @return the IZUGFeRDExportableTradeParty delivery address
*/
default IZUGFeRDExportableTradeParty getDeliveryAddress() {
return null;
}
/***
* payee / payment receiver, if different from seller, ram:Payee (only supported for zf2)
*
* @return the IZUGFeRDExportableTradeParty payment receiver, if different from sellver
*/
default IZUGFeRDExportableTradeParty getPayee() {
return null;
}
/***
* specifies the document level delivery period, will be included in a
* BillingSpecifiedPeriod element

View File

@@ -39,8 +39,8 @@ public class TransactionCalculator implements IAbsoluteValueProvider {
}
/***
* the invoice total with VAT, corrected by prepaid amount, allowances and
* charges
* the invoice total with VAT, allowances and
* charges, WITHOUT considering prepaid amount
*
* @return the invoice total including taxes
*/

View File

@@ -155,11 +155,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
if ((party.getContact() != null) && (isSender || profile == Profiles.getByName("EN16931") || profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
xml += "<ram:DefinedTradeContact>";
if (party.getContact().getName() != null) {
xml += "<ram:PersonName>" + XMLTools.encodeXML(party.getContact().getName())
xml += "<ram:PersonName>"
+ XMLTools.encodeXML(party.getContact().getName())
+ "</ram:PersonName>";
}
if (party.getContact().getPhone() != null) {
xml += "<ram:TelephoneUniversalCommunication><ram:CompleteNumber>"
+ XMLTools.encodeXML(party.getContact().getPhone()) + "</ram:CompleteNumber>"
+ "</ram:TelephoneUniversalCommunication>";
@@ -200,7 +200,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ "</ram:CityName>";
}
//country IS mandatory
//country IS mandatory
xml += "<ram:CountryID>" + XMLTools.encodeXML(party.getCountry())
+ "</ram:CountryID>"
+ "</ram:PostalTradeAddress>";
@@ -228,6 +228,30 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
protected String getTradePartyPayeeAsXML(IZUGFeRDExportableTradeParty party) {
String xml = "";
// According EN16931 either GlobalID or seller assigned ID might be present for a Payee
if (party.getID() != null) {
xml += "<ram:ID>" + XMLTools.encodeXML(party.getID()) + "</ram:ID>";
}
if ((party.getGlobalIDScheme() != null) && (party.getGlobalID() != null)) {
xml += "<ram:GlobalID schemeID=\"" + XMLTools.encodeXML(party.getGlobalIDScheme()) + "\">"
+ XMLTools.encodeXML(party.getGlobalID())
+ "</ram:GlobalID>";
}
xml += "<ram:Name>" + XMLTools.encodeXML(party.getName()) + "</ram:Name>";
if (party.getLegalOrganisation() != null) {
xml += "<ram:SpecifiedLegalOrganization> ";
if (party.getLegalOrganisation().getSchemedID() != null) {
xml += "<ram:ID schemeID=\"" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getScheme()) + "\">" + XMLTools.encodeXML(party.getLegalOrganisation().getSchemedID().getID()) + "</ram:ID>";
}
xml += "</ram:SpecifiedLegalOrganization>";
}
return xml;
}
/***
* returns the XML for a charge or allowance on item level
@@ -247,8 +271,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
String reason = "";
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended"))) {
// only in extended profile
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
}
String reasonCode = "";
@@ -283,8 +306,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
String reason = "";
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended"))) {
// only in extended profile
if ((allowance.getReason() != null) && (profile == Profiles.getByName("Extended") || profile == Profiles.getByName("XRechnung"))) {
reason = "<ram:Reason>" + XMLTools.encodeXML(allowance.getReason()) + "</ram:Reason>";
}
String reasonCode = "";
@@ -588,6 +610,12 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
"</ram:ShipToTradeParty>";
}
if (this.trans.getPayee() != null) {
xml += "<ram:PayeeTradeParty>" +
getTradePartyPayeeAsXML(this.trans.getPayee()) +
"</ram:PayeeTradeParty>";
}
if (trans.getDeliveryDate() != null) {
xml += "<ram:ActualDeliverySupplyChainEvent>"

View File

@@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
@@ -74,6 +75,10 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
xpr = xpath.compile("//*[local-name()=\"BuyerTradeParty\"]|//*[local-name()=\"AccountingCustomerParty\"]/*");
NodeList BuyerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"PayeeTradeParty\"]|//*[local-name()=\"PayeeParty\"]/*");
NodeList payeeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
xpr = xpath.compile("//*[local-name()=\"ExchangedDocument\"]|//*[local-name()=\"HeaderExchangedDocument\"]");
NodeList ExchangedDocumentNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -84,6 +89,12 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
expectedGrandTotal = new BigDecimal(totalNodes.item(0).getTextContent());
}
xpr = xpath.compile("//*[local-name()=\"PrepaidAmount\"]");
NodeList prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (prepaidNodes.getLength() > 0) {
zpp.setTotalPrepaidAmount(new BigDecimal(prepaidNodes.item(0).getTextContent()));
}
Date issueDate = null;
Date dueDate = null;
Date deliveryDate = null;
@@ -282,8 +293,13 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
}
zpp.setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode);
bankDetails.forEach(bankDetail -> zpp.getSender().addBankDetails(bankDetail));
if (payeeNodes.getLength() > 0) {
zpp.setPayee(new TradeParty(payeeNodes));
}
if (buyerOrderIssuerAssignedID != null) {
zpp.setBuyerOrderReferencedDocumentID(buyerOrderIssuerAssignedID);
}
@@ -298,9 +314,9 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
xpr = xpath.compile("//*[local-name()=\"BuyerReference\"]");
String buyerReference = null;
totalNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (totalNodes.getLength() > 0) {
buyerReference = totalNodes.item(0).getTextContent();
prepaidNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
if (prepaidNodes.getLength() > 0) {
buyerReference = prepaidNodes.item(0).getTextContent();
}
if (buyerReference != null) {
zpp.setReferenceNumber(buyerReference);
@@ -400,7 +416,8 @@ public class ZUGFeRDInvoiceImporter extends ZUGFeRDImporter {
}
TransactionCalculator tc = new TransactionCalculator(zpp);
String expectedStringTotalGross = tc.getGrandTotal().toPlainString();
String expectedStringTotalGross = tc.getGrandTotal()
.subtract(Objects.requireNonNullElse(zpp.getTotalPrepaidAmount(), BigDecimal.ZERO)).toPlainString();
EStandard whichType;
try {
whichType = getStandard();

View File

@@ -123,6 +123,23 @@ public class UBLTest extends ResourceCase {
}
public void testEdgeInvoiceImportUBL2() {
File UBLinputFile = getResourceAsFile("ubl/04.01a-INVOICE_ubl.xml");
boolean hasExceptions = false;
ZUGFeRDInvoiceImporter zii = null;
Invoice invoice = null;
try {
zii = new ZUGFeRDInvoiceImporter(new FileInputStream(UBLinputFile));
invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException | FileNotFoundException e) {
e.printStackTrace();
hasExceptions = true;
}
assertFalse(hasExceptions);
assertEquals(new BigDecimal("10000.0"), invoice.getTotalPrepaidAmount());
}
/* public void testInvoiceImportOtherUBL() {

View File

@@ -95,6 +95,7 @@ public class XRTest extends TestCase {
.setReferenceNumber("991-01484-64")//leitweg-id
// not using any VAT, this is also a test of zero-rated goods:
.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)))
.setPayee( new TradeParty().setName("VR Factoring GmbH").setID("DE813838785").setLegalOrganisation(new LegalOrganisation("0199", "391200LDDFJDMIPPMZ54")))
.embedFileInXML(fe1);
@@ -109,6 +110,9 @@ public class XRTest extends TestCase {
.asInt()
.isEqualTo(1); //2 errors are OK because there is a known bug
assertThat(theXML).valueByXPath("count(//*[local-name()='PayeeTradeParty'])")
.asInt()
.isEqualTo(1);
assertThat(theXML).valueByXPath("//*[local-name()='DuePayableAmount']")
.asDouble()

View File

@@ -139,6 +139,9 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
assertEquals("DE", invoice.getSender().getCountry());
assertEquals("Stadthausen", invoice.getSender().getLocation());
assertTrue(invoice.getPayee() != null);
assertEquals("VR Factoring GmbH", invoice.getPayee().getName());
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("571.04"), tc.getGrandTotal());
@@ -285,6 +288,8 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase {
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("1.00"), tc.getGrandTotal());
assertTrue(invoice.getPayee() != null);
assertEquals("VR Factoring GmbH", invoice.getPayee().getName());
}
/**

View File

@@ -66,6 +66,11 @@
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PayeeParty>
<cac:PartyName>
<cbc:Name>VR Factoring GmbH</cbc:Name>
</cac:PartyName>
</cac:PayeeParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2017-05-07</cbc:ActualDeliveryDate>
</cac:Delivery>

View File

@@ -0,0 +1,388 @@
<ubl:Invoice xmlns:ubl="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2</cbc:CustomizationID>
<cbc:ID>12345</cbc:ID>
<cbc:IssueDate>2019-05-15</cbc:IssueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>12345678-12345-83</cbc:BuyerReference>
<cac:InvoicePeriod>
<cbc:StartDate>2019-02-01</cbc:StartDate>
<cbc:EndDate>2019-05-07</cbc:EndDate>
</cac:InvoicePeriod>
<cac:OrderReference>
<cbc:ID>123</cbc:ID>
</cac:OrderReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cac:PartyName>
<cbc:Name>M. Meier Handwerk GbR</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>Hauptstraße 2</cbc:StreetName>
<cbc:CityName>Musterstadt</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>DE/12/345/67890</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>M. Meier Handwerk GbR</cbc:RegistrationName>
<cbc:CompanyID>1122334455</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:Name>M. Meier Handwerk GbR</cbc:Name>
<cbc:Telephone>010/12345</cbc:Telephone>
<cbc:ElectronicMail>info@m-meier.de</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cac:PartyIdentification>
<cbc:ID>345LA5324</cbc:ID>
</cac:PartyIdentification>
<cac:PostalAddress>
<cbc:StreetName>Dorfplatz 3</cbc:StreetName>
<cbc:CityName>Musterort</cbc:CityName>
<cbc:PostalZone>54321</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyLegalEntity>
<cbc:RegistrationName>Beispielkunde</cbc:RegistrationName>
</cac:PartyLegalEntity>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:PaymentMeans>
<cbc:PaymentMeansCode>31</cbc:PaymentMeansCode>
<cac:PayeeFinancialAccount>
<cbc:ID>DE091111222233334444</cbc:ID>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:PaymentTerms>
<cbc:Note>Zahlbar innerhalb 14 Tagen nach Erhalt der Rechnung.</cbc:Note>
</cac:PaymentTerms>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="EUR">2382</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="EUR">12536.84</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="EUR">2382</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">12536.84</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">12536.84</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="EUR">14918.84</cbc:TaxInclusiveAmount>
<cbc:PrepaidAmount currencyID="EUR">10000.0</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="EUR">4918.84</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">818.04</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Sanitär und Zubehör</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">818.04</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
<cac:SubInvoiceLine>
<cbc:ID>1 1</cbc:ID>
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">335.79</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Demontage Sanitär</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">335.79</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
<cac:SubInvoiceLine>
<cbc:ID>1 1 1</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTR">149</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>193.70</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Demontage TW-Rohrleitung DN 12-25</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">1.30</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>1 1 2</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTR">32.50</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>48.75</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Demontage SML DN 100</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">1.50</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>1 1 3</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTR">71.80</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>93.34</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Demontage AW-Rohrleitungen Kunststoff PP bis DN100</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">1.30</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>1 2</cbc:ID>
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">482.25</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Abwasserleitungen und Zubehör</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">482.25</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
<cac:SubInvoiceLine>
<cbc:ID>1 2 1</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTR">9.5</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>99.75</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Abwasserleitung HT-PP DN 100</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10.50</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>1 2 2</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTR">45.0</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>382.50</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Abwasserleitung HT-PP DN 50</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">8.50</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
</cac:SubInvoiceLine>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">11718.8</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Heizung und Zubehör</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">11718.8</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
<cac:SubInvoiceLine>
<cbc:ID>2 1</cbc:ID>
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">1324</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Demontage Heizung</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">1324</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
<cac:SubInvoiceLine>
<cbc:ID>2 1 1</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">20</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">700</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Entleeren der Heizungsanlage, teilnetz</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">35</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>2 1 2</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">52</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">624</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Demontage Flachheizkörpers</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">12</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>2 2</cbc:ID>
<cbc:InvoicedQuantity unitCode="XPP">1</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>10394.8</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Heizflächen und Zubehör</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">10394.8</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
<cac:SubInvoiceLine>
<cbc:ID>2 2 1</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">52</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>10202.4</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Flachheizkörper Stahl profiliert Seitent. H 300mm L -500mm Typ22</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">196.20</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="C62">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
<cac:SubInvoiceLine>
<cbc:ID>2 2 2</cbc:ID>
<cbc:InvoicedQuantity unitCode="C62">104</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR"
>192.4</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Einzelrosette aus Kunststoff, weiß</cbc:Name>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">1.85</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTR">1</cbc:BaseQuantity>
</cac:Price>
</cac:SubInvoiceLine>
</cac:SubInvoiceLine>
</cac:InvoiceLine>
</ubl:Invoice>