Skip to content

Commit 5563d62

Browse files
authored
Merge pull request #52 from ebics-java/btd-download
feat(h005): support BTD download orders with service params and date range
2 parents fc09f77 + d1a02df commit 5563d62

9 files changed

Lines changed: 785 additions & 24 deletions

src/main/java/org/kopi/ebics/client/EbicsClient.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.kopi.ebics.session.OrderType;
5959
import org.kopi.ebics.session.Product;
6060
import org.kopi.ebics.utils.Constants;
61+
import org.kopi.ebics.xml.EbicsXmlFactory;
6162
import org.slf4j.Logger;
6263
import org.slf4j.LoggerFactory;
6364

@@ -413,6 +414,17 @@ public void sendFile(File file, EbicsOrderType orderType) throws Exception {
413414

414415
public void fetchFile(File file, User user, Product product, EbicsOrderType orderType,
415416
boolean isTest) throws IOException, EbicsException {
417+
fetchFile(file, user, product, orderType, null, isTest);
418+
}
419+
420+
/**
421+
* Downloads a file from the bank.
422+
*
423+
* @param downloadParams optional EBICS 3.0 service parameters and report period; with a
424+
* service name set the order is sent as a BTD business transaction format order
425+
*/
426+
public void fetchFile(File file, User user, Product product, EbicsOrderType orderType,
427+
EbicsDownloadParams downloadParams, boolean isTest) throws IOException, EbicsException {
416428
FileTransfer transferManager;
417429
EbicsSession session = createSession(user, product);
418430
session.addSessionParam("FORMAT", "pain.xxx.cfonb160.dct");
@@ -425,7 +437,7 @@ public void fetchFile(File file, User user, Product product, EbicsOrderType orde
425437
configuration.getTransferTraceDirectory(user));
426438

427439
try {
428-
transferManager.fetchFile(orderType, file);
440+
transferManager.fetchFile(orderType, downloadParams, file);
429441
} catch (NoDownloadDataAvailableException e) {
430442
// don't log this exception as an error, caller can decide how to handle
431443
throw e;
@@ -435,9 +447,22 @@ public void fetchFile(File file, User user, Product product, EbicsOrderType orde
435447
}
436448
}
437449

450+
/**
451+
* Downloads a file for a report period.
452+
*
453+
* <p><b>A {@link Date} is an instant, the EBICS report period is a pair of calendar days.</b>
454+
* The calendar day is therefore read in the timezone of the machine running this code, so a
455+
* {@code Date} at UTC midnight becomes the previous day in any zone west of UTC. Prefer
456+
* {@link #fetchFile(File, User, Product, EbicsOrderType, EbicsDownloadParams, boolean)} with
457+
* {@link java.time.LocalDate} values, which has no timezone in it.
458+
*/
438459
public void fetchFile(File file, EbicsOrderType orderType, Date start, Date end) throws IOException,
439460
EbicsException {
440-
fetchFile(file, defaultUser, defaultProduct, orderType, false);
461+
fetchFile(file, defaultUser, defaultProduct, orderType,
462+
EbicsDownloadParams.dateRangeOnly(
463+
start == null ? null : EbicsXmlFactory.toLocalDate(start),
464+
end == null ? null : EbicsXmlFactory.toLocalDate(end)),
465+
false);
441466
}
442467

443468
/**
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.kopi.ebics.client;
2+
3+
import java.time.LocalDate;
4+
5+
/**
6+
* Service parameters for an EBICS 3.0 (H005) BTD download order.
7+
*
8+
* <p>With a {@code serviceName} set, the request is sent as {@code AdminOrderType=BTD} with a
9+
* {@code BTDOrderParams/Service} block. With {@code serviceName} left {@code null}, only the
10+
* optional date range is applied and the legacy EBICS 2.x order type is kept, so existing
11+
* callers keep their behaviour.
12+
*
13+
* <p>The report period is a pair of calendar days ({@link LocalDate}), not instants: EBICS sends
14+
* it as {@code xs:date}, and a timezone in that position only creates off-by-one-day bugs.
15+
*
16+
* <p>The constructor rejects a partial or reversed range. Both would otherwise travel silently:
17+
* a half range is dropped when the request is built, and a reversed one is schema-valid and comes
18+
* back as "no data available", which is indistinguishable from a period that really was empty.
19+
* This is the single place every caller passes through, so the check lives here rather than in
20+
* each caller.
21+
*/
22+
public record EbicsDownloadParams(
23+
String serviceName,
24+
String scope,
25+
String option,
26+
String messageName,
27+
String messageVersion,
28+
String containerType,
29+
LocalDate startDate,
30+
LocalDate endDate) {
31+
32+
public EbicsDownloadParams {
33+
if ((startDate == null) != (endDate == null)) {
34+
throw new IllegalArgumentException(
35+
"startDate and endDate must be given together (--start/--end); a single one"
36+
+ " would be dropped from the bank request");
37+
}
38+
if (startDate != null && endDate.isBefore(startDate)) {
39+
throw new IllegalArgumentException(
40+
"endDate must not be before startDate, got " + startDate + " to " + endDate);
41+
}
42+
}
43+
44+
/** Date-range-only parameters for the legacy (non-BTD) download path. */
45+
public static EbicsDownloadParams dateRangeOnly(LocalDate startDate, LocalDate endDate) {
46+
if (startDate == null && endDate == null) {
47+
return null;
48+
}
49+
return new EbicsDownloadParams(null, null, null, null, null, null, startDate, endDate);
50+
}
51+
52+
/** Whether these parameters describe an EBICS 3.0 BTD business transaction format order. */
53+
public boolean isBtd() {
54+
return serviceName != null;
55+
}
56+
}

src/main/java/org/kopi/ebics/client/FileTransfer.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,27 @@ public void sendFile(ContentFactory factory,
173173
public void fetchFile(EbicsOrderType orderType,
174174
File outputFile)
175175
throws IOException, EbicsException
176+
{
177+
fetchFile(orderType, null, outputFile);
178+
}
179+
180+
/**
181+
* Fetches a file of the given order type from the bank.
182+
* This type of transfer will run until everything is processed.
183+
* No transaction recovery is possible.
184+
* @param orderType type of file to fetch
185+
* @param downloadParams optional EBICS 3.0 service parameters and report period
186+
* @param outputFile where to put the data
187+
* @throws IOException communication error
188+
* @throws EbicsException server generated error
189+
*/
190+
public void fetchFile(EbicsOrderType orderType,
191+
EbicsDownloadParams downloadParams,
192+
File outputFile)
193+
throws IOException, EbicsException
176194
{
177195
var sender = new HttpRequestSender(session);
178-
var initializer = new DownloadInitializationRequestElement(session, orderType);
196+
var initializer = new DownloadInitializationRequestElement(session, orderType, downloadParams);
179197
initializer.build();
180198
initializer.validate();
181199

0 commit comments

Comments
 (0)