Add `paymentMethod` and `paymentProcessing` fields to `GET /v1/subscription/{subscriberId}` endpoint
This commit is contained in:
parent
e1aa734c40
commit
207ae6129b
|
@ -394,6 +394,7 @@ public class SubscriptionController {
|
|||
return switch (paymentMethod) {
|
||||
case CARD, SEPA_DEBIT -> stripeManager;
|
||||
case PAYPAL -> braintreeManager;
|
||||
case UNKNOWN -> throw new BadRequestException("Invalid payment method");
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -886,7 +887,7 @@ public class SubscriptionController {
|
|||
|
||||
public record Subscription(long level, Instant billingCycleAnchor, Instant endOfCurrentPeriod, boolean active,
|
||||
boolean cancelAtPeriodEnd, String currency, BigDecimal amount, String status,
|
||||
SubscriptionProcessor processor) {
|
||||
SubscriptionProcessor processor, PaymentMethod paymentMethod, boolean paymentProcessing) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -919,7 +920,9 @@ public class SubscriptionController {
|
|||
subscriptionInformation.price().currency(),
|
||||
subscriptionInformation.price().amount(),
|
||||
subscriptionInformation.status().getApiValue(),
|
||||
manager.getProcessor()),
|
||||
manager.getProcessor(),
|
||||
subscriptionInformation.paymentMethod(),
|
||||
subscriptionInformation.paymentProcessing()),
|
||||
subscriptionInformation.chargeFailure()
|
||||
)).build()));
|
||||
});
|
||||
|
|
|
@ -426,12 +426,17 @@ public class BraintreeManager implements SubscriptionProcessorManager {
|
|||
final Instant anchor = subscription.getFirstBillingDate().toInstant();
|
||||
final Instant endOfCurrentPeriod = subscription.getBillingPeriodEndDate().toInstant();
|
||||
|
||||
final ChargeFailure chargeFailure = getLatestTransactionForSubscription(subscription).map(transaction -> {
|
||||
if (getPaymentStatus(transaction.getStatus()).equals(PaymentStatus.SUCCEEDED)) {
|
||||
return null;
|
||||
boolean paymentProcessing = false;
|
||||
ChargeFailure chargeFailure = null;
|
||||
|
||||
final Optional<Transaction> latestTransaction = getLatestTransactionForSubscription(subscription);
|
||||
|
||||
if (latestTransaction.isPresent()){
|
||||
paymentProcessing = isPaymentProcessing(latestTransaction.get().getStatus());
|
||||
if (!getPaymentStatus(latestTransaction.get().getStatus()).equals(PaymentStatus.SUCCEEDED)) {
|
||||
chargeFailure = createChargeFailure(latestTransaction.get());
|
||||
}
|
||||
return createChargeFailure(transaction);
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
return new SubscriptionInformation(
|
||||
new SubscriptionPrice(plan.getCurrencyIsoCode().toUpperCase(Locale.ROOT),
|
||||
|
@ -442,11 +447,25 @@ public class BraintreeManager implements SubscriptionProcessorManager {
|
|||
Subscription.Status.ACTIVE == subscription.getStatus(),
|
||||
!subscription.neverExpires(),
|
||||
getSubscriptionStatus(subscription.getStatus()),
|
||||
latestTransaction.map(this::getPaymentMethodFromTransaction).orElse(PaymentMethod.PAYPAL),
|
||||
paymentProcessing,
|
||||
chargeFailure
|
||||
);
|
||||
}, executor);
|
||||
}
|
||||
|
||||
private PaymentMethod getPaymentMethodFromTransaction(Transaction transaction) {
|
||||
if (transaction.getPayPalDetails() != null) {
|
||||
return PaymentMethod.PAYPAL;
|
||||
}
|
||||
logger.error("Unexpected payment method from Braintree: {}, transaction id {}", transaction.getPaymentInstrumentType(), transaction.getId());
|
||||
return PaymentMethod.UNKNOWN;
|
||||
}
|
||||
|
||||
private static boolean isPaymentProcessing(final Transaction.Status status) {
|
||||
return status == Transaction.Status.SETTLEMENT_PENDING;
|
||||
}
|
||||
|
||||
private ChargeFailure createChargeFailure(Transaction transaction) {
|
||||
|
||||
final String code;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package org.whispersystems.textsecuregcm.subscriptions;
|
||||
|
||||
public enum PaymentMethod {
|
||||
UNKNOWN,
|
||||
/**
|
||||
* A credit card or debit card, including those from Apple Pay and Google Pay
|
||||
*/
|
||||
|
|
|
@ -67,10 +67,12 @@ import javax.ws.rs.WebApplicationException;
|
|||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.textsecuregcm.util.Conversions;
|
||||
|
||||
public class StripeManager implements SubscriptionProcessorManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(StripeManager.class);
|
||||
private static final String METADATA_KEY_LEVEL = "level";
|
||||
|
||||
private final StripeClient stripeClient;
|
||||
|
@ -483,17 +485,30 @@ public class StripeManager implements SubscriptionProcessorManager {
|
|||
return getPriceForSubscription(subscription).thenCompose(price ->
|
||||
getLevelForPrice(price).thenApply(level -> {
|
||||
ChargeFailure chargeFailure = null;
|
||||
boolean paymentProcessing = false;
|
||||
PaymentMethod paymentMethod = null;
|
||||
|
||||
if (subscription.getLatestInvoiceObject() != null && subscription.getLatestInvoiceObject().getChargeObject() != null &&
|
||||
(subscription.getLatestInvoiceObject().getChargeObject().getFailureCode() != null || subscription.getLatestInvoiceObject().getChargeObject().getFailureMessage() != null)) {
|
||||
Charge charge = subscription.getLatestInvoiceObject().getChargeObject();
|
||||
Charge.Outcome outcome = charge.getOutcome();
|
||||
chargeFailure = new ChargeFailure(
|
||||
if (subscription.getLatestInvoiceObject() != null) {
|
||||
final Invoice invoice = subscription.getLatestInvoiceObject();
|
||||
paymentProcessing = "open".equals(invoice.getStatus());
|
||||
|
||||
if (invoice.getChargeObject() != null) {
|
||||
final Charge charge = invoice.getChargeObject();
|
||||
if (charge.getFailureCode() != null || charge.getFailureMessage() != null) {
|
||||
Charge.Outcome outcome = charge.getOutcome();
|
||||
chargeFailure = new ChargeFailure(
|
||||
charge.getFailureCode(),
|
||||
charge.getFailureMessage(),
|
||||
outcome != null ? outcome.getNetworkStatus() : null,
|
||||
outcome != null ? outcome.getReason() : null,
|
||||
outcome != null ? outcome.getType() : null);
|
||||
}
|
||||
|
||||
if (charge.getPaymentMethodDetails() != null
|
||||
&& charge.getPaymentMethodDetails().getType() != null) {
|
||||
paymentMethod = getPaymentMethodFromStripeString(charge.getPaymentMethodDetails().getType(), invoice.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new SubscriptionInformation(
|
||||
|
@ -504,11 +519,24 @@ public class StripeManager implements SubscriptionProcessorManager {
|
|||
Objects.equals(subscription.getStatus(), "active"),
|
||||
subscription.getCancelAtPeriodEnd(),
|
||||
getSubscriptionStatus(subscription.getStatus()),
|
||||
paymentMethod,
|
||||
paymentProcessing,
|
||||
chargeFailure
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
||||
private static PaymentMethod getPaymentMethodFromStripeString(final String paymentMethodString, final String invoiceId) {
|
||||
return switch (paymentMethodString) {
|
||||
case "sepa_debit" -> PaymentMethod.SEPA_DEBIT;
|
||||
case "card" -> PaymentMethod.CARD;
|
||||
default -> {
|
||||
logger.error("Unexpected payment method from Stripe: {}, invoice id: {}", paymentMethodString, invoiceId);
|
||||
yield PaymentMethod.UNKNOWN;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Subscription getSubscription(Object subscriptionObj) {
|
||||
if (!(subscriptionObj instanceof final Subscription subscription)) {
|
||||
throw new IllegalArgumentException("invalid subscription object: " + subscriptionObj.getClass().getName());
|
||||
|
|
|
@ -144,8 +144,8 @@ public interface SubscriptionProcessorManager {
|
|||
|
||||
record SubscriptionInformation(SubscriptionPrice price, long level, Instant billingCycleAnchor,
|
||||
Instant endOfCurrentPeriod, boolean active, boolean cancelAtPeriodEnd,
|
||||
SubscriptionStatus status,
|
||||
ChargeFailure chargeFailure) {
|
||||
SubscriptionStatus status, PaymentMethod paymentMethod, boolean paymentProcessing,
|
||||
@Nullable ChargeFailure chargeFailure) {
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue