diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SubscriptionController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SubscriptionController.java index 784741205..b43331422 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SubscriptionController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/SubscriptionController.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Strings; import com.stripe.model.Invoice; import com.stripe.model.InvoiceLineItem; -import com.stripe.model.Product; import com.stripe.model.Subscription; import io.dropwizard.auth.Auth; import java.math.BigDecimal; @@ -33,6 +32,7 @@ import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; +import javax.validation.constraints.NotEmpty; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -190,6 +190,22 @@ public class SubscriptionController { .thenApply(setupIntent -> Response.ok(new CreatePaymentMethodResponse(setupIntent.getClientSecret())).build()); } + @Timed + @POST + @Path("/{subscriberId}/default_payment_method/{paymentMethodId}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public CompletableFuture setDefaultPaymentMethod( + @Auth Optional authenticatedAccount, + @PathParam("subscriberId") String subscriberId, + @PathParam("paymentMethodId") @NotEmpty String paymentMethodId) { + RequestData requestData = RequestData.process(authenticatedAccount, subscriberId, clock); + return subscriptionManager.get(requestData.subscriberUser, requestData.hmac) + .thenApply(this::requireRecordFromGetResult) + .thenCompose(record -> stripeManager.setDefaultPaymentMethodForCustomer(record.customerId, paymentMethodId)) + .thenApply(customer -> Response.ok().build()); + } + public static class SetSubscriptionLevelSuccessResponse { private final long level; @@ -587,8 +603,7 @@ public class SubscriptionController { } InvoiceLineItem subscriptionLineItem = subscriptionLineItems.stream().findAny().get(); - Product product = subscriptionLineItem.getPrice().getProductObject(); - return CompletableFuture.completedFuture(new Receipt( + return stripeManager.getProductForPrice(subscriptionLineItem.getPrice().getId()).thenApply(product -> new Receipt( Instant.ofEpochSecond(subscriptionLineItem.getPeriod().getEnd()).plus(config.getBadgeGracePeriod()), stripeManager.getLevelForProduct(product), subscriptionLineItem.getId())); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/stripe/StripeManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/stripe/StripeManager.java index 525d8fedc..42f590eb9 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/stripe/StripeManager.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/stripe/StripeManager.java @@ -19,6 +19,8 @@ import com.stripe.model.SubscriptionItem; import com.stripe.net.RequestOptions; import com.stripe.param.CustomerCreateParams; import com.stripe.param.CustomerRetrieveParams; +import com.stripe.param.CustomerUpdateParams; +import com.stripe.param.CustomerUpdateParams.InvoiceSettings; import com.stripe.param.InvoiceListParams; import com.stripe.param.PriceRetrieveParams; import com.stripe.param.SetupIntentCreateParams; @@ -107,6 +109,23 @@ public class StripeManager { }, executor); } + public CompletableFuture setDefaultPaymentMethodForCustomer(String customerId, String paymentMethodId) { + return CompletableFuture.supplyAsync(() -> { + Customer customer = new Customer(); + customer.setId(customerId); + CustomerUpdateParams params = CustomerUpdateParams.builder() + .setInvoiceSettings(InvoiceSettings.builder() + .setDefaultPaymentMethod(paymentMethodId) + .build()) + .build(); + try { + return customer.update(params, commonOptions()); + } catch (StripeException e) { + throw new CompletionException(e); + } + }, executor); + } + public CompletableFuture createSetupIntent(String customerId) { return CompletableFuture.supplyAsync(() -> { SetupIntentCreateParams params = SetupIntentCreateParams.builder() @@ -278,7 +297,6 @@ public class StripeManager { .setCreated(InvoiceListParams.Created.builder() .setGte(now.minus(Duration.ofDays(90)).getEpochSecond()) .build()) - .addExpand("lines.data.price.product") .build(); try { ArrayList invoices = Lists.newArrayList(Invoice.list(params, commonOptions())