Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Add Gallop to your project via [Maven Central](https://central.sonatype.com/arti

```groovy
dependencies {
implementation 'de.codebarista:gallop:2.0.0'
implementation 'de.codebarista:gallop:2.1.0'
}
```

Expand All @@ -53,7 +53,7 @@ dependencies {
<dependency>
<groupId>de.codebarista</groupId>
<artifactId>gallop</artifactId>
<version>2.0.0</version>
<version>2.1.0</version>
</dependency>
```

Expand Down Expand Up @@ -153,7 +153,8 @@ public class InvoiceGenerator {
.taxBasisTotalAmount(new BigDecimal("529.48")) // Tax basis total
.taxTotalAmount(new BigDecimal("100.60")) // Total VAT amount
.grandTotalAmount(new BigDecimal("630.08")) // Invoice total with VAT
.duePayableAmount(new BigDecimal("630.08")) // Amount due for payment
.paidAmount(new BigDecimal("100.00")) // Already paid amount
.duePayableAmount(new BigDecimal("530.08")) // Amount due for payment

// Sales order reference
.salesOrderReference("SO-98765");
Expand All @@ -167,6 +168,11 @@ public class InvoiceGenerator {

### Changelog

- 2.1.0: Add BT-30/BT-47 (Seller/Buyer legal registration identifier),
BT-32 (Seller tax registration identifier),
BT-33 (Seller additional legal information),
BT-113 (Paid amount)
and `NetAmount#getVatCategory`
- 2.0.0: Gallop no longer relies on lombok, introduce fluent api
- 1.0.1: Add action to publish to maven central
- 1.0.0: Initial version
14 changes: 12 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ plugins {
}

group = 'de.codebarista'
version = '2.0.0'
version = '2.1.0'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

repositories {
mavenCentral()
Expand Down Expand Up @@ -59,7 +65,11 @@ mavenPublishing {
}

publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
signAllPublications()

// Only sign if publishing to Maven Central (not for local)
if (project.hasProperty("signingInMemoryKeyId") || project.hasProperty("signing.keyId")) {
signAllPublications()
}
}

tasks.register('printVersion') {
Expand Down
38 changes: 35 additions & 3 deletions src/main/java/de/codebarista/gallop/xrechnung/XRechnungWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,19 +220,41 @@ private Element createTradeHeader(XmlDocumentBuilder builder) {
Element seller = builder.createElement(NS_RAM, "SellerTradeParty");
tradeHeader.appendChild(seller);
seller.appendChild(createName(builder, sellerInfo.getName()));
if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getSellerAdditionalLegalInfo())) {
seller.appendChild(createDescription(builder, sellerInfo.getSellerAdditionalLegalInfo()));
}
if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getLegalRegistrationIdentifier())) {
Element specifiedLegalOrganization = builder.createElement(NS_RAM, "SpecifiedLegalOrganization");
specifiedLegalOrganization.appendChild(
createID(builder,
sellerInfo.getLegalRegistrationIdentifier(),
sellerInfo.getLegalRegistrationIdentifierScheme()));
seller.appendChild(specifiedLegalOrganization);
}
seller.appendChild(createTradeContact(builder, sellerInfo.getContact()));
seller.appendChild(createAddress(builder, sellerInfo.getAddress()));
seller.appendChild(createElectronicAddressEmailElement(builder, sellerInfo.getElectronicAddress()));
if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getVatId())) {
seller.appendChild(createTaxRegistration(builder, "VA", sellerInfo.getVatId()));
}
if (XRechnungUtils.isNotNullOrBlank(sellerInfo.getSellerTaxRegistrationIdentifier())) {
seller.appendChild(createTaxRegistration(builder, "FC", sellerInfo.getSellerTaxRegistrationIdentifier()));
}
}

SellerOrBuyer buyerInfo = invoice.getBuyer();
if (buyerInfo != null) {
Element buyer = builder.createElement(NS_RAM, "BuyerTradeParty");
tradeHeader.appendChild(buyer);
buyer.appendChild(createName(builder, buyerInfo.getName()));
if (XRechnungUtils.isNotNullOrBlank(buyerInfo.getLegalRegistrationIdentifier())) {
Element specifiedLegalOrganization = builder.createElement(NS_RAM, "SpecifiedLegalOrganization");
specifiedLegalOrganization.appendChild(
createID(builder,
buyerInfo.getLegalRegistrationIdentifier(),
buyerInfo.getLegalRegistrationIdentifierScheme()));
buyer.appendChild(specifiedLegalOrganization);
}
buyer.appendChild(createAddress(builder, buyerInfo.getAddress()));
buyer.appendChild(createElectronicAddressEmailElement(builder, buyerInfo.getElectronicAddress()));
if (XRechnungUtils.isNotNullOrBlank(buyerInfo.getVatId())) {
Expand Down Expand Up @@ -343,6 +365,11 @@ private Element createTradeSettlement(XmlDocumentBuilder builder) {
grandTotal.setTextContent(invoice.getGrandTotalAmount().toString());
}
sum.appendChild(grandTotal);
if (invoice.getPaidAmount() != null) {
Element totalPrepaid = builder.createElement(NS_RAM, "TotalPrepaidAmount"); // BT-113
totalPrepaid.setTextContent(invoice.getPaidAmount().toString());
sum.appendChild(totalPrepaid);
}
Element duePayable = builder.createElement(NS_RAM, "DuePayableAmount");
if (invoice.getDuePayableAmount() != null) {
duePayable.setTextContent(invoice.getDuePayableAmount().toString());
Expand Down Expand Up @@ -472,8 +499,15 @@ private Element createCharge(XmlDocumentBuilder builder, Charge charge) {
}

private static Element createID(XmlDocumentBuilder builder, String id) {
return createID(builder, id, null);
}

private static Element createID(XmlDocumentBuilder builder, String id, String schemeID) {
Element element = builder.createElement(NS_RAM, "ID");
element.setTextContent(id);
if (XRechnungUtils.isNotNullOrBlank(schemeID)) {
element.setAttribute("schemeID", schemeID);
}
return element;
}

Expand Down Expand Up @@ -506,9 +540,7 @@ private static Element createDateTimeString(XmlDocumentBuilder builder, OffsetDa

private static Element createTaxRegistration(XmlDocumentBuilder builder, String scheme, String id) {
Element element = builder.createElement(NS_RAM, "SpecifiedTaxRegistration");
Element idElement = createID(builder, id);
idElement.setAttribute("schemeID", scheme);
element.appendChild(idElement);
element.appendChild(createID(builder, id, scheme));
return element;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public BigDecimal getNetAmount() {
/**
* Gets the {@link #vatCategory}.
*/
@Override
public TaxCategory getVatCategory() {
return vatCategory;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public BigDecimal getNetAmount() {
return netAmount;
}

@Override
public TaxCategory getVatCategory() {
return vatCategory;
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/de/codebarista/gallop/xrechnung/model/Invoice.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ public class Invoice {
*/
private BigDecimal grandTotalAmount;

/**
* Sum of the amount that has already been paid (BT-113)
*/
private BigDecimal paidAmount;

/**
* Amount due for payment (BT-115)
*/
Expand Down Expand Up @@ -333,6 +338,14 @@ public Invoice grandTotalAmount(BigDecimal grandTotalAmount) {
return this;
}

/**
* Sets the {@link #paidAmount}
*/
public Invoice paidAmount(BigDecimal paidAmount) {
this.paidAmount = paidAmount;
return this;
}

/**
* Sets the {@link #duePayableAmount}
*/
Expand Down Expand Up @@ -544,6 +557,13 @@ public BigDecimal getGrandTotalAmount() {
return grandTotalAmount;
}

/**
* Gets the {@link #paidAmount}
*/
public BigDecimal getPaidAmount() {
return paidAmount;
}

/**
* Gets the {@link #duePayableAmount}.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/de/codebarista/gallop/xrechnung/model/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ public BigDecimal getVatRate() {
return vat.getRate();
}

@Override
public TaxCategory getVatCategory() {
return vat.getCategory();
}

/**
* Gets the {@link #sellerAssignedId}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ public interface NetAmount<T> {
* @return the vat rate as a {@link BigDecimal}
*/
BigDecimal getVatRate();

/**
* Returns the vat category.
*/
TaxCategory getVatCategory();
}
100 changes: 100 additions & 0 deletions src/main/java/de/codebarista/gallop/xrechnung/model/SellerOrBuyer.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,58 @@ public class SellerOrBuyer {
* The official/legal name under which the seller/buyer can be found.
*/
private String name;

/**
* Seller/Buyer trading name (BT-28/BT-45)
* <p>
* Optional name under which the seller/buyer is known if different from the official/legal name
*/
private String tradingName;

/**
* Seller/Buyer legal registration identifier (BT-30/BT-47)
* <p>
* An identifier issued by an official registration authority that identifies the seller/buyer
* as a legal entity or legal person.
*/
private String legalRegistrationIdentifier;

/**
* Seller/Buyer legal registration identifier scheme for (BT-30/BT-47)
* <p>
* A code from <a href="https://www.xrepository.de/details/urn:xoev-de:kosit:codeliste:icd_5">ISO/IEC 17 6523</a>
* that describes the schema/type of the legal registration identifier.
* <p>
* No schema is set for BT-30 if this is null or empty.
*/
private String legalRegistrationIdentifierScheme;

/**
* Seller/Buyer VAT identifier (BT-31/BT-48)
*/
private String vatId;

/**
* Seller tax registration identifier (BT-32)
* <p>
* A local tax identification of the seller (determined by their address)
* or a reference to their registered tax status.
* (If applicable, the indication "reverse charge" or the VAT exemption of
* the invoice issuer should be entered here.)
* <p>
* Usually the Tax-ID.
* <p>
* Only necessary if VAT identifier (BT-31) is not present.
*/
private String sellerTaxRegistrationIdentifier;

/**
* Seller additional legal information (BT-33)
* <p>
* Additional legal information that is relevant for the seller (such as share capital).
*/
private String sellerAdditionalLegalInfo;

/**
* Seller/Buyer electronic address (BT-34/BT-49)
*/
Expand Down Expand Up @@ -89,6 +129,38 @@ public SellerOrBuyer vatId(String vatId) {
return this;
}

/**
* Sets the {@link #sellerTaxRegistrationIdentifier}.
*/
public SellerOrBuyer sellerTaxRegistrationIdentifier(String taxId) {
this.sellerTaxRegistrationIdentifier = taxId;
return this;
}

/**
* Sets the {@link #legalRegistrationIdentifier}.
*/
public SellerOrBuyer legalRegistrationIdentifier(String legalRegistrationIdentifier) {
this.legalRegistrationIdentifier = legalRegistrationIdentifier;
return this;
}

/**
* Sets the {@link #legalRegistrationIdentifierScheme}.
*/
public SellerOrBuyer legalRegistrationIdentifierScheme(String legalRegistrationIdentifierScheme) {
this.legalRegistrationIdentifierScheme = legalRegistrationIdentifierScheme;
return this;
}

/**
* Sets the {@link #sellerAdditionalLegalInfo}.
*/
public SellerOrBuyer sellerAdditionalLegalInfo(String info) {
this.sellerAdditionalLegalInfo = info;
return this;
}

/**
* Sets the {@link #electronicAddress}.
*/
Expand Down Expand Up @@ -142,6 +214,34 @@ public String getVatId() {
return vatId;
}

/**
* Gets the {@link #sellerTaxRegistrationIdentifier}
*/
public String getSellerTaxRegistrationIdentifier() {
return sellerTaxRegistrationIdentifier;
}

/**
* Gets the {@link #legalRegistrationIdentifier}
*/
public String getLegalRegistrationIdentifier() {
return legalRegistrationIdentifier;
}

/**
* Gets the {@link #legalRegistrationIdentifierScheme}
*/
public String getLegalRegistrationIdentifierScheme() {
return legalRegistrationIdentifierScheme;
}

/**
* Gets the {@link #sellerAdditionalLegalInfo}
*/
public String getSellerAdditionalLegalInfo() {
return sellerAdditionalLegalInfo;
}

/**
* Gets the {@link #electronicAddress}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ public void buildInvoice() {
.taxBasisTotalAmount(new BigDecimal("529.48")) // Tax basis total
.taxTotalAmount(new BigDecimal("100.60")) // Total VAT amount
.grandTotalAmount(new BigDecimal("630.08")) // Invoice total with VAT
.duePayableAmount(new BigDecimal("630.08")) // Amount due for payment
.paidAmount(new BigDecimal("100.00")) // Already paid amount
.duePayableAmount(new BigDecimal("530.08")) // Amount due for payment

// Sales order reference
.salesOrderReference("SO-98765");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ public class XRechnungWriterScenariosTest {
"order_with_paypal_direct_debit",
"order_with_paypal_invoice",
"order_with_shipping_costs_with_multiple_taxes",
"order_with_tax_free_product"
"order_with_tax_free_product",
"order_with_already_paid_amount",
"order_without_vatid",
"order_with_legal_registration_identifiers"
})
public void writeXRechnung(String testFile) throws ParserConfigurationException, TransformerException {
TestHelper testHelper = new TestHelper("invoice");
Expand Down
Loading