diff --git a/.editorconfig b/.editorconfig index d946a7a..9e08b26 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,5 @@ [*] charset=utf-8 -end_of_line=lf insert_final_newline=true indent_style=space indent_size=4 diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 209c7b1..4300839 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -202,7 +202,6 @@ - @@ -354,7 +353,6 @@ - - - diff --git a/README.md b/README.md index 7deb788..fb787b1 100644 --- a/README.md +++ b/README.md @@ -70,12 +70,12 @@ This library is in early alpha version and not all API methods are implemented y - [x] Get an account - [ ] ~~Get multiple accounts~~ (won't be implemented as deprecated) - [x] Get and search all accounts - - [ ] Get daily balances + - [x] Get daily balances - [x] Edit an account - - [ ] Request SEPA Money Transfer - - [ ] Execute SEPA Money Transfer - - [ ] Request SEPA Direct Debit - - [ ] Execute SEPA Direct Debit + - [x] Request SEPA Money Transfer + - [x] Execute SEPA Money Transfer + - [x] Request SEPA Direct Debit + - [x] Execute SEPA Direct Debit - [x] Delete an account - [x] Delete all accounts - Transactions diff --git a/src/main/java/org/proshin/finapi/account/Account.java b/src/main/java/org/proshin/finapi/account/Account.java index 040e5cb..3727fe3 100644 --- a/src/main/java/org/proshin/finapi/account/Account.java +++ b/src/main/java/org/proshin/finapi/account/Account.java @@ -21,6 +21,8 @@ import org.proshin.finapi.account.in.FpEditParameters; import org.proshin.finapi.account.out.ClearingAccount; import org.proshin.finapi.account.out.Holder; +import org.proshin.finapi.account.out.Order; +import org.proshin.finapi.account.out.Status; import org.proshin.finapi.bankconnection.BankConnection; public interface Account { @@ -65,9 +67,5 @@ public interface Account { void edit(FpEditParameters parameters); - MoneyTransfer moneyTransfer(); - - DirectDebit directDebit(); - void delete(Long id); } diff --git a/src/main/java/org/proshin/finapi/account/Accounts.java b/src/main/java/org/proshin/finapi/account/Accounts.java index 27249e4..1387976 100644 --- a/src/main/java/org/proshin/finapi/account/Accounts.java +++ b/src/main/java/org/proshin/finapi/account/Accounts.java @@ -16,15 +16,21 @@ package org.proshin.finapi.account; import org.proshin.finapi.account.in.DailyBalancesCriteria; +import org.proshin.finapi.account.in.FpQueryCriteria; import org.proshin.finapi.account.out.DailyBalances; +import org.proshin.finapi.account.out.DirectDebit; public interface Accounts { Account one(Long id); - Iterable query(QueryCriteria criteria); + Iterable query(FpQueryCriteria criteria); DailyBalances dailyBalances(DailyBalancesCriteria criteria); + MoneyTransfer moneyTransfer(); + + DirectDebit directDebit(); + void deleteAll(); } diff --git a/src/main/java/org/proshin/finapi/account/FpAccount.java b/src/main/java/org/proshin/finapi/account/FpAccount.java index ade7e04..2f9f9e3 100644 --- a/src/main/java/org/proshin/finapi/account/FpAccount.java +++ b/src/main/java/org/proshin/finapi/account/FpAccount.java @@ -25,6 +25,8 @@ import org.proshin.finapi.account.out.FpClearingAccount; import org.proshin.finapi.account.out.FpHolder; import org.proshin.finapi.account.out.Holder; +import org.proshin.finapi.account.out.Order; +import org.proshin.finapi.account.out.Status; import org.proshin.finapi.bankconnection.BankConnection; import org.proshin.finapi.bankconnection.FpBankConnections; import org.proshin.finapi.endpoint.Endpoint; @@ -41,11 +43,13 @@ public final class FpAccount implements Account { private final Endpoint endpoint; private final AccessToken token; private final JSONObject origin; + private final String url; - public FpAccount(final Endpoint endpoint, final AccessToken token, final JSONObject origin) { + public FpAccount(final Endpoint endpoint, final AccessToken token, final JSONObject origin, final String url) { this.endpoint = endpoint; this.token = token; this.origin = origin; + this.url = url; } @Override @@ -56,7 +60,7 @@ public Long id() { @Override public BankConnection bankConnection() { return new FpBankConnections(this.endpoint, this.token) - .one(this.origin.getLong("bankConnectionId")); + .one(this.origin.getLong("bankConnectionId")); } @Override @@ -152,29 +156,13 @@ public Iterable clearingAccounts() { @Override public void edit(final FpEditParameters parameters) { - this.endpoint.patch(String.format("/api/v1/accounts/%d", this.id()), this.token, parameters, 200); - } - - /** - * @todo #21 Implement money transfer - */ - @Override - public MoneyTransfer moneyTransfer() { - throw new UnsupportedOperationException("This method is not implemented yet"); - } - - /** - * @todo #21 Implement direct debit - */ - @Override - public DirectDebit directDebit() { - throw new UnsupportedOperationException("This method is not implemented yet"); + this.endpoint.patch(this.url + this.id(), this.token, parameters, 200); } @Override public void delete(final Long id) { this.endpoint.delete( - String.format("/api/v1/accounts/%d", this.id()), + this.url + this.id(), this.token ); } diff --git a/src/main/java/org/proshin/finapi/account/FpAccounts.java b/src/main/java/org/proshin/finapi/account/FpAccounts.java index e623d60..b3d1445 100644 --- a/src/main/java/org/proshin/finapi/account/FpAccounts.java +++ b/src/main/java/org/proshin/finapi/account/FpAccounts.java @@ -18,7 +18,11 @@ import org.json.JSONObject; import org.proshin.finapi.accesstoken.AccessToken; import org.proshin.finapi.account.in.DailyBalancesCriteria; +import org.proshin.finapi.account.in.FpQueryCriteria; import org.proshin.finapi.account.out.DailyBalances; +import org.proshin.finapi.account.out.DirectDebit; +import org.proshin.finapi.account.out.FpDailyBalances; +import org.proshin.finapi.account.out.FpDirectDebit; import org.proshin.finapi.endpoint.Endpoint; import org.proshin.finapi.primitives.IterableJsonArray; @@ -29,10 +33,16 @@ public final class FpAccounts implements Accounts { private final Endpoint endpoint; private final AccessToken token; + private final String url; public FpAccounts(final Endpoint endpoint, final AccessToken token) { + this(endpoint, token, "/api/v1/accounts/"); + } + + public FpAccounts(final Endpoint endpoint, final AccessToken token, final String url) { this.endpoint = endpoint; this.token = token; + this.url = url; } @Override @@ -41,17 +51,18 @@ public Account one(final Long id) { this.endpoint, this.token, new JSONObject( - this.endpoint.get(String.format("/api/v1/accounts/%d", id), this.token) - ) + this.endpoint.get(this.url + id, this.token) + ), + this.url ); } @Override - public Iterable query(final QueryCriteria criteria) { + public Iterable query(final FpQueryCriteria criteria) { return new IterableJsonArray<>( new JSONObject( this.endpoint.get( - "/api/v1/accounts", + this.url, this.token, criteria ) @@ -59,21 +70,33 @@ public Iterable query(final QueryCriteria criteria) { (array, index) -> new FpAccount( this.endpoint, this.token, - array.getJSONObject(index) + array.getJSONObject(index), + this.url ) ); } - /** - * @todo #21 Implement daily balances for accounts endpoint - */ @Override public DailyBalances dailyBalances(final DailyBalancesCriteria criteria) { - throw new UnsupportedOperationException("This method is not implemented yet"); + return new FpDailyBalances( + new JSONObject( + this.endpoint.get(this.url + "dailyBalances", this.token, criteria) + ) + ); + } + + @Override + public MoneyTransfer moneyTransfer() { + return new FpMoneyTransfer(this.endpoint, this.token, this.url); + } + + @Override + public DirectDebit directDebit() { + return new FpDirectDebit(this.endpoint, this.token, this.url); } @Override public void deleteAll() { - this.endpoint.delete("/api/v1/accounts", this.token); + this.endpoint.delete(this.url, this.token); } } diff --git a/src/main/java/org/proshin/finapi/account/FpMoneyTransfer.java b/src/main/java/org/proshin/finapi/account/FpMoneyTransfer.java new file mode 100644 index 0000000..35dde02 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/FpMoneyTransfer.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account; + +import org.json.JSONObject; +import org.proshin.finapi.accesstoken.AccessToken; +import org.proshin.finapi.account.in.MoneyTransferParameters; +import org.proshin.finapi.account.out.FpSepaExecutingResponse; +import org.proshin.finapi.account.out.FpSepaRequestingResponse; +import org.proshin.finapi.account.out.SepaExecutingResponse; +import org.proshin.finapi.account.out.SepaRequestingResponse; +import org.proshin.finapi.endpoint.Endpoint; + +public final class FpMoneyTransfer implements MoneyTransfer { + + private final Endpoint endpoint; + private final AccessToken token; + private final String url; + + public FpMoneyTransfer(final Endpoint endpoint, final AccessToken token, final String url) { + this.endpoint = endpoint; + this.token = token; + this.url = url; + } + + @Override + public SepaRequestingResponse request(final MoneyTransferParameters parameters) { + return new FpSepaRequestingResponse( + new JSONObject( + this.endpoint.post( + this.url + "requestSepaMoneyTransfer", + this.token, + parameters + ) + ) + ); + } + + @Override + public SepaExecutingResponse execute(final Long account, final String bankingTan) { + return new FpSepaExecutingResponse( + new JSONObject( + this.endpoint.post( + this.url + "executeSepaMoneyTransfer", + this.token, + () -> new JSONObject() + .put("accountId", account) + .put("bankingTan", bankingTan) + .toString() + ) + ) + ); + } +} diff --git a/src/main/java/org/proshin/finapi/account/MoneyTransfer.java b/src/main/java/org/proshin/finapi/account/MoneyTransfer.java index df7948e..5174b40 100644 --- a/src/main/java/org/proshin/finapi/account/MoneyTransfer.java +++ b/src/main/java/org/proshin/finapi/account/MoneyTransfer.java @@ -15,5 +15,13 @@ */ package org.proshin.finapi.account; +import org.proshin.finapi.account.in.MoneyTransferParameters; +import org.proshin.finapi.account.out.SepaExecutingResponse; +import org.proshin.finapi.account.out.SepaRequestingResponse; + public interface MoneyTransfer { + + SepaRequestingResponse request(final MoneyTransferParameters parameters); + + SepaExecutingResponse execute(Long account, String bankingTan); } diff --git a/src/main/java/org/proshin/finapi/account/QueryCriteria.java b/src/main/java/org/proshin/finapi/account/QueryCriteria.java deleted file mode 100644 index 6abcaeb..0000000 --- a/src/main/java/org/proshin/finapi/account/QueryCriteria.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 Roman Proshin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.proshin.finapi.account; - -import java.math.BigDecimal; -import java.time.OffsetDateTime; -import org.apache.http.NameValuePair; - -public interface QueryCriteria extends Iterable { - - QueryCriteria withIds(Iterable ids); - - QueryCriteria withSearch(String search); - - QueryCriteria withTypes(Type... types); - - QueryCriteria withBankConnections(Iterable ids); - - QueryCriteria withMinLastSuccessfulUpdate(OffsetDateTime minLastSuccessfulUpdate); - - QueryCriteria withMaxLastSuccessfulUpdate(OffsetDateTime maxLastSuccessfulUpdate); - - QueryCriteria withMinBalance(BigDecimal minBalance); - - QueryCriteria withMaxBalance(BigDecimal maxBalance); -} diff --git a/src/main/java/org/proshin/finapi/account/in/DailyBalancesCriteria.java b/src/main/java/org/proshin/finapi/account/in/DailyBalancesCriteria.java index 8acd0f5..b3df0e2 100644 --- a/src/main/java/org/proshin/finapi/account/in/DailyBalancesCriteria.java +++ b/src/main/java/org/proshin/finapi/account/in/DailyBalancesCriteria.java @@ -16,16 +16,61 @@ package org.proshin.finapi.account.in; import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.apache.http.NameValuePair; +import org.proshin.finapi.primitives.StringOf; +import org.proshin.finapi.primitives.pair.CommaSeparatedPair; +import org.proshin.finapi.primitives.pair.UrlEncodedPair; -public interface DailyBalancesCriteria { +public final class DailyBalancesCriteria implements Iterable { - DailyBalancesCriteria withAccounts(Iterable ids); + private final List pairs; - DailyBalancesCriteria withStartDate(OffsetDateTime startDate); + public DailyBalancesCriteria() { + this(new ArrayList<>()); + } - DailyBalancesCriteria withEndDate(OffsetDateTime endDate); + public DailyBalancesCriteria(final List pairs) { + this.pairs = pairs; + } - DailyBalancesCriteria withProjection(boolean projection); + public DailyBalancesCriteria withAccounts(final Iterable accounts) { + this.pairs.add(new UrlEncodedPair(new CommaSeparatedPair<>("accountIds", accounts))); + return this; + } - DailyBalancesCriteria withOrdering(String order); + public DailyBalancesCriteria withStartDate(final OffsetDateTime startDate) { + this.pairs.add(new UrlEncodedPair("startDate", new StringOf(startDate))); + return this; + } + + public DailyBalancesCriteria withEndDate(final OffsetDateTime endDate) { + this.pairs.add(new UrlEncodedPair("endDate", new StringOf(endDate))); + return this; + } + + public DailyBalancesCriteria withProjection() { + this.pairs.add(new UrlEncodedPair("withProjection", false)); + return this; + } + + public DailyBalancesCriteria withPage(final int page, final int perPage) { + this.pairs.add(new UrlEncodedPair("page", page)); + this.pairs.add(new UrlEncodedPair("perPage", perPage)); + return this; + } + + public DailyBalancesCriteria orderBy(final String... orders) { + for (final String order : orders) { + this.pairs.add(new UrlEncodedPair("order", order)); + } + return this; + } + + @Override + public Iterator iterator() { + return this.pairs.iterator(); + } } diff --git a/src/main/java/org/proshin/finapi/account/in/DirectDebitParameters.java b/src/main/java/org/proshin/finapi/account/in/DirectDebitParameters.java new file mode 100644 index 0000000..2a774f3 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/in/DirectDebitParameters.java @@ -0,0 +1,158 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.in; + +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import org.json.JSONObject; +import org.proshin.finapi.Jsonable; +import org.proshin.finapi.primitives.StringOf; + +public final class DirectDebitParameters implements Jsonable { + + private final JSONObject origin; + + public DirectDebitParameters() { + this(new JSONObject()); + } + + public DirectDebitParameters(final JSONObject origin) { + this.origin = origin; + } + + public DirectDebitParameters withAccount(final Long account) { + this.origin.put("accountId", account); + return this; + } + + public DirectDebitParameters withBankingPin(final String bankingPin) { + this.origin.put("bankingPin", bankingPin); + return this; + } + + public DirectDebitParameters withStoringPin() { + this.origin.put("storePin", true); + return this; + } + + public DirectDebitParameters withTwoStepProcedure(final String id) { + this.origin.put("twoStepProcedureId", id); + return this; + } + + public DirectDebitParameters withDirectDebitType(final DirectDebitType type) { + this.origin.put("directDebitType", type); + return this; + } + + public DirectDebitParameters withSequenceType(final SequenceType type) { + this.origin.put("sequenceType", type); + return this; + } + + public DirectDebitParameters withExecutionDate(final OffsetDateTime executionDate) { + this.origin.put("executionDate", new StringOf(executionDate)); + return this; + } + + public DirectDebitParameters asSingleBooking() { + this.origin.put("singleBooking", true); + return this; + } + + public DirectDebitParameters withDebtors(final Debtor debtors) { + return this; + } + + @Override + public String asJson() { + return this.origin.toString(); + } + + public enum DirectDebitType { + BASIC, B2B + } + + public enum SequenceType { + OOFF, FRST, RCUR, FNAL + } + + public static final class Debtor { + private final JSONObject origin; + + public Debtor() { + this(new JSONObject()); + } + + public Debtor(final JSONObject origin) { + this.origin = origin; + } + + public Debtor withName(final String name) { + this.origin.put("debitorName", name); + return this; + } + + public Debtor withIban(final String iban) { + this.origin.put("debitorIban", iban); + return this; + } + + public Debtor withBic(final String bic) { + this.origin.put("debitorBic", bic); + return this; + } + + public Debtor withAmount(final BigDecimal amount) { + this.origin.put("amount", amount); + return this; + } + + public Debtor withPurpose(final String purpose) { + this.origin.put("purpose", purpose); + return this; + } + + public Debtor withSepaPurposeCode(final String sepaPurposeCode) { + this.origin.put("sepaPurposeCode", sepaPurposeCode); + return this; + } + + public Debtor withMandateId(final String mandateId) { + this.origin.put("mandateId", mandateId); + return this; + } + + public Debtor withMandateDate(final OffsetDateTime mandateDate) { + this.origin.put("mandateDate", new StringOf(mandateDate)); + return this; + } + + public Debtor withCreditorId(final String creditorId) { + this.origin.put("creditorId", creditorId); + return this; + } + + public Debtor withEndToEndId(final String endToEndId) { + this.origin.put("endToEndIdId", endToEndId); + return this; + } + + public JSONObject asJsonObject() { + return this.origin; + } + } +} diff --git a/src/main/java/org/proshin/finapi/account/FpQueryCriteria.java b/src/main/java/org/proshin/finapi/account/in/FpQueryCriteria.java similarity index 71% rename from src/main/java/org/proshin/finapi/account/FpQueryCriteria.java rename to src/main/java/org/proshin/finapi/account/in/FpQueryCriteria.java index 395ebb8..8923ab4 100644 --- a/src/main/java/org/proshin/finapi/account/FpQueryCriteria.java +++ b/src/main/java/org/proshin/finapi/account/in/FpQueryCriteria.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.proshin.finapi.account; +package org.proshin.finapi.account.in; import java.math.BigDecimal; import java.time.OffsetDateTime; @@ -23,11 +23,12 @@ import java.util.List; import java.util.stream.Collectors; import org.apache.http.NameValuePair; +import org.proshin.finapi.account.Type; import org.proshin.finapi.primitives.StringOf; import org.proshin.finapi.primitives.pair.CommaSeparatedPair; import org.proshin.finapi.primitives.pair.UrlEncodedPair; -public final class FpQueryCriteria implements QueryCriteria { +public final class FpQueryCriteria implements Iterable { private final List pairs; @@ -39,20 +40,17 @@ public FpQueryCriteria(final List pairs) { this.pairs = pairs; } - @Override - public QueryCriteria withIds(final Iterable ids) { + public FpQueryCriteria withIds(final Iterable ids) { this.pairs.add(new UrlEncodedPair(new CommaSeparatedPair<>("ids", ids))); return this; } - @Override - public QueryCriteria withSearch(final String search) { + public FpQueryCriteria withSearch(final String search) { this.pairs.add(new UrlEncodedPair("search", search)); return this; } - @Override - public QueryCriteria withTypes(final Type... types) { + public FpQueryCriteria withTypes(final Type... types) { this.pairs.add( new UrlEncodedPair( new CommaSeparatedPair<>( @@ -66,43 +64,38 @@ public QueryCriteria withTypes(final Type... types) { return this; } - @Override - public QueryCriteria withBankConnections(final Iterable ids) { + public FpQueryCriteria withBankConnections(final Iterable ids) { this.pairs.add(new UrlEncodedPair(new CommaSeparatedPair<>("bankConnectionIds", ids))); return this; } - @Override - public QueryCriteria withMinLastSuccessfulUpdate(final OffsetDateTime minLastSuccessfulUpdate) { + public FpQueryCriteria withMinLastSuccessfulUpdate(final OffsetDateTime minLastSuccessfulUpdate) { this.pairs.add( new UrlEncodedPair( "minLastSuccessfulUpdate", - new StringOf(minLastSuccessfulUpdate).get() + new StringOf(minLastSuccessfulUpdate) ) ); return this; } - @Override - public QueryCriteria withMaxLastSuccessfulUpdate(final OffsetDateTime maxLastSuccessfulUpdate) { + public FpQueryCriteria withMaxLastSuccessfulUpdate(final OffsetDateTime maxLastSuccessfulUpdate) { this.pairs.add( new UrlEncodedPair( "maxLastSuccessfulUpdate", - new StringOf(maxLastSuccessfulUpdate).get() + new StringOf(maxLastSuccessfulUpdate) ) ); return this; } - @Override - public QueryCriteria withMinBalance(final BigDecimal minBalance) { - this.pairs.add(new UrlEncodedPair("minBalance", new StringOf(minBalance).get())); + public FpQueryCriteria withMinBalance(final BigDecimal minBalance) { + this.pairs.add(new UrlEncodedPair("minBalance", new StringOf(minBalance))); return this; } - @Override - public QueryCriteria withMaxBalance(final BigDecimal maxBalance) { - this.pairs.add(new UrlEncodedPair("maxBalance", new StringOf(maxBalance).get())); + public FpQueryCriteria withMaxBalance(final BigDecimal maxBalance) { + this.pairs.add(new UrlEncodedPair("maxBalance", new StringOf(maxBalance))); return this; } diff --git a/src/main/java/org/proshin/finapi/account/in/MoneyTransferParameters.java b/src/main/java/org/proshin/finapi/account/in/MoneyTransferParameters.java new file mode 100644 index 0000000..ef5f205 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/in/MoneyTransferParameters.java @@ -0,0 +1,143 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.in; + +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import java.util.Iterator; +import org.cactoos.iterator.IteratorOf; +import org.json.JSONObject; +import org.proshin.finapi.Jsonable; +import org.proshin.finapi.primitives.StringOf; + +public final class MoneyTransferParameters implements Jsonable { + + private final JSONObject origin; + + public MoneyTransferParameters() { + this(new JSONObject()); + } + + public MoneyTransferParameters(final JSONObject origin) { + this.origin = origin; + } + + public MoneyTransferParameters withAccount(final Long account) { + this.origin.put("accountId", account); + return this; + } + + public MoneyTransferParameters withBankingPin(final String bankingPin) { + this.origin.put("bankingPin", bankingPin); + return this; + } + + public MoneyTransferParameters withStoringPin() { + this.origin.put("storePin", true); + return this; + } + + public MoneyTransferParameters withTwoStepProcedure(final String id) { + this.origin.put("twoStepProcedureId", id); + return this; + } + + public MoneyTransferParameters withChallengeResponse(final String response) { + this.origin.put("challengeResponse", response); + return this; + } + + public MoneyTransferParameters withExecutionDate(final OffsetDateTime executionDate) { + this.origin.put("executionDate", new StringOf(executionDate)); + return this; + } + + public MoneyTransferParameters asSingleBooking() { + this.origin.put("singleBooking", true); + return this; + } + + public MoneyTransferParameters withRecipients(final Recipient... recipients) { + final Iterator iterator = new IteratorOf<>(recipients); + if (iterator.hasNext()) { + final JSONObject jsonObject = iterator.next().asJsonObject(); + for (final String key : jsonObject.keySet()) { + this.origin.put(key, jsonObject.get(key)); + } + } + while (iterator.hasNext()) { + this.origin.append("additionalMoneyTransfers", iterator.next().asJsonObject()); + } + return this; + } + + @Override + public String asJson() { + return this.origin.toString(); + } + + public static final class Recipient { + + private final JSONObject origin; + + public Recipient() { + this(new JSONObject()); + } + + public Recipient(final JSONObject origin) { + this.origin = origin; + } + + public Recipient withName(final String name) { + this.origin.put("recipientName", name); + return this; + } + + public Recipient withIban(final String iban) { + this.origin.put("recipientIban", iban); + return this; + } + + public Recipient withBic(final String bic) { + this.origin.put("recipientBic", bic); + return this; + } + + public Recipient withClearingAccount(final String id) { + this.origin.put("clearingAccountId", id); + return this; + } + + public Recipient withAmount(final BigDecimal amount) { + this.origin.put("amount", amount); + return this; + } + + public Recipient withPurpose(final String purpose) { + this.origin.put("purpose", purpose); + return this; + } + + public Recipient withSepaPurposeCode(final String sepaPurposeCode) { + this.origin.put("sepaPurposeCode", sepaPurposeCode); + return this; + } + + public JSONObject asJsonObject() { + return this.origin; + } + } +} diff --git a/src/main/java/org/proshin/finapi/account/out/DailyBalance.java b/src/main/java/org/proshin/finapi/account/out/DailyBalance.java index 88a9a42..d0730d4 100644 --- a/src/main/java/org/proshin/finapi/account/out/DailyBalance.java +++ b/src/main/java/org/proshin/finapi/account/out/DailyBalance.java @@ -17,7 +17,6 @@ import java.math.BigDecimal; import java.time.OffsetDateTime; -import org.proshin.finapi.transaction.Transaction; public interface DailyBalance { OffsetDateTime date(); @@ -28,5 +27,5 @@ public interface DailyBalance { BigDecimal spending(); - Iterable transactions(); + Iterable transactions(); } diff --git a/src/main/java/org/proshin/finapi/account/out/DailyBalances.java b/src/main/java/org/proshin/finapi/account/out/DailyBalances.java index caf09cf..8ef029c 100644 --- a/src/main/java/org/proshin/finapi/account/out/DailyBalances.java +++ b/src/main/java/org/proshin/finapi/account/out/DailyBalances.java @@ -17,9 +17,9 @@ import java.time.OffsetDateTime; import java.util.Optional; -import org.proshin.finapi.collection.Pages; +import org.proshin.finapi.primitives.paging.Page; -public interface DailyBalances extends Pages { +public interface DailyBalances extends Page { Optional latestCommonBalanceTimestamp(); } diff --git a/src/main/java/org/proshin/finapi/account/out/DirectDebit.java b/src/main/java/org/proshin/finapi/account/out/DirectDebit.java new file mode 100644 index 0000000..fca0bbf --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/DirectDebit.java @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import org.proshin.finapi.account.in.DirectDebitParameters; + +public interface DirectDebit { + + SepaRequestingResponse request(final DirectDebitParameters parameters); + + SepaExecutingResponse execute(Long account, String bankingTan); +} diff --git a/src/main/java/org/proshin/finapi/account/out/FpDailyBalance.java b/src/main/java/org/proshin/finapi/account/out/FpDailyBalance.java new file mode 100644 index 0000000..06b1da2 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/FpDailyBalance.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import org.json.JSONArray; +import org.json.JSONObject; +import org.proshin.finapi.primitives.IterableJsonArray; +import org.proshin.finapi.primitives.OffsetDateTimeOf; + +public final class FpDailyBalance implements DailyBalance { + + private final JSONObject origin; + + public FpDailyBalance(final JSONObject origin) { + this.origin = origin; + } + + @Override + public OffsetDateTime date() { + return new OffsetDateTimeOf(this.origin.getString("date")).get(); + } + + @Override + public BigDecimal balance() { + return this.origin.getBigDecimal("balance"); + } + + @Override + public BigDecimal income() { + return this.origin.getBigDecimal("income"); + } + + @Override + public BigDecimal spending() { + return this.origin.getBigDecimal("spending"); + } + + @Override + public Iterable transactions() { + return new IterableJsonArray<>( + this.origin.getJSONArray("transactions"), + JSONArray::getLong + ); + } +} diff --git a/src/main/java/org/proshin/finapi/account/out/FpDailyBalances.java b/src/main/java/org/proshin/finapi/account/out/FpDailyBalances.java new file mode 100644 index 0000000..e044a0f --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/FpDailyBalances.java @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import java.time.OffsetDateTime; +import java.util.Optional; +import org.json.JSONObject; +import org.proshin.finapi.primitives.optional.OptionalOffsetDateTimeOf; +import org.proshin.finapi.primitives.paging.FpPage; +import org.proshin.finapi.primitives.paging.Page; +import org.proshin.finapi.primitives.paging.Paging; + +public final class FpDailyBalances implements DailyBalances { + + private final JSONObject origin; + private final Page page; + + public FpDailyBalances(final JSONObject origin) { + this.origin = origin; + this.page = new FpPage<>( + "dailyBalances", + this.origin, + (array, index) -> new FpDailyBalance(array.getJSONObject(index)) + ); + } + + @Override + public Optional latestCommonBalanceTimestamp() { + return new OptionalOffsetDateTimeOf(this.origin, "latestCommonBalanceTimestamp").get(); + } + + @Override + public Iterable items() { + return this.page.items(); + } + + @Override + public Paging paging() { + return this.page.paging(); + } +} diff --git a/src/main/java/org/proshin/finapi/account/out/FpDirectDebit.java b/src/main/java/org/proshin/finapi/account/out/FpDirectDebit.java new file mode 100644 index 0000000..7e46938 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/FpDirectDebit.java @@ -0,0 +1,63 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import org.json.JSONObject; +import org.proshin.finapi.accesstoken.AccessToken; +import org.proshin.finapi.account.in.DirectDebitParameters; +import org.proshin.finapi.endpoint.Endpoint; + +public final class FpDirectDebit implements DirectDebit { + + private final Endpoint endpoint; + private final AccessToken token; + private final String url; + + public FpDirectDebit(final Endpoint endpoint, final AccessToken token, final String url) { + this.endpoint = endpoint; + this.token = token; + this.url = url; + } + + @Override + public SepaRequestingResponse request(final DirectDebitParameters parameters) { + return new FpSepaRequestingResponse( + new JSONObject( + this.endpoint.post( + this.url + "requestSepaDirectDebit", + this.token, + parameters + ) + ) + ); + } + + @Override + public SepaExecutingResponse execute(final Long account, final String bankingTan) { + return new FpSepaExecutingResponse( + new JSONObject( + this.endpoint.post( + this.url + "executeSepaDirectDebit", + this.token, + () -> new JSONObject() + .put("accountId", account) + .put("bankingTan", bankingTan) + .toString() + ) + ) + ); + } +} diff --git a/src/main/java/org/proshin/finapi/account/out/FpSepaExecutingResponse.java b/src/main/java/org/proshin/finapi/account/out/FpSepaExecutingResponse.java new file mode 100644 index 0000000..b60f5b9 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/FpSepaExecutingResponse.java @@ -0,0 +1,43 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import java.util.Optional; +import org.json.JSONObject; +import org.proshin.finapi.primitives.optional.OptionalStringOf; + +public final class FpSepaExecutingResponse implements SepaExecutingResponse { + + private final JSONObject origin; + + public FpSepaExecutingResponse() { + this(new JSONObject()); + } + + public FpSepaExecutingResponse(final JSONObject origin) { + this.origin = origin; + } + + @Override + public Optional successMessage() { + return new OptionalStringOf(this.origin, "successMessage").get(); + } + + @Override + public Optional warnMessage() { + return new OptionalStringOf(this.origin, "warnMessage").get(); + } +} diff --git a/src/main/java/org/proshin/finapi/account/out/FpSepaRequestingResponse.java b/src/main/java/org/proshin/finapi/account/out/FpSepaRequestingResponse.java new file mode 100644 index 0000000..888c51d --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/FpSepaRequestingResponse.java @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import java.util.Optional; +import org.json.JSONObject; +import org.proshin.finapi.primitives.optional.OptionalStringOf; + +public final class FpSepaRequestingResponse implements SepaRequestingResponse { + + private final JSONObject origin; + + public FpSepaRequestingResponse() { + this(new JSONObject()); + } + + public FpSepaRequestingResponse(final JSONObject origin) { + this.origin = origin; + } + + @Override + public Optional successMessage() { + return new OptionalStringOf(this.origin, "successMessage").get(); + } + + @Override + public Optional warnMessage() { + return new OptionalStringOf(this.origin, "warnMessage").get(); + } + + @Override + public Optional challengeMessage() { + return new OptionalStringOf(this.origin, "challengeMessage").get(); + } + + @Override + public Optional answerFieldLabel() { + return new OptionalStringOf(this.origin, "answerFieldLabel").get(); + } + + @Override + public Optional tanListNumber() { + return new OptionalStringOf(this.origin, "tanListNumber").get(); + } + + @Override + public Optional opticalData() { + return new OptionalStringOf(this.origin, "opticalData").get(); + } + + @Override + public Optional photoTanMimeType() { + return new OptionalStringOf(this.origin, "photoTanMimeType").get(); + } + + @Override + public Optional photoTanData() { + return new OptionalStringOf(this.origin, "photoTanData").get(); + } +} diff --git a/src/main/java/org/proshin/finapi/account/Order.java b/src/main/java/org/proshin/finapi/account/out/Order.java similarity index 95% rename from src/main/java/org/proshin/finapi/account/Order.java rename to src/main/java/org/proshin/finapi/account/out/Order.java index 1c02700..47e2a21 100644 --- a/src/main/java/org/proshin/finapi/account/Order.java +++ b/src/main/java/org/proshin/finapi/account/out/Order.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.proshin.finapi.account; +package org.proshin.finapi.account.out; public enum Order { SEPA_MONEY_TRANSFER, diff --git a/src/main/java/org/proshin/finapi/account/DirectDebit.java b/src/main/java/org/proshin/finapi/account/out/SepaExecutingResponse.java similarity index 76% rename from src/main/java/org/proshin/finapi/account/DirectDebit.java rename to src/main/java/org/proshin/finapi/account/out/SepaExecutingResponse.java index f0201ae..8990026 100644 --- a/src/main/java/org/proshin/finapi/account/DirectDebit.java +++ b/src/main/java/org/proshin/finapi/account/out/SepaExecutingResponse.java @@ -13,7 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.proshin.finapi.account; +package org.proshin.finapi.account.out; -public interface DirectDebit { +import java.util.Optional; + +public interface SepaExecutingResponse { + + Optional successMessage(); + + Optional warnMessage(); } diff --git a/src/main/java/org/proshin/finapi/account/out/SepaRequestingResponse.java b/src/main/java/org/proshin/finapi/account/out/SepaRequestingResponse.java new file mode 100644 index 0000000..4fd4ea5 --- /dev/null +++ b/src/main/java/org/proshin/finapi/account/out/SepaRequestingResponse.java @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Roman Proshin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.proshin.finapi.account.out; + +import java.util.Optional; + +public interface SepaRequestingResponse { + + Optional successMessage(); + + Optional warnMessage(); + + Optional challengeMessage(); + + Optional answerFieldLabel(); + + Optional tanListNumber(); + + Optional opticalData(); + + Optional photoTanMimeType(); + + Optional photoTanData(); +} diff --git a/src/main/java/org/proshin/finapi/account/Status.java b/src/main/java/org/proshin/finapi/account/out/Status.java similarity index 94% rename from src/main/java/org/proshin/finapi/account/Status.java rename to src/main/java/org/proshin/finapi/account/out/Status.java index c3d7822..cd0b447 100644 --- a/src/main/java/org/proshin/finapi/account/Status.java +++ b/src/main/java/org/proshin/finapi/account/out/Status.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.proshin.finapi.account; +package org.proshin.finapi.account.out; public enum Status { UPDATED, diff --git a/src/main/java/org/proshin/finapi/bankconnection/FpBankConnections.java b/src/main/java/org/proshin/finapi/bankconnection/FpBankConnections.java index e777c4c..9a4c40e 100644 --- a/src/main/java/org/proshin/finapi/bankconnection/FpBankConnections.java +++ b/src/main/java/org/proshin/finapi/bankconnection/FpBankConnections.java @@ -95,8 +95,7 @@ public Future update(final UpdateParameters parameters) { this.endpoint.post( "/api/v1/bankConnections/update", this.token, - parameters, - 200 + parameters ) ) )); diff --git a/src/main/java/org/proshin/finapi/category/FpCategories.java b/src/main/java/org/proshin/finapi/category/FpCategories.java index 17cd48b..d2a20b7 100644 --- a/src/main/java/org/proshin/finapi/category/FpCategories.java +++ b/src/main/java/org/proshin/finapi/category/FpCategories.java @@ -92,7 +92,7 @@ public Category create(final CreateCategoryParameters parameters) { @Override public void trainCategorization(final TrainCategorizationParameters parameters) { - this.endpoint.post(this.url + "trainCategorization", this.token, parameters, 200); + this.endpoint.post(this.url + "trainCategorization", this.token, parameters); } @Override diff --git a/src/main/java/org/proshin/finapi/endpoint/Endpoint.java b/src/main/java/org/proshin/finapi/endpoint/Endpoint.java index 4acf392..68e17fc 100644 --- a/src/main/java/org/proshin/finapi/endpoint/Endpoint.java +++ b/src/main/java/org/proshin/finapi/endpoint/Endpoint.java @@ -45,6 +45,18 @@ default String get(final String path, final AccessToken token, final NameValuePa String post(String path, AccessToken token, HttpEntity entity, int expected); + default String post(final String path, final AccessToken token, final Jsonable body) { + return this.post( + path, + token, + new StringEntity( + body.asJson(), + ContentType.create("application/json", StandardCharsets.UTF_8) + ), + 200 + ); + } + default String post(final String path, final AccessToken token, final Jsonable body, final int expected) { return this.post( path, @@ -52,7 +64,8 @@ default String post(final String path, final AccessToken token, final Jsonable b new StringEntity( body.asJson(), ContentType.create("application/json", StandardCharsets.UTF_8) - ), expected + ), + expected ); } diff --git a/src/main/java/org/proshin/finapi/primitives/StringOf.java b/src/main/java/org/proshin/finapi/primitives/StringOf.java index 34097c2..a2a2a31 100644 --- a/src/main/java/org/proshin/finapi/primitives/StringOf.java +++ b/src/main/java/org/proshin/finapi/primitives/StringOf.java @@ -30,8 +30,8 @@ public final class StringOf implements Supplier { public StringOf(final OffsetDateTime value) { this(DateTimeFormatter.ofPattern("yyyy-MM-dd") - .withZone(ZoneId.of("Europe/Berlin")) - .format(value)); + .withZone(ZoneId.of("Europe/Berlin")) + .format(value)); } public StringOf(final BigDecimal value) { diff --git a/src/main/java/org/proshin/finapi/user/FpUsers.java b/src/main/java/org/proshin/finapi/user/FpUsers.java index ad875a0..190df57 100644 --- a/src/main/java/org/proshin/finapi/user/FpUsers.java +++ b/src/main/java/org/proshin/finapi/user/FpUsers.java @@ -15,8 +15,6 @@ */ package org.proshin.finapi.user; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; import org.json.JSONObject; import org.proshin.finapi.accesstoken.AccessToken; import org.proshin.finapi.endpoint.Endpoint; @@ -59,8 +57,7 @@ public String requestPasswordChange(final String userId) { this.endpoint.post( "/api/v1/users/requestPasswordChange", this.token, - new StringEntity(new JSONObject().put("userId", userId).toString(), ContentType.APPLICATION_JSON), - 200 + () -> new JSONObject().put("userId", userId).toString() ) ).getString("passwordChangeToken"); } @@ -70,15 +67,11 @@ public void executePasswordChange(final String userId, final String password, fi this.endpoint.post( "/api/v1/users/executePasswordChange", this.token, - new StringEntity( - new JSONObject() - .put("userId", userId) - .put("password", password) - .put("passwordChangeToken", token) - .toString(), - ContentType.APPLICATION_JSON - ), - 200 + () -> new JSONObject() + .put("userId", userId) + .put("password", password) + .put("passwordChangeToken", token) + .toString() ); } diff --git a/src/test/java/org/proshin/finapi/primitives/StringOfTest.java b/src/test/java/org/proshin/finapi/primitives/StringOfTest.java index 8533374..8bd72ca 100644 --- a/src/test/java/org/proshin/finapi/primitives/StringOfTest.java +++ b/src/test/java/org/proshin/finapi/primitives/StringOfTest.java @@ -26,7 +26,7 @@ public class StringOfTest { @Test public void testStringOfOffsetDateTime() { assertThat( - new StringOf(OffsetDateTime.of(2018, 10, 25, 1, 2, 3, 4, ZoneOffset.UTC)).get(), + new StringOf(OffsetDateTime.of(2018, 10, 25, 1, 2, 3, 4, ZoneOffset.UTC)).toString(), is("2018-10-25") ); } @@ -34,7 +34,7 @@ public void testStringOfOffsetDateTime() { @Test public void testStringOfBigDecimal() { assertThat( - new StringOf(new BigDecimal("123456.012")).get(), + new StringOf(new BigDecimal("123456.012")).toString(), is("123456.01") ); }