stripeZeroDecimalCurrencies = Set.of("bif", "clp", "djf", "gnf", "jpy", "kmf", "krw",
+ "mga", "pyg", "rwf", "vnd", "vuv", "xaf", "xof", "xpf");
+
+
+ /**
+ * Takes an amount as configured and turns it into an amount as API clients (and Stripe) expect to see it. For
+ * instance, {@code USD 4.99} return {@code 499}, while {@code JPY 500} returns {@code 500}.
+ *
+ *
+ * Stripe appears to only support zero- and two-decimal currencies, but also has some backwards compatibility issues
+ * with 0 decimal currencies, so this is not to any ISO standard but rather directly from Stripe's API doc page.
+ */
+ public static BigDecimal convertConfiguredAmountToApiAmount(String currency, BigDecimal configuredAmount) {
+ if (stripeZeroDecimalCurrencies.contains(currency.toLowerCase(Locale.ROOT))) {
+ return configuredAmount;
+ }
+
+ return configuredAmount.scaleByPowerOfTen(2);
+ }
+
+ /**
+ * @see org.whispersystems.textsecuregcm.subscriptions.SubscriptionCurrencyUtil#convertConfiguredAmountToApiAmount(String,
+ * BigDecimal)
+ */
+ public static BigDecimal convertConfiguredAmountToStripeAmount(String currency, BigDecimal configuredAmount) {
+ return convertConfiguredAmountToApiAmount(currency, configuredAmount);
+ }
+
+ /**
+ * Braintree’s API expects amounts in a currency’s primary unit (e.g. USD 4.99)
+ *
+ * @see org.whispersystems.textsecuregcm.subscriptions.SubscriptionCurrencyUtil#convertConfiguredAmountToApiAmount(String,
+ * BigDecimal)
+ */
+ static BigDecimal convertBraintreeAmountToApiAmount(final String currency, final BigDecimal amount) {
+ return convertConfiguredAmountToApiAmount(currency, amount);
+ }
+}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessor.java b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessor.java
index 81e4a6b37..a76dc8593 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessor.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessor.java
@@ -36,7 +36,7 @@ public enum SubscriptionProcessor {
private final byte id;
SubscriptionProcessor(int id) {
- if (id > 256) {
+ if (id > 255) {
throw new IllegalArgumentException("ID must fit in one byte: " + id);
}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessorManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessorManager.java
index d26710ad9..71fd6f91d 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessorManager.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/SubscriptionProcessorManager.java
@@ -5,13 +5,16 @@
package org.whispersystems.textsecuregcm.subscriptions;
+import java.math.BigDecimal;
import java.time.Instant;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import javax.annotation.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public interface SubscriptionProcessorManager {
-
SubscriptionProcessor getProcessor();
boolean supportsPaymentMethod(PaymentMethod paymentMethod);
@@ -26,6 +29,32 @@ public interface SubscriptionProcessorManager {
CompletableFuture createPaymentMethodSetupToken(String customerId);
+
+ /**
+ * @param customerId
+ * @param paymentMethodToken a processor-specific token necessary
+ * @param currentSubscriptionId (nullable) an active subscription ID, in case it needs an explicit update
+ * @return
+ */
+ CompletableFuture setDefaultPaymentMethodForCustomer(String customerId, String paymentMethodToken,
+ @Nullable String currentSubscriptionId);
+
+ CompletableFuture