diff --git a/core/src/main/java/bisq/core/payment/AchTransferAccount.java b/core/src/main/java/bisq/core/payment/AchTransferAccount.java new file mode 100644 index 00000000000..386e9f2a798 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/AchTransferAccount.java @@ -0,0 +1,63 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.payment; + +import bisq.core.payment.payload.BankAccountPayload; +import bisq.core.payment.payload.AchTransferAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +public final class AchTransferAccount extends CountryBasedPaymentAccount implements SameCountryRestrictedBankAccount { + public AchTransferAccount() { + super(PaymentMethod.ACH_TRANSFER); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new AchTransferAccountPayload(paymentMethod.getId(), id); + } + + @Override + public String getBankId() { + return ((BankAccountPayload) paymentAccountPayload).getBankId(); + } + + @Override + public String getCountryCode() { + return getCountry() != null ? getCountry().code : ""; + } + + public AchTransferAccountPayload getPayload() { + return (AchTransferAccountPayload) paymentAccountPayload; + } + + public String getMessageForBuyer() { + return "payment.achTransfer.info.buyer"; + } + + public String getMessageForSeller() { + return "payment.achTransfer.info.seller"; + } + + public String getMessageForAccountCreation() { + return "payment.achTransfer.info.account"; + } +} diff --git a/core/src/main/java/bisq/core/payment/DomesticWireTransferAccount.java b/core/src/main/java/bisq/core/payment/DomesticWireTransferAccount.java new file mode 100644 index 00000000000..4844211c335 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/DomesticWireTransferAccount.java @@ -0,0 +1,63 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.payment; + +import bisq.core.payment.payload.BankAccountPayload; +import bisq.core.payment.payload.DomesticWireTransferAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.payment.payload.PaymentMethod; + +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +public final class DomesticWireTransferAccount extends CountryBasedPaymentAccount implements SameCountryRestrictedBankAccount { + public DomesticWireTransferAccount() { + super(PaymentMethod.DOMESTIC_WIRE_TRANSFER); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new DomesticWireTransferAccountPayload(paymentMethod.getId(), id); + } + + @Override + public String getBankId() { + return ((BankAccountPayload) paymentAccountPayload).getBankId(); + } + + @Override + public String getCountryCode() { + return getCountry() != null ? getCountry().code : ""; + } + + public DomesticWireTransferAccountPayload getPayload() { + return (DomesticWireTransferAccountPayload) paymentAccountPayload; + } + + public String getMessageForBuyer() { + return "payment.domesticWire.info.buyer"; + } + + public String getMessageForSeller() { + return "payment.domesticWire.info.seller"; + } + + public String getMessageForAccountCreation() { + return "payment.domesticWire.info.account"; + } +} diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java index c570d749bef..8e3c1e74a36 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountFactory.java @@ -124,6 +124,10 @@ public static PaymentAccount getPaymentAccount(PaymentMethod paymentMethod) { return new StrikeAccount(); case PaymentMethod.SWIFT_ID: return new SwiftAccount(); + case PaymentMethod.ACH_TRANSFER_ID: + return new AchTransferAccount(); + case PaymentMethod.DOMESTIC_WIRE_TRANSFER_ID: + return new DomesticWireTransferAccount(); case PaymentMethod.BSQ_SWAP_ID: return new BsqSwapAccount(); diff --git a/core/src/main/java/bisq/core/payment/payload/AchTransferAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/AchTransferAccountPayload.java new file mode 100644 index 00000000000..7c438bb078b --- /dev/null +++ b/core/src/main/java/bisq/core/payment/payload/AchTransferAccountPayload.java @@ -0,0 +1,115 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.payment.payload; + +import bisq.core.locale.Res; + +import com.google.protobuf.Message; + +import java.util.HashMap; +import java.util.Map; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@EqualsAndHashCode(callSuper = true) +@ToString +@Getter +@Setter +@Slf4j +public final class AchTransferAccountPayload extends BankAccountPayload { + private String holderAddress = ""; + + public AchTransferAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTO BUFFER + /////////////////////////////////////////////////////////////////////////////////////////// + + private AchTransferAccountPayload(String paymentMethodName, + String id, + String countryCode, + String holderName, + String bankName, + String branchId, + String accountNr, + String accountType, + String holderAddress, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethodName, + id, + countryCode, + holderName, + bankName, + branchId, + accountNr, + accountType, + null, // holderTaxId not used + null, // bankId not used + null, // nationalAccountId not used + maxTradePeriod, + excludeFromJsonDataMap); + + this.holderAddress = holderAddress; + } + + @Override + public Message toProtoMessage() { + protobuf.AchTransferAccountPayload.Builder builder = protobuf.AchTransferAccountPayload.newBuilder() + .setHolderAddress(holderAddress); + protobuf.BankAccountPayload.Builder bankAccountPayloadBuilder = getPaymentAccountPayloadBuilder() + .getCountryBasedPaymentAccountPayloadBuilder() + .getBankAccountPayloadBuilder() + .setAchTransferAccountPayload(builder); + protobuf.CountryBasedPaymentAccountPayload.Builder countryBasedPaymentAccountPayloadBuilder = getPaymentAccountPayloadBuilder() + .getCountryBasedPaymentAccountPayloadBuilder() + .setBankAccountPayload(bankAccountPayloadBuilder); + return getPaymentAccountPayloadBuilder() + .setCountryBasedPaymentAccountPayload(countryBasedPaymentAccountPayloadBuilder) + .build(); + } + + public static AchTransferAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + protobuf.CountryBasedPaymentAccountPayload countryBasedPaymentAccountPayload = proto.getCountryBasedPaymentAccountPayload(); + protobuf.BankAccountPayload bankAccountPayloadPB = countryBasedPaymentAccountPayload.getBankAccountPayload(); + protobuf.AchTransferAccountPayload accountPayloadPB = bankAccountPayloadPB.getAchTransferAccountPayload(); + return new AchTransferAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + countryBasedPaymentAccountPayload.getCountryCode(), + bankAccountPayloadPB.getHolderName(), + bankAccountPayloadPB.getBankName().isEmpty() ? null : bankAccountPayloadPB.getBankName(), + bankAccountPayloadPB.getBranchId().isEmpty() ? null : bankAccountPayloadPB.getBranchId(), + bankAccountPayloadPB.getAccountNr().isEmpty() ? null : bankAccountPayloadPB.getAccountNr(), + bankAccountPayloadPB.getAccountType().isEmpty() ? null : bankAccountPayloadPB.getAccountType(), + accountPayloadPB.getHolderAddress().isEmpty() ? null : accountPayloadPB.getHolderAddress(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + @Override + public String getPaymentDetails() { + return Res.get(paymentMethodId) + " - " + getPaymentDetailsForTradePopup().replace("\n", ", "); + } +} diff --git a/core/src/main/java/bisq/core/payment/payload/DomesticWireTransferAccountPayload.java b/core/src/main/java/bisq/core/payment/payload/DomesticWireTransferAccountPayload.java new file mode 100644 index 00000000000..f3bba3223e6 --- /dev/null +++ b/core/src/main/java/bisq/core/payment/payload/DomesticWireTransferAccountPayload.java @@ -0,0 +1,119 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.payment.payload; + +import bisq.core.locale.BankUtil; +import bisq.core.locale.Res; + +import com.google.protobuf.Message; + +import java.util.HashMap; +import java.util.Map; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +@EqualsAndHashCode(callSuper = true) +@ToString +@Getter +@Setter +@Slf4j +public final class DomesticWireTransferAccountPayload extends BankAccountPayload { + private String holderAddress = ""; + + public DomesticWireTransferAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTO BUFFER + /////////////////////////////////////////////////////////////////////////////////////////// + + private DomesticWireTransferAccountPayload(String paymentMethodName, + String id, + String countryCode, + String holderName, + String bankName, + String branchId, + String accountNr, + String holderAddress, + long maxTradePeriod, + Map excludeFromJsonDataMap) { + super(paymentMethodName, + id, + countryCode, + holderName, + bankName, + branchId, + accountNr, + null, + null, // holderTaxId not used + null, // bankId not used + null, // nationalAccountId not used + maxTradePeriod, + excludeFromJsonDataMap); + + this.holderAddress = holderAddress; + } + + @Override + public Message toProtoMessage() { + protobuf.DomesticWireTransferAccountPayload.Builder builder = protobuf.DomesticWireTransferAccountPayload.newBuilder() + .setHolderAddress(holderAddress); + protobuf.BankAccountPayload.Builder bankAccountPayloadBuilder = getPaymentAccountPayloadBuilder() + .getCountryBasedPaymentAccountPayloadBuilder() + .getBankAccountPayloadBuilder() + .setDomesticWireTransferAccountPayload(builder); + protobuf.CountryBasedPaymentAccountPayload.Builder countryBasedPaymentAccountPayloadBuilder = getPaymentAccountPayloadBuilder() + .getCountryBasedPaymentAccountPayloadBuilder() + .setBankAccountPayload(bankAccountPayloadBuilder); + return getPaymentAccountPayloadBuilder() + .setCountryBasedPaymentAccountPayload(countryBasedPaymentAccountPayloadBuilder) + .build(); + } + + public static DomesticWireTransferAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + protobuf.CountryBasedPaymentAccountPayload countryBasedPaymentAccountPayload = proto.getCountryBasedPaymentAccountPayload(); + protobuf.BankAccountPayload bankAccountPayloadPB = countryBasedPaymentAccountPayload.getBankAccountPayload(); + protobuf.DomesticWireTransferAccountPayload accountPayloadPB = bankAccountPayloadPB.getDomesticWireTransferAccountPayload(); + return new DomesticWireTransferAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + countryBasedPaymentAccountPayload.getCountryCode(), + bankAccountPayloadPB.getHolderName(), + bankAccountPayloadPB.getBankName().isEmpty() ? null : bankAccountPayloadPB.getBankName(), + bankAccountPayloadPB.getBranchId().isEmpty() ? null : bankAccountPayloadPB.getBranchId(), + bankAccountPayloadPB.getAccountNr().isEmpty() ? null : bankAccountPayloadPB.getAccountNr(), + accountPayloadPB.getHolderAddress().isEmpty() ? null : accountPayloadPB.getHolderAddress(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + @Override + public String getPaymentDetails() { + String paymentDetails = (Res.get(paymentMethodId) + " - " + + Res.getWithCol("payment.account.owner") + " " + holderName + ", " + + BankUtil.getBankNameLabel(countryCode) + ": " + this.bankName + ", " + + BankUtil.getBranchIdLabel(countryCode) + ": " + this.branchId + ", " + + BankUtil.getAccountNrLabel(countryCode) + ": " + this.accountNr); + return paymentDetails; + } +} diff --git a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java index 59f76e04a82..9850aac2e9c 100644 --- a/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/bisq/core/payment/payload/PaymentMethod.java @@ -118,6 +118,8 @@ public final class PaymentMethod implements PersistablePayload, Comparable. + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.BankUtil; +import bisq.core.locale.Country; +import bisq.core.locale.Res; +import bisq.core.payment.AchTransferAccount; +import bisq.core.payment.CountryBasedPaymentAccount; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.AchTransferAccountPayload; +import bisq.core.payment.payload.BankAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import javafx.scene.control.ComboBox; +import javafx.scene.layout.GridPane; + +import javafx.collections.FXCollections; + +import static bisq.desktop.util.FormBuilder.*; + +public class AchTransferForm extends GeneralUsBankForm { + + public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { + AchTransferAccountPayload achTransferAccountPayload = (AchTransferAccountPayload) paymentAccountPayload; + return addFormForBuyer(gridPane, gridRow, paymentAccountPayload, achTransferAccountPayload.getAccountType(), achTransferAccountPayload.getHolderAddress()); + } + + private final AchTransferAccount achTransferAccount; + + public AchTransferForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, InputValidator inputValidator, + GridPane gridPane, int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.achTransferAccount = (AchTransferAccount) paymentAccount; + } + + @Override + public void addFormForDisplayAccount() { + addFormForDisplayAccount(achTransferAccount.getPayload(), achTransferAccount.getPayload().getHolderAddress()); + } + + @Override + public void addFormForAddAccount() { + addFormForAddAccountInternal(achTransferAccount.getPayload(), achTransferAccount.getPayload().getHolderAddress()); + } + + @Override + protected void setHolderAddress(String holderAddress) { + achTransferAccount.getPayload().setHolderAddress(holderAddress); + } + + @Override + protected void maybeAddAccountTypeCombo(BankAccountPayload bankAccountPayload, Country country) { + ComboBox accountTypeComboBox = addComboBox(gridPane, ++gridRow, Res.get("payment.select.account")); + accountTypeComboBox.setItems(FXCollections.observableArrayList(BankUtil.getAccountTypeValues(country.code))); + accountTypeComboBox.setOnAction(e -> { + if (BankUtil.isAccountTypeRequired(country.code)) { + bankAccountPayload.setAccountType(accountTypeComboBox.getSelectionModel().getSelectedItem()); + updateFromInputs(); + } + }); + } + + @Override + public void updateAllInputsValid() { + AchTransferAccountPayload achTransferAccountPayload = achTransferAccount.getPayload(); + boolean result = isAccountNameValid() + && paymentAccount.getSingleTradeCurrency() != null + && ((CountryBasedPaymentAccount) this.paymentAccount).getCountry() != null + && inputValidator.validate(achTransferAccountPayload.getHolderName()).isValid + && inputValidator.validate(achTransferAccountPayload.getHolderAddress()).isValid; + + result = getValidationResult(result, + achTransferAccountPayload.getCountryCode(), + achTransferAccountPayload.getBankName(), + achTransferAccountPayload.getBankId(), + achTransferAccountPayload.getBranchId(), + achTransferAccountPayload.getAccountNr(), + achTransferAccountPayload.getAccountType(), + achTransferAccountPayload.getHolderTaxId(), + achTransferAccountPayload.getNationalAccountId()); + allInputsValid.set(result); + } +} diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/DomesticWireTransferForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/DomesticWireTransferForm.java new file mode 100644 index 00000000000..a4c3f920340 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/DomesticWireTransferForm.java @@ -0,0 +1,89 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.Country; +import bisq.core.payment.DomesticWireTransferAccount; +import bisq.core.payment.CountryBasedPaymentAccount; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.BankAccountPayload; +import bisq.core.payment.payload.DomesticWireTransferAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import javafx.scene.layout.GridPane; + +public class DomesticWireTransferForm extends GeneralUsBankForm { + + public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { + DomesticWireTransferAccountPayload domesticWireTransferAccountPayload = (DomesticWireTransferAccountPayload) paymentAccountPayload; + return addFormForBuyer(gridPane, gridRow, paymentAccountPayload, null, + domesticWireTransferAccountPayload.getHolderAddress()); + } + + private final DomesticWireTransferAccount domesticWireTransferAccount; + + public DomesticWireTransferForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, InputValidator inputValidator, + GridPane gridPane, int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.domesticWireTransferAccount = (DomesticWireTransferAccount) paymentAccount; + } + + @Override + public void addFormForDisplayAccount() { + addFormForDisplayAccount(domesticWireTransferAccount.getPayload(), domesticWireTransferAccount.getPayload().getHolderAddress()); + } + + @Override + public void addFormForAddAccount() { + addFormForAddAccountInternal(domesticWireTransferAccount.getPayload(), domesticWireTransferAccount.getPayload().getHolderAddress()); + } + + @Override + protected void setHolderAddress(String holderAddress) { + domesticWireTransferAccount.getPayload().setHolderAddress(holderAddress); + } + + @Override + protected void maybeAddAccountTypeCombo(BankAccountPayload bankAccountPayload, Country country) { + // DomesticWireTransfer does not use the account type combo + } + + @Override + public void updateAllInputsValid() { + DomesticWireTransferAccountPayload domesticWireTransferAccountPayload = domesticWireTransferAccount.getPayload(); + boolean result = isAccountNameValid() + && paymentAccount.getSingleTradeCurrency() != null + && ((CountryBasedPaymentAccount) this.paymentAccount).getCountry() != null + && inputValidator.validate(domesticWireTransferAccountPayload.getHolderName()).isValid + && inputValidator.validate(domesticWireTransferAccountPayload.getHolderAddress()).isValid; + + result = getValidationResult(result, + domesticWireTransferAccountPayload.getCountryCode(), + domesticWireTransferAccountPayload.getBankName(), + domesticWireTransferAccountPayload.getBankId(), + domesticWireTransferAccountPayload.getBranchId(), + domesticWireTransferAccountPayload.getAccountNr(), + domesticWireTransferAccountPayload.getAccountNr(), + domesticWireTransferAccountPayload.getHolderTaxId(), + domesticWireTransferAccountPayload.getNationalAccountId()); + allInputsValid.set(result); + } +} diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralUsBankForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralUsBankForm.java new file mode 100644 index 00000000000..74d196a4a96 --- /dev/null +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/GeneralUsBankForm.java @@ -0,0 +1,171 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.desktop.components.paymentmethods; + +import bisq.desktop.components.InputTextField; +import bisq.desktop.util.Layout; + +import bisq.core.account.witness.AccountAgeWitnessService; +import bisq.core.locale.BankUtil; +import bisq.core.locale.Country; +import bisq.core.locale.CountryUtil; +import bisq.core.locale.CurrencyUtil; +import bisq.core.locale.Res; +import bisq.core.locale.TradeCurrency; +import bisq.core.payment.CountryBasedPaymentAccount; +import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.BankAccountPayload; +import bisq.core.payment.payload.CountryBasedPaymentAccountPayload; +import bisq.core.payment.payload.PaymentAccountPayload; +import bisq.core.util.coin.CoinFormatter; +import bisq.core.util.validation.InputValidator; + +import javafx.scene.control.TextArea; +import javafx.scene.layout.GridPane; + +import javax.annotation.Nullable; + +import static bisq.common.util.Utilities.cleanString; +import static bisq.desktop.util.FormBuilder.*; + +public abstract class GeneralUsBankForm extends GeneralBankForm { + + protected static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload, + @Nullable String accountType, + String holderAddress) { + BankAccountPayload bankAccountPayload = (BankAccountPayload) paymentAccountPayload; + String countryCode = bankAccountPayload.getCountryCode(); + int colIndex = 1; + + addTopLabelTextFieldWithCopyIcon(gridPane, getIndexOfColumn(colIndex) == 0 ? ++gridRow : gridRow, getIndexOfColumn(colIndex++), + Res.get("payment.account.owner"), bankAccountPayload.getHolderName(), Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE); + + String branchIdLabel = BankUtil.getBranchIdLabel(countryCode); + String accountNrLabel = BankUtil.getAccountNrLabel(countryCode); + addCompactTopLabelTextFieldWithCopyIcon(gridPane, getIndexOfColumn(colIndex) == 0 ? ++gridRow : gridRow, getIndexOfColumn(colIndex++), + branchIdLabel + " / " + accountNrLabel, + bankAccountPayload.getBranchId() + " / " + bankAccountPayload.getAccountNr()); + + String bankNameLabel = BankUtil.getBankNameLabel(countryCode); + String accountTypeLabel = accountType == null ? "" : " / " + BankUtil.getAccountTypeLabel(countryCode); + addCompactTopLabelTextFieldWithCopyIcon(gridPane, getIndexOfColumn(colIndex) == 0 ? ++gridRow : gridRow, getIndexOfColumn(colIndex++), + bankNameLabel + accountTypeLabel, + accountType == null ? bankAccountPayload.getBankName() : bankAccountPayload.getBankName() + " / " + accountType); + + if (holderAddress.length() > 0) { + TextArea textAddress = addCompactTopLabelTextArea(gridPane, getIndexOfColumn(colIndex) == 0 ? ++gridRow : gridRow, getIndexOfColumn(colIndex++), + Res.get("payment.account.address"), "").second; + textAddress.setMinHeight(70); + textAddress.setEditable(false); + textAddress.setText(holderAddress); + } + return gridRow; + } + + public GeneralUsBankForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, InputValidator inputValidator, + GridPane gridPane, int gridRow, CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + } + + protected void addFormForDisplayAccount(BankAccountPayload bankAccountPayload, String holderAddress) { + Country country = ((CountryBasedPaymentAccount) paymentAccount).getCountry(); + addTopLabelTextField(gridPane, gridRow, Res.get("payment.account.name"), + paymentAccount.getAccountName(), Layout.FIRST_ROW_AND_GROUP_DISTANCE); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(paymentAccount.getPaymentMethod().getId())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), bankAccountPayload.getHolderName()); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner.address"), cleanString(holderAddress)); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.bank.name"), bankAccountPayload.getBankName()); + addCompactTopLabelTextField(gridPane, ++gridRow, BankUtil.getBranchIdLabel(country.code), bankAccountPayload.getBranchId()); + addCompactTopLabelTextField(gridPane, ++gridRow, BankUtil.getAccountNrLabel(country.code), bankAccountPayload.getAccountNr()); + if (bankAccountPayload.getAccountType() != null) { + addCompactTopLabelTextField(gridPane, ++gridRow, BankUtil.getAccountTypeLabel(country.code), bankAccountPayload.getAccountType()); + } + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), paymentAccount.getSingleTradeCurrency().getNameAndCode()); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.country"), country.name); + addLimitations(true); + } + + protected void addFormForAddAccountInternal(BankAccountPayload bankAccountPayload, String holderAddress) { + // this payment method is only for United States/USD + CountryUtil.findCountryByCode("US").ifPresent(c -> onCountrySelected(c)); + Country country = ((CountryBasedPaymentAccount) paymentAccount).getCountry(); + + InputTextField holderNameInputTextField = addInputTextField(gridPane, ++gridRow, Res.get("payment.account.owner")); + holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + bankAccountPayload.setHolderName(newValue); + updateFromInputs(); + }); + holderNameInputTextField.setValidator(inputValidator); + + TextArea addressTextArea = addTopLabelTextArea(gridPane, ++gridRow, + Res.get("payment.account.owner.address"), Res.get("payment.account.owner.address")).second; + addressTextArea.setMinHeight(70); + addressTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + setHolderAddress(newValue.trim()); + updateFromInputs(); + }); + + bankNameInputTextField = addInputTextField(gridPane, ++gridRow, Res.get("payment.bank.name")); + bankNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + bankAccountPayload.setBankName(newValue); + updateFromInputs(); + }); + bankNameInputTextField.setValidator(inputValidator); + + branchIdInputTextField = addInputTextField(gridPane, ++gridRow, BankUtil.getBranchIdLabel(country.code)); + branchIdInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + bankAccountPayload.setBranchId(newValue); + updateFromInputs(); + }); + branchIdInputTextField.setValidator(inputValidator); + + accountNrInputTextField = addInputTextField(gridPane, ++gridRow, BankUtil.getAccountNrLabel(country.code)); + accountNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + bankAccountPayload.setAccountNr(newValue); + updateFromInputs(); + }); + accountNrInputTextField.setValidator(inputValidator); + + maybeAddAccountTypeCombo(bankAccountPayload, country); + + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), paymentAccount.getSingleTradeCurrency().getNameAndCode()); + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.country"), country.name); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + this.validatorsApplied = true; + } + + abstract protected void setHolderAddress(String holderAddress); + + abstract protected void maybeAddAccountTypeCombo(BankAccountPayload bankAccountPayload, Country country); + + protected void onCountrySelected(Country country) { + if (country != null) { + ((CountryBasedPaymentAccount) this.paymentAccount).setCountry(country); + String countryCode = country.code; + TradeCurrency currency = CurrencyUtil.getCurrencyByCountryCode(countryCode); + paymentAccount.setSingleTradeCurrency(currency); + } + } + + @Override + protected void autoFillNameTextField() { + autoFillAccountTextFields((CountryBasedPaymentAccountPayload) paymentAccount.getPaymentAccountPayload()); + } +} diff --git a/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java b/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java index 69a5e9183e6..359afaff8ff 100644 --- a/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java +++ b/desktop/src/main/java/bisq/desktop/components/paymentmethods/TransferwiseUsdForm.java @@ -94,7 +94,8 @@ public void addFormForAddAccount() { updateFromInputs(); }); - TextArea addressTextArea = addTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.transferwiseUsd.address"), Res.get("payment.transferwiseUsd.address")).second; + String addressLabel = Res.get("payment.account.owner.address") + Res.get("payment.transferwiseUsd.address"); + TextArea addressTextArea = addTopLabelTextArea(gridPane, ++gridRow, addressLabel, addressLabel).second; addressTextArea.setMinHeight(70); addressTextArea.textProperty().addListener((ov, oldValue, newValue) -> { account.setBeneficiaryAddress(newValue.trim()); diff --git a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java index 178c63084bd..bad77df7d83 100644 --- a/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java +++ b/desktop/src/main/java/bisq/desktop/main/account/content/fiataccounts/FiatAccountsView.java @@ -19,6 +19,7 @@ import bisq.desktop.common.view.FxmlView; import bisq.desktop.components.TitledGroupBg; +import bisq.desktop.components.paymentmethods.AchTransferForm; import bisq.desktop.components.paymentmethods.AdvancedCashForm; import bisq.desktop.components.paymentmethods.AliPayForm; import bisq.desktop.components.paymentmethods.AmazonGiftCardForm; @@ -30,6 +31,7 @@ import bisq.desktop.components.paymentmethods.CelPayForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; import bisq.desktop.components.paymentmethods.ClearXchangeForm; +import bisq.desktop.components.paymentmethods.DomesticWireTransferForm; import bisq.desktop.components.paymentmethods.F2FForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm; import bisq.desktop.components.paymentmethods.HalCashForm; @@ -597,6 +599,10 @@ private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod, Paym return new StrikeForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.SWIFT_ID: return new SwiftForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); + case PaymentMethod.ACH_TRANSFER_ID: + return new AchTransferForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); + case PaymentMethod.DOMESTIC_WIRE_TRANSFER_ID: + return new DomesticWireTransferForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); default: log.error("Not supported PaymentMethod: " + paymentMethod); return null; diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index a2ee010eec7..304b2a48a29 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -21,6 +21,7 @@ import bisq.desktop.components.BusyAnimation; import bisq.desktop.components.TextFieldWithCopyIcon; import bisq.desktop.components.TitledGroupBg; +import bisq.desktop.components.paymentmethods.AchTransferForm; import bisq.desktop.components.paymentmethods.AdvancedCashForm; import bisq.desktop.components.paymentmethods.AliPayForm; import bisq.desktop.components.paymentmethods.AmazonGiftCardForm; @@ -32,6 +33,7 @@ import bisq.desktop.components.paymentmethods.CelPayForm; import bisq.desktop.components.paymentmethods.ChaseQuickPayForm; import bisq.desktop.components.paymentmethods.ClearXchangeForm; +import bisq.desktop.components.paymentmethods.DomesticWireTransferForm; import bisq.desktop.components.paymentmethods.F2FForm; import bisq.desktop.components.paymentmethods.FasterPaymentsForm; import bisq.desktop.components.paymentmethods.HalCashForm; @@ -400,6 +402,12 @@ protected void addContent() { case PaymentMethod.SWIFT_ID: gridRow = SwiftForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload, trade); break; + case PaymentMethod.ACH_TRANSFER_ID: + gridRow = AchTransferForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; + case PaymentMethod.DOMESTIC_WIRE_TRANSFER_ID: + gridRow = DomesticWireTransferForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; default: log.error("Not supported PaymentMethod: " + paymentMethodId); } diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 255cc52c3aa..e305174798c 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1151,10 +1151,20 @@ message BankAccountPayload { NationalBankAccountPayload national_bank_account_payload = 9; SameBankAccountPayload same_bank_accont_payload = 10; SpecificBanksAccountPayload specific_banks_account_payload = 11; + AchTransferAccountPayload ach_transfer_account_payload = 13; + DomesticWireTransferAccountPayload domestic_wire_transfer_account_payload = 14; } string national_account_id = 12; } +message AchTransferAccountPayload { + string holder_address = 1; +} + +message DomesticWireTransferAccountPayload { + string holder_address = 1; +} + message NationalBankAccountPayload { }