Skip to content

Commit b242a1f

Browse files
authored
Introduce fluent api (#3)
* introduce fluent API * remove lombok dependency * bump version to 2.0.0
1 parent 52e05d8 commit b242a1f

24 files changed

+1827
-368
lines changed

README.md

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Add Gallop to your project via [Maven Central](https://central.sonatype.com/arti
4040

4141
```groovy
4242
dependencies {
43-
implementation 'de.codebarista:gallop:1.0.1'
43+
implementation 'de.codebarista:gallop:2.0.0'
4444
}
4545
```
4646

@@ -51,120 +51,99 @@ dependencies {
5151
<dependency>
5252
<groupId>de.codebarista</groupId>
5353
<artifactId>gallop</artifactId>
54-
<version>1.0.1</version>
54+
<version>2.0.0</version>
5555
</dependency>
5656
```
5757

5858
### Code example
5959

60-
```java
61-
import de.codebarista.gallop.xrechnung.model.Invoice;
62-
import de.codebarista.gallop.xrechnung.model.Item;
63-
import de.codebarista.gallop.xrechnung.model.InvoiceNote;
64-
import de.codebarista.gallop.XmlDocumentBuilder;
65-
66-
import java.math.BigDecimal;
67-
import java.time.OffsetDateTime;
68-
import java.util.List;
60+
You find this code in the `BuildInvoiceTest` class.
6961

62+
```java
7063
public class InvoiceGenerator {
7164

72-
public byte[] generateInvoice() throws Exception {
73-
Invoice invoice = Invoice.builder()
65+
public String generateInvoice() throws XRechnungWriterException {
66+
Invoice invoice = Invoice.create()
7467
.documentTypeCode(InvoiceType.COMMERCIAL_INVOICE.getValue()) // Define invoice type
7568
.documentId("INV-2025-1001") // Unique invoice identifier
7669
.leitwegId("N/A") // Buyer reference (BT-10)
7770
.currency("EUR") // Currency used for the invoice
7871

7972
// Payment details including method and terms
80-
.paymentInstructions(PaymentInstructions.builder()
73+
.paymentInstructions(PaymentInstructions.create()
8174
.meansType(PaymentCode.CASH)
8275
.meansText("Cash on delivery")
8376
.paymentTerms("The goods remain our property until full payment is received."
84-
+ "\nDate of service corresponds to invoice date.")
85-
.build())
77+
+ "\nDate of service corresponds to invoice date."))
8678

8779
.issueDate(OffsetDateTime.now()) // Invoice issue date
8880

8981
// Seller details
90-
.seller(SellerOrBuyer.builder()
82+
.seller(SellerOrBuyer.create()
9183
.name("TechNova Solutions GmbH")
92-
.address(PostalAddress.builder()
84+
.address(PostalAddress.create()
9385
.addressLineOne("Innovationsstraße 15")
9486
.city("Berlin")
9587
.zipCode("10115")
96-
.countryIsoCode("DE")
97-
.build())
88+
.countryIsoCode("DE"))
9889
.vatId("DE298765432") // Seller VAT ID
9990
.electronicAddress("[email protected]") // Electronic address for invoicing
100-
.contact(Contact.builder()
91+
.contact(Contact.create()
10192
.name("Dr. Stefan Wagner")
10293
.phone("+49 (0) 30 987654321")
103-
104-
.build())
105-
.build())
94+
.email("[email protected]")))
10695

10796
// Buyer details
108-
.buyer(SellerOrBuyer.builder()
97+
.buyer(SellerOrBuyer.create()
10998
.name("Greenline Retail AG")
110-
.address(PostalAddress.builder()
99+
.address(PostalAddress.create()
111100
.addressLineOne("Einkaufsstraße 78")
112101
.city("Hamburg")
113102
.zipCode("20095")
114-
.countryIsoCode("DE")
115-
.build())
116-
.electronicAddress("[email protected]") // Electronic address for buyer
117-
.build())
103+
.countryIsoCode("DE"))
104+
.electronicAddress("[email protected]")) // Electronic address for buyer
118105

119106
// Delivery information
120-
.deliveryInfo(DeliveryInformation.builder()
107+
.deliveryInfo(DeliveryInformation.create()
121108
.name("Greenline Retail AG - Warehouse")
122-
.deliveryAddress(PostalAddress.builder()
109+
.deliveryAddress(PostalAddress.create()
123110
.addressLineOne("Lagerstraße 5")
124111
.city("Hamburg")
125112
.zipCode("21079")
126-
.countryIsoCode("DE")
127-
.build())
128-
.build())
113+
.countryIsoCode("DE")))
129114

130115
// Invoice items
131116
.items(List.of(
132-
Item.builder()
117+
Item.create()
133118
.id(1L)
134119
.name("Ergonomic Office Chair")
135120
.sellerAssignedId("CHAIR-ERG-2025") // Seller's internal product ID
136121
.quantity(2L) // Quantity purchased
137122
.unitPrice(new BigDecimal("199.99")) // Price per unit
138123
.itemTotalNetAmount(new BigDecimal("399.98")) // Total price without VAT
139124
.unitCode(UnitCode.PIECE) // Unit of measurement
140-
.vat(Vat.builder()
125+
.vat(Vat.create()
141126
.rate(BigDecimal.valueOf(19)) // VAT rate (19%)
142-
.category(TaxCategory.STANDARD_RATE)
143-
.build())
144-
.build(),
145-
Item.builder()
127+
.category(TaxCategory.STANDARD_RATE)),
128+
Item.create()
146129
.id(2L)
147130
.name("Wireless Mechanical Keyboard")
148131
.sellerAssignedId("KEY-MECH-WL")
149132
.quantity(1L)
150133
.unitPrice(new BigDecimal("129.50"))
151134
.itemTotalNetAmount(new BigDecimal("129.50"))
152135
.unitCode(UnitCode.PIECE)
153-
.vat(Vat.builder()
136+
.vat(Vat.create()
154137
.rate(BigDecimal.valueOf(19))
155-
.category(TaxCategory.STANDARD_RATE)
156-
.build())
157-
.build()
158-
))
138+
.category(TaxCategory.STANDARD_RATE))))
159139

160140
// VAT breakdown
161141
.vatTotals(List.of(
162-
Vat.builder()
142+
Vat.create()
163143
.rate(BigDecimal.valueOf(19))
164144
.category(TaxCategory.STANDARD_RATE)
165145
.taxableAmount(BigDecimal.valueOf(529.48)) // Taxable amount
166146
.taxAmount(BigDecimal.valueOf(100.60)) // VAT amount
167-
.build()
168147
))
169148

170149
// Invoice totals
@@ -175,13 +154,17 @@ public class InvoiceGenerator {
175154
.duePayableAmount(new BigDecimal("630.08")) // Amount due for payment
176155

177156
// Sales order reference
178-
.salesOrderReference("SO-98765")
179-
180-
.build();
157+
.salesOrderReference("SO-98765");
181158

159+
// Generate the XRechnung XML from the invoice
182160
byte[] xRechnungXML = XRechnungWriter.generateXRechnungXML(invoice);
161+
return new String(xRechnungXML);
183162
}
184163
}
185164
```
186165

187-
You also find this code in the `BuildInvoiceTest` class.
166+
### Changelog
167+
168+
- 2.0.0: Gallop no longer relies on lombok, introduce fluent api
169+
- 1.0.1: Add action to publish to maven central
170+
- 1.0.0: Initial version

build.gradle

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,13 @@ plugins {
77
}
88

99
group = 'de.codebarista'
10-
version = '1.0.1'
10+
version = '2.0.0'
1111

1212
repositories {
1313
mavenCentral()
1414
}
1515

1616
dependencies {
17-
compileOnly 'org.projectlombok:lombok:1.18.36'
18-
annotationProcessor 'org.projectlombok:lombok:1.18.36'
19-
2017
testImplementation platform('org.junit:junit-bom:5.10.0')
2118
testImplementation 'org.junit.jupiter:junit-jupiter'
2219
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'

src/main/java/de/codebarista/gallop/xrechnung/XRechnungWriter.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import de.codebarista.gallop.xrechnung.model.PrecedingInvoiceReference;
1616
import de.codebarista.gallop.xrechnung.model.SellerOrBuyer;
1717
import de.codebarista.gallop.xrechnung.model.Vat;
18-
import lombok.NonNull;
1918
import org.w3c.dom.Element;
2019

2120
import javax.xml.parsers.ParserConfigurationException;
@@ -29,6 +28,7 @@
2928
import java.time.OffsetDateTime;
3029
import java.time.format.DateTimeFormatter;
3130
import java.util.List;
31+
import java.util.Objects;
3232

3333
/**
3434
* Writes a XRechnung XML with the data of an {@linkplain Invoice} object
@@ -55,18 +55,20 @@ public class XRechnungWriter {
5555
*
5656
* @param invoice the invoice to be written, must not be {@code null}
5757
*/
58-
public XRechnungWriter(@NonNull Invoice invoice) {
58+
public XRechnungWriter(Invoice invoice) {
59+
Objects.requireNonNull(invoice, "Invoice must not be null");
5960
this.invoice = invoice;
6061
}
6162

6263
/**
6364
* Convert an invoice to a XRechnung XML
6465
*
65-
* @param invoice the Invoice object to serialize to XML
66+
* @param invoice the Invoice object to serialize to XML, must not be {@code null}
6667
* @return binary XRechnung XML document
6768
* @throws XRechnungWriterException if the creation of the XRechnung failed
6869
*/
69-
public static byte[] generateXRechnungXML(@NonNull Invoice invoice) {
70+
public static byte[] generateXRechnungXML(Invoice invoice) {
71+
Objects.requireNonNull(invoice, "Invoice must not be null");
7072
var xmlWriter = new XRechnungWriter(invoice);
7173
try {
7274
return xmlWriter.getXML();
@@ -315,17 +317,13 @@ private Element createTradeSettlement(XmlDocumentBuilder builder) {
315317

316318
if (invoice.getChargeTotalAmount() != null) {
317319
Element chargeTotal = builder.createElement(NS_RAM, "ChargeTotalAmount"); // BT-108
318-
if (invoice.getChargeTotalAmount() != null) {
319-
chargeTotal.setTextContent(invoice.getChargeTotalAmount().toString());
320-
}
320+
chargeTotal.setTextContent(invoice.getChargeTotalAmount().toString());
321321
sum.appendChild(chargeTotal);
322322
}
323323

324324
if (invoice.getAllowanceTotalAmount() != null) {
325325
Element allowanceTotal = builder.createElement(NS_RAM, "AllowanceTotalAmount");
326-
if (invoice.getAllowanceTotalAmount() != null) {
327-
allowanceTotal.setTextContent(invoice.getAllowanceTotalAmount().toString());
328-
}
326+
allowanceTotal.setTextContent(invoice.getAllowanceTotalAmount().toString());
329327
sum.appendChild(allowanceTotal);
330328
}
331329

@@ -368,7 +366,7 @@ private Element createPrecedingInvoiceReference(XmlDocumentBuilder builder, Prec
368366
element.appendChild(issuerAssignedId);
369367
if (reference.getPrecedingInvoiceIssueDate() != null) { // BT-26, optional
370368
Element issueDateTime = builder.createElement(NS_RAM, "FormattedIssueDateTime");
371-
issueDateTime.appendChild(createDateTimeString(builder, invoice.getIssueDate(), NS_QDT));
369+
issueDateTime.appendChild(createDateTimeString(builder, reference.getPrecedingInvoiceIssueDate(), NS_QDT));
372370
element.appendChild(issueDateTime);
373371
}
374372
return element;
Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,104 @@
11
package de.codebarista.gallop.xrechnung.model;
22

3-
import lombok.AllArgsConstructor;
4-
import lombok.Builder;
5-
import lombok.Getter;
6-
import lombok.NoArgsConstructor;
7-
import lombok.With;
8-
93
import java.math.BigDecimal;
104

115
/**
126
* Document Level Allowances (BG-20)
137
*/
14-
@Builder
15-
@With
16-
@Getter
17-
@NoArgsConstructor
18-
@AllArgsConstructor
19-
public class Allowance implements NetAmount {
8+
public class Allowance implements NetAmount<Allowance> {
209
/**
2110
* Document level allowance amount (BT-92). The actual amount without taxes.<br>
2211
* <b>Must be 0 or a positive value.</b>
2312
*/
24-
public BigDecimal netAmount;
13+
private BigDecimal netAmount;
2514

2615
/**
2716
* Document level allowance VAT category code (BT-95)
2817
*/
29-
public TaxCategory vatCategory;
18+
private TaxCategory vatCategory;
3019

3120
/**
3221
* Document level allowance VAT rate (BT-96)
3322
*/
34-
public BigDecimal vatRate;
23+
private BigDecimal vatRate;
3524

3625
/**
3726
* Document level allowance reason (BT-97)
3827
*/
39-
public String reason;
28+
private String reason;
29+
30+
/**
31+
* Creates a new, empty instance of this class.
32+
*/
33+
public Allowance() {
34+
}
35+
36+
/**
37+
* Creates a new, empty instance of this class.
38+
*
39+
* @return a new, empty instance
40+
*/
41+
public static Allowance create() {
42+
return new Allowance();
43+
}
44+
45+
/**
46+
* Sets the {@link #netAmount}.
47+
*/
48+
@Override
49+
public Allowance netAmount(BigDecimal netAmount) {
50+
this.netAmount = netAmount;
51+
return this;
52+
}
53+
54+
/**
55+
* Sets the {@link #vatCategory}.
56+
*/
57+
public Allowance vatCategory(TaxCategory vatCategory) {
58+
this.vatCategory = vatCategory;
59+
return this;
60+
}
61+
62+
/**
63+
* Sets the {@link #vatRate}.
64+
*/
65+
public Allowance vatRate(BigDecimal vatRate) {
66+
this.vatRate = vatRate;
67+
return this;
68+
}
69+
70+
/**
71+
* Sets the {@link #reason}.
72+
*/
73+
public Allowance reason(String reason) {
74+
this.reason = reason;
75+
return this;
76+
}
77+
78+
@Override
79+
public BigDecimal getNetAmount() {
80+
return netAmount;
81+
}
82+
83+
/**
84+
* Gets the {@link #vatCategory}.
85+
*/
86+
public TaxCategory getVatCategory() {
87+
return vatCategory;
88+
}
89+
90+
/**
91+
* Gets the {@link #vatRate}.
92+
*/
93+
@Override
94+
public BigDecimal getVatRate() {
95+
return vatRate;
96+
}
97+
98+
/**
99+
* Gets the {@link #reason}.
100+
*/
101+
public String getReason() {
102+
return reason;
103+
}
40104
}

0 commit comments

Comments
 (0)