Skip to content

Commit 6148632

Browse files
authored
Merge pull request #12 from FacturAPI/feat/payment-summary
feat: add invoices.paymentSummary for payment complements
2 parents 3aebcad + a1aa171 commit 6148632

5 files changed

Lines changed: 199 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.1.0] - 2026-09-04
9+
10+
### Added
11+
12+
- Add `invoices.paymentSummary(String id, double amount)` to get the related-document object needed to build a payment complement (complemento de pago): installment number, previous balance, and taxes prorated to the paid amount.
13+
- Add the `PaymentSummary` model.
14+
815
## [2.0.0] - 2026-08-24
916

1017
### Added

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>io.facturapi</groupId>
77
<artifactId>facturapi-java</artifactId>
8-
<version>2.0.0</version>
8+
<version>2.1.0</version>
99
<name>facturapi-java</name>
1010
<description>Official Java SDK for Facturapi</description>
1111
<url>https://github.com/facturapi/facturapi-java</url>
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package io.facturapi.models;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
/**
8+
* Related document summary for a payment complement (complemento de pago).
9+
* Ready to be used as an element of the complement's related documents.
10+
*/
11+
@JsonIgnoreProperties(ignoreUnknown = true)
12+
public class PaymentSummary {
13+
private String uuid;
14+
private Integer folioNumber;
15+
private String series;
16+
private Integer installment;
17+
private Double lastBalance;
18+
private Double total;
19+
private String currency;
20+
private Double amount;
21+
private List<PaymentSummaryTax> taxes = new ArrayList<>();
22+
23+
public String getUuid() {
24+
return uuid;
25+
}
26+
27+
public void setUuid(String uuid) {
28+
this.uuid = uuid;
29+
}
30+
31+
public Integer getFolioNumber() {
32+
return folioNumber;
33+
}
34+
35+
public void setFolioNumber(Integer folioNumber) {
36+
this.folioNumber = folioNumber;
37+
}
38+
39+
public String getSeries() {
40+
return series;
41+
}
42+
43+
public void setSeries(String series) {
44+
this.series = series;
45+
}
46+
47+
public Integer getInstallment() {
48+
return installment;
49+
}
50+
51+
public void setInstallment(Integer installment) {
52+
this.installment = installment;
53+
}
54+
55+
public Double getLastBalance() {
56+
return lastBalance;
57+
}
58+
59+
public void setLastBalance(Double lastBalance) {
60+
this.lastBalance = lastBalance;
61+
}
62+
63+
public Double getTotal() {
64+
return total;
65+
}
66+
67+
public void setTotal(Double total) {
68+
this.total = total;
69+
}
70+
71+
public String getCurrency() {
72+
return currency;
73+
}
74+
75+
public void setCurrency(String currency) {
76+
this.currency = currency;
77+
}
78+
79+
public Double getAmount() {
80+
return amount;
81+
}
82+
83+
public void setAmount(Double amount) {
84+
this.amount = amount;
85+
}
86+
87+
public List<PaymentSummaryTax> getTaxes() {
88+
return taxes;
89+
}
90+
91+
public void setTaxes(List<PaymentSummaryTax> taxes) {
92+
this.taxes = taxes;
93+
}
94+
95+
/** Prorated tax breakdown for the paid amount. */
96+
@JsonIgnoreProperties(ignoreUnknown = true)
97+
public static class PaymentSummaryTax {
98+
private Double base;
99+
private Double rate;
100+
private String type;
101+
private String factor;
102+
private Boolean withholding;
103+
104+
public Double getBase() {
105+
return base;
106+
}
107+
108+
public void setBase(Double base) {
109+
this.base = base;
110+
}
111+
112+
public Double getRate() {
113+
return rate;
114+
}
115+
116+
public void setRate(Double rate) {
117+
this.rate = rate;
118+
}
119+
120+
public String getType() {
121+
return type;
122+
}
123+
124+
public void setType(String type) {
125+
this.type = type;
126+
}
127+
128+
public String getFactor() {
129+
return factor;
130+
}
131+
132+
public void setFactor(String factor) {
133+
this.factor = factor;
134+
}
135+
136+
public Boolean getWithholding() {
137+
return withholding;
138+
}
139+
140+
public void setWithholding(Boolean withholding) {
141+
this.withholding = withholding;
142+
}
143+
}
144+
}

src/main/java/io/facturapi/resources/InvoicesResource.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.facturapi.http.FacturapiHttpClient;
55
import io.facturapi.models.GenericResponse;
66
import io.facturapi.models.Invoice;
7+
import io.facturapi.models.PaymentSummary;
78
import io.facturapi.models.SearchResult;
89
import java.io.InputStream;
910
import java.util.Map;
@@ -52,6 +53,22 @@ public Invoice retrieve(String id) {
5253
return get("/invoices/" + id, null, Invoice.class);
5354
}
5455

56+
/**
57+
* Gets the information needed to add this invoice as a related document in a
58+
* payment complement (complemento de pago): the installment number according
59+
* to the payment history, the previous balance, and the invoice tax breakdown
60+
* prorated to the amount being paid.
61+
*
62+
* @param id Invoice id.
63+
* @param amount Amount being paid, expressed in the invoice currency. Cannot
64+
* exceed the outstanding balance.
65+
* @return Payment summary ready to be used as a related document.
66+
* @see <a href="https://docs.facturapi.io/api#operation/getInvoicePaymentSummary">API reference</a>
67+
*/
68+
public PaymentSummary paymentSummary(String id, double amount) {
69+
return get("/invoices/" + id + "/payment-summary", Map.of("amount", amount), PaymentSummary.class);
70+
}
71+
5572
/**
5673
* Cancels an invoice.
5774
*

src/test/java/io/facturapi/FacturapiResourcesTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,36 @@ void invoiceCreateUsesExpectedPath() {
4646
assertEquals("/v2/invoices?test=true", request.uri().getPath() + "?" + request.uri().getQuery());
4747
}
4848

49+
@Test
50+
void invoicePaymentSummaryUsesExpectedPath() {
51+
StubHttpClient httpClient = new StubHttpClient();
52+
httpClient.enqueueJson(
53+
200,
54+
"{\"uuid\":\"6CF6CE33-1BD2-4F88-A443-33013C069169\",\"installment\":1,"
55+
+ "\"last_balance\":100,\"total\":100,\"currency\":\"MXN\",\"amount\":58,"
56+
+ "\"taxes\":[{\"base\":50,\"rate\":0.16,\"type\":\"IVA\",\"factor\":\"Tasa\",\"withholding\":false}]}"
57+
);
58+
59+
Facturapi sdk = new Facturapi(
60+
FacturapiConfig.builder("sk_test")
61+
.httpClient(httpClient.client())
62+
.build()
63+
);
64+
65+
var response = sdk.invoices().paymentSummary("inv_1", 58.0);
66+
67+
assertEquals("6CF6CE33-1BD2-4F88-A443-33013C069169", response.getUuid());
68+
assertEquals(1, response.getInstallment());
69+
assertEquals(50.0, response.getTaxes().get(0).getBase());
70+
71+
var request = httpClient.requests().get(0);
72+
assertEquals("GET", request.method());
73+
assertEquals(
74+
"/v2/invoices/inv_1/payment-summary?amount=58.0",
75+
request.uri().getPath() + "?" + request.uri().getQuery()
76+
);
77+
}
78+
4979
@Test
5080
void receiptsToInvoiceUsesExpectedPath() {
5181
StubHttpClient httpClient = new StubHttpClient();

0 commit comments

Comments
 (0)