support MoneyGram form api

This commit is contained in:
woodser 2022-06-17 09:14:15 -04:00
parent faeb9ca8db
commit c40938f438
9 changed files with 87 additions and 36 deletions

View file

@ -71,7 +71,8 @@ public final class PaymentAccountForm implements PersistablePayload {
CLEAR_X_CHANGE, CLEAR_X_CHANGE,
SWIFT, SWIFT,
F2F, F2F,
STRIKE; STRIKE,
MONEY_GRAM;
public static PaymentAccountForm.FormId fromProto(protobuf.PaymentAccountForm.FormId formId) { public static PaymentAccountForm.FormId fromProto(protobuf.PaymentAccountForm.FormId formId) {
return ProtoUtil.enumFromProto(PaymentAccountForm.FormId.class, formId.name()); return ProtoUtil.enumFromProto(PaymentAccountForm.FormId.class, formId.name());
@ -108,6 +109,15 @@ public final class PaymentAccountForm implements PersistablePayload {
return new PaymentAccountForm(FormId.fromProto(proto.getId()), fields); return new PaymentAccountForm(FormId.fromProto(proto.getId()), fields);
} }
public String getValue(PaymentAccountFormField.FieldId fieldId) {
for (PaymentAccountFormField field : fields) {
if (field.getId() == fieldId) {
return field.getValue();
}
}
throw new IllegalArgumentException("Form does not contain field " + fieldId);
}
/** /**
* Get a structured form for the given payment method. * Get a structured form for the given payment method.
*/ */

View file

@ -21,6 +21,7 @@ import bisq.common.proto.ProtoUtil;
import bisq.common.proto.persistable.PersistablePayload; import bisq.common.proto.persistable.PersistablePayload;
import bisq.core.locale.Country; import bisq.core.locale.Country;
import bisq.core.locale.TradeCurrency; import bisq.core.locale.TradeCurrency;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -109,6 +110,7 @@ public final class PaymentAccountFormField implements PersistablePayload {
public enum Component { public enum Component {
TEXT, TEXT,
TEXTAREA,
SELECT_ONE, SELECT_ONE,
SELECT_MULTIPLE; SELECT_MULTIPLE;
@ -133,6 +135,7 @@ public final class PaymentAccountFormField implements PersistablePayload {
private List<Country> supportedCountries; private List<Country> supportedCountries;
private List<Country> supportedSepaEuroCountries; private List<Country> supportedSepaEuroCountries;
private List<Country> supportedSepaNonEuroCountries; private List<Country> supportedSepaNonEuroCountries;
private List<String> requiredForCountries;
public PaymentAccountFormField(FieldId id) { public PaymentAccountFormField(FieldId id) {
this.id = id; this.id = id;
@ -152,6 +155,7 @@ public final class PaymentAccountFormField implements PersistablePayload {
Optional.ofNullable(supportedCountries).ifPresent(e -> builder.addAllSupportedCountries(ProtoUtil.collectionToProto(supportedCountries, protobuf.Country.class))); Optional.ofNullable(supportedCountries).ifPresent(e -> builder.addAllSupportedCountries(ProtoUtil.collectionToProto(supportedCountries, protobuf.Country.class)));
Optional.ofNullable(supportedSepaEuroCountries).ifPresent(e -> builder.addAllSupportedSepaEuroCountries(ProtoUtil.collectionToProto(supportedSepaEuroCountries, protobuf.Country.class))); Optional.ofNullable(supportedSepaEuroCountries).ifPresent(e -> builder.addAllSupportedSepaEuroCountries(ProtoUtil.collectionToProto(supportedSepaEuroCountries, protobuf.Country.class)));
Optional.ofNullable(supportedSepaNonEuroCountries).ifPresent(e -> builder.addAllSupportedSepaNonEuroCountries(ProtoUtil.collectionToProto(supportedSepaNonEuroCountries, protobuf.Country.class))); Optional.ofNullable(supportedSepaNonEuroCountries).ifPresent(e -> builder.addAllSupportedSepaNonEuroCountries(ProtoUtil.collectionToProto(supportedSepaNonEuroCountries, protobuf.Country.class)));
Optional.ofNullable(requiredForCountries).ifPresent(builder::addAllRequiredForCountries);
return builder.build(); return builder.build();
} }
@ -165,6 +169,7 @@ public final class PaymentAccountFormField implements PersistablePayload {
formField.supportedCountries = proto.getSupportedCountriesList().isEmpty() ? null : proto.getSupportedCountriesList().stream().map(Country::fromProto).collect(Collectors.toList()); formField.supportedCountries = proto.getSupportedCountriesList().isEmpty() ? null : proto.getSupportedCountriesList().stream().map(Country::fromProto).collect(Collectors.toList());
formField.supportedSepaEuroCountries = proto.getSupportedSepaEuroCountriesList().isEmpty() ? null : proto.getSupportedSepaEuroCountriesList().stream().map(Country::fromProto).collect(Collectors.toList()); formField.supportedSepaEuroCountries = proto.getSupportedSepaEuroCountriesList().isEmpty() ? null : proto.getSupportedSepaEuroCountriesList().stream().map(Country::fromProto).collect(Collectors.toList());
formField.supportedSepaNonEuroCountries = proto.getSupportedSepaNonEuroCountriesList().isEmpty() ? null : proto.getSupportedSepaNonEuroCountriesList().stream().map(Country::fromProto).collect(Collectors.toList()); formField.supportedSepaNonEuroCountries = proto.getSupportedSepaNonEuroCountriesList().isEmpty() ? null : proto.getSupportedSepaNonEuroCountriesList().stream().map(Country::fromProto).collect(Collectors.toList());
formField.requiredForCountries = proto.getRequiredForCountriesList() == null ? null : new ArrayList<String>(proto.getRequiredForCountriesList());
return formField; return formField;
} }
} }

View file

@ -20,7 +20,7 @@ package bisq.core.locale;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -264,18 +264,15 @@ public class BankUtil {
} }
} }
public static List<Country> getAllStateRequiredCountries() {
List<String> codes = List.of("US", "CA", "AU", "MY", "MX", "CN");
List<Country> list = CountryUtil.getCountries(codes);
list.sort((a, b) -> a.name.compareTo(b.name));
return list;
}
public static boolean isStateRequired(String countryCode) { public static boolean isStateRequired(String countryCode) {
switch (countryCode) { return getAllStateRequiredCountries().stream().map(country -> country.code).collect(Collectors.toList()).contains(countryCode);
case "US":
case "CA":
case "AU":
case "MY":
case "MX":
case "CN":
return true;
default:
return false;
}
} }
public static boolean isNationalAccountIdRequired(String countryCode) { public static boolean isNationalAccountIdRequired(String countryCode) {

View file

@ -41,6 +41,10 @@ public class CountryUtil {
return countries.stream().map(country -> country.code).collect(Collectors.toList()); return countries.stream().map(country -> country.code).collect(Collectors.toList());
} }
public static Country getCountry(String code) {
return getCountries(List.of(code)).get(0);
}
public static List<Country> getCountries(List<String> codes) { public static List<Country> getCountries(List<String> codes) {
List<Country> countries = new ArrayList<Country>(); List<Country> countries = new ArrayList<Country>();
for (String code : codes) { for (String code : codes) {

View file

@ -40,6 +40,16 @@ public final class MoneyGramAccount extends PaymentAccount {
@Nullable @Nullable
private Country country; private Country country;
private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of(
PaymentAccountFormField.FieldId.ACCOUNT_NAME,
PaymentAccountFormField.FieldId.COUNTRY,
PaymentAccountFormField.FieldId.STATE,
PaymentAccountFormField.FieldId.HOLDER_NAME,
PaymentAccountFormField.FieldId.EMAIL,
PaymentAccountFormField.FieldId.TRADE_CURRENCIES,
PaymentAccountFormField.FieldId.SALT
);
public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of( public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of(
new FiatCurrency("AED"), new FiatCurrency("AED"),
new FiatCurrency("ARS"), new FiatCurrency("ARS"),
@ -108,7 +118,7 @@ public final class MoneyGramAccount extends PaymentAccount {
@Override @Override
public @NotNull List<PaymentAccountFormField.FieldId> getInputFieldIds() { public @NotNull List<PaymentAccountFormField.FieldId> getInputFieldIds() {
throw new RuntimeException("Not implemented"); return INPUT_FIELD_IDS;
} }
@Nullable @Nullable
@ -145,7 +155,14 @@ public final class MoneyGramAccount extends PaymentAccount {
return ((MoneyGramAccountPayload) paymentAccountPayload).getState(); return ((MoneyGramAccountPayload) paymentAccountPayload).getState();
} }
public void setState(String email) { public void setState(String state) {
((MoneyGramAccountPayload) paymentAccountPayload).setState(email); ((MoneyGramAccountPayload) paymentAccountPayload).setState(state);
}
@Override
protected PaymentAccountFormField getEmptyFormField(PaymentAccountFormField.FieldId fieldId) {
var field = super.getEmptyFormField(fieldId);
if (field.getId() == PaymentAccountFormField.FieldId.HOLDER_NAME) field.setLabel("Full name (first, middle, last)");
return field;
} }
} }

View file

@ -19,6 +19,7 @@ package bisq.core.payment;
import bisq.core.api.model.PaymentAccountForm; import bisq.core.api.model.PaymentAccountForm;
import bisq.core.api.model.PaymentAccountFormField; import bisq.core.api.model.PaymentAccountFormField;
import bisq.core.locale.BankUtil;
import bisq.core.locale.Country; import bisq.core.locale.Country;
import bisq.core.locale.CountryUtil; import bisq.core.locale.CountryUtil;
import bisq.core.locale.CurrencyUtil; import bisq.core.locale.CurrencyUtil;
@ -379,15 +380,15 @@ public abstract class PaymentAccount implements PersistablePayload {
checkNotEmpty(value); checkNotEmpty(value);
break; break;
case COUNTRY: case COUNTRY:
List<Country> supportedCountries = ((CountryBasedPaymentAccount) this).getSupportedCountries(); if (this instanceof CountryBasedPaymentAccount) {
if (supportedCountries == null || supportedCountries.isEmpty()) { List<Country> supportedCountries = ((CountryBasedPaymentAccount) this).getSupportedCountries();
if (!CountryUtil.findCountryByCode(value).isPresent()) throw new IllegalArgumentException("Invalid country code: " + value); if (supportedCountries != null && !supportedCountries.isEmpty()) {
} else { List<String> supportedCountryCodes = CountryUtil.getCountryCodes(supportedCountries);
System.out.println("BUT WE SUPPORT THESE COUNTRIES!"); if (!supportedCountryCodes.contains(value)) throw new IllegalArgumentException("Country is not supported by " + getPaymentMethod().getId() + ": " + value);
System.out.println(supportedCountries); return;
List<String> supportedCountryCodes = CountryUtil.getCountryCodes(supportedCountries); }
if (!supportedCountryCodes.contains(value)) throw new IllegalArgumentException("Country is not supported by " + getPaymentMethod().getId() + ": " + value);
} }
if (!CountryUtil.findCountryByCode(value).isPresent()) throw new IllegalArgumentException("Invalid country code: " + value);
break; break;
case EMAIL: case EMAIL:
checkNotEmpty(value); checkNotEmpty(value);
@ -414,7 +415,7 @@ public abstract class PaymentAccount implements PersistablePayload {
case IFSC: case IFSC:
throw new IllegalArgumentException("Not implemented"); throw new IllegalArgumentException("Not implemented");
case INTERMEDIARY_COUNTRY_CODE: case INTERMEDIARY_COUNTRY_CODE:
if (!CountryUtil.findCountryByCode(value).isPresent()) throw new IllegalArgumentException("Invalid country code: " + value); // TODO: value must be within supported countries unless all countries supported if (!CountryUtil.findCountryByCode(value).isPresent()) throw new IllegalArgumentException("Invalid country code: " + value);
break; break;
case MOBILE_NR: case MOBILE_NR:
throw new IllegalArgumentException("Not implemented"); throw new IllegalArgumentException("Not implemented");
@ -440,7 +441,17 @@ public abstract class PaymentAccount implements PersistablePayload {
case SPECIAL_INSTRUCTIONS: case SPECIAL_INSTRUCTIONS:
break; break;
case STATE: case STATE:
throw new IllegalArgumentException("Not implemented"); String countryCode = form.getValue(PaymentAccountFormField.FieldId.COUNTRY);
System.out.println("BACKEND RECEIVED STATE COUNTRY CODE: " + countryCode);
System.out.println("BACKEND RECEIVED STATE: " + value);
boolean isStateRequired = BankUtil.isStateRequired(countryCode);
System.out.println("IS STATE REQUIRED :" + isStateRequired);
if (value == null || value.isEmpty()) {
if (isStateRequired) throw new IllegalArgumentException("Must provide state for country " + countryCode);
} else {
if (!isStateRequired) throw new IllegalArgumentException("Must not provide state for country " + countryCode);
}
break;
case TRADE_CURRENCIES: case TRADE_CURRENCIES:
checkNotEmpty(value); checkNotEmpty(value);
List<String> currencyCodes = commaDelimitedCodesToList.apply(value); List<String> currencyCodes = commaDelimitedCodesToList.apply(value);
@ -497,7 +508,7 @@ public abstract class PaymentAccount implements PersistablePayload {
case BANK_ACCOUNT_TYPE: case BANK_ACCOUNT_TYPE:
throw new IllegalArgumentException("Not implemented"); throw new IllegalArgumentException("Not implemented");
case BANK_ADDRESS: case BANK_ADDRESS:
field.setComponent(PaymentAccountFormField.Component.TEXT); field.setComponent(PaymentAccountFormField.Component.TEXTAREA);
field.setLabel("Receiving Bank address"); field.setLabel("Receiving Bank address");
break; break;
case BANK_BRANCH: case BANK_BRANCH:
@ -531,7 +542,7 @@ public abstract class PaymentAccount implements PersistablePayload {
field.setLabel("Account No. (or IBAN)"); field.setLabel("Account No. (or IBAN)");
break; break;
case BENEFICIARY_ADDRESS: case BENEFICIARY_ADDRESS:
field.setComponent(PaymentAccountFormField.Component.TEXT); field.setComponent(PaymentAccountFormField.Component.TEXTAREA);
field.setLabel("Beneficiary address"); field.setLabel("Beneficiary address");
break; break;
case BENEFICIARY_CITY: case BENEFICIARY_CITY:
@ -561,7 +572,7 @@ public abstract class PaymentAccount implements PersistablePayload {
case COUNTRY: case COUNTRY:
field.setComponent(PaymentAccountFormField.Component.SELECT_ONE); field.setComponent(PaymentAccountFormField.Component.SELECT_ONE);
field.setLabel("Country"); field.setLabel("Country");
field.setSupportedCountries(((CountryBasedPaymentAccount) this).getSupportedCountries()); if (this instanceof CountryBasedPaymentAccount) field.setSupportedCountries(((CountryBasedPaymentAccount) this).getSupportedCountries());
break; break;
case EMAIL: case EMAIL:
field.setComponent(PaymentAccountFormField.Component.TEXT); field.setComponent(PaymentAccountFormField.Component.TEXT);
@ -573,7 +584,7 @@ public abstract class PaymentAccount implements PersistablePayload {
field.setLabel("Email or mobile number"); field.setLabel("Email or mobile number");
break; break;
case EXTRA_INFO: case EXTRA_INFO:
field.setComponent(PaymentAccountFormField.Component.TEXT); field.setComponent(PaymentAccountFormField.Component.TEXTAREA);
field.setLabel("Optional additional information"); field.setLabel("Optional additional information");
break; break;
case HOLDER_ADDRESS: case HOLDER_ADDRESS:
@ -595,7 +606,7 @@ public abstract class PaymentAccount implements PersistablePayload {
case IFSC: case IFSC:
throw new IllegalArgumentException("Not implemented"); throw new IllegalArgumentException("Not implemented");
case INTERMEDIARY_ADDRESS: case INTERMEDIARY_ADDRESS:
field.setComponent(PaymentAccountFormField.Component.TEXT); field.setComponent(PaymentAccountFormField.Component.TEXTAREA);
field.setLabel("Intermediary Bank address"); field.setLabel("Intermediary Bank address");
break; break;
case INTERMEDIARY_BRANCH: case INTERMEDIARY_BRANCH:
@ -641,7 +652,10 @@ public abstract class PaymentAccount implements PersistablePayload {
field.setLabel("Special instructions"); field.setLabel("Special instructions");
break; break;
case STATE: case STATE:
throw new IllegalArgumentException("Not implemented"); field.setComponent(PaymentAccountFormField.Component.TEXT);
field.setLabel("State/Province/Region");
field.setRequiredForCountries(CountryUtil.getCountryCodes(BankUtil.getAllStateRequiredCountries()));
break;
case TRADE_CURRENCIES: case TRADE_CURRENCIES:
field.setComponent(PaymentAccountFormField.Component.SELECT_MULTIPLE); field.setComponent(PaymentAccountFormField.Component.SELECT_MULTIPLE);
field.setLabel("Supported currencies"); field.setLabel("Supported currencies");

View file

@ -334,7 +334,8 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme
CLEAR_X_CHANGE_ID, CLEAR_X_CHANGE_ID,
SWIFT_ID, SWIFT_ID,
F2F_ID, F2F_ID,
STRIKE_ID); STRIKE_ID,
MONEY_GRAM_ID);
return paymentMethods.stream().filter(paymentMethod -> paymentMethodIds.contains(paymentMethod.getId())).collect(Collectors.toList()); return paymentMethods.stream().filter(paymentMethod -> paymentMethodIds.contains(paymentMethod.getId())).collect(Collectors.toList());
} }

View file

@ -2081,6 +2081,7 @@ message PaymentAccountForm {
SWIFT = 4; SWIFT = 4;
F2F = 5; F2F = 5;
STRIKE = 6; STRIKE = 6;
MONEY_GRAM = 7;
} }
FormId id = 1; FormId id = 1;
repeated PaymentAccountFormField fields = 2; repeated PaymentAccountFormField fields = 2;
@ -2149,8 +2150,9 @@ message PaymentAccountFormField {
} }
enum Component { enum Component {
TEXT = 0; TEXT = 0;
SELECT_ONE = 1; TEXTAREA = 1;
SELECT_MULTIPLE = 2; SELECT_ONE = 2;
SELECT_MULTIPLE = 3;
} }
FieldId id = 1; FieldId id = 1;
Component component = 2; Component component = 2;
@ -2163,4 +2165,5 @@ message PaymentAccountFormField {
repeated Country supported_countries = 9; repeated Country supported_countries = 9;
repeated Country supported_sepa_euro_countries = 10; repeated Country supported_sepa_euro_countries = 10;
repeated Country supported_sepa_non_euro_countries = 11; repeated Country supported_sepa_non_euro_countries = 11;
repeated string required_for_countries = 12;
} }