1

I'm attempting to create a monthly subscription with free 7 day trial, but after the trial period the payment fails.

EDIT: It appears to fail because the customer has no default payment method, so despite the payment method being attached to customer, it is not set to default. I can not figure out how to set it to default payment method.

I am setting ConfirmCardSetup in frontend javascript, which I believe is tying the card to the customer. And I am creating the customer, and starting the subscription/trial in my backend django view.

I have found this in Stripe documentation:

"To use this PaymentMethod as the default for invoice or subscription payments, set invoice_settings.default_payment_method, on the Customer to the PaymentMethod’s ID."

but I am unsure how to get the Payment Method ID from front end, and use it to update the customer.

Here is my subscription create view:

class SubscriptionCreateView(View, SubscriptionCancellationMixin, 
                         CustomerMixin, StripeReferenceMixin, FetchCouponMixin):

"""View to Create subscription and sync with stripe"""
def post(self, request, *args, **kwargs):
    context = {}
    subscription_payload = {}
    price_id = request.POST.get('price_id')
    coupon_id = request.POST.get('coupon_id')
    customer = self.fetch_customer(request.user)

    #Retrieve stripe coupon id or None
    if coupon_id != '':
        stripe_coupon_id, is_valid = self.is_coupon_valid(coupon_id)
        #Set payload to create a subscription
        subscription_payload['coupon'] = stripe_coupon_id
        #Send invalid coupon response
        if not is_valid:
            context['invalid_coupon'] = True
            response = JsonResponse(context)
            response.status_code = 400
            return response

    if not customer:
        customer = self.stripe.Customer.create(
                email=request.user.email
        )
    try:
        now = int(time.time())
        # Cancel the previous subscription.
        self.cancel_subscription(customer)
        #Create a new subscription
        subscription_payload.update({
            'customer':customer.id,
            'items':  [{
                    'price': price_id,
                },
                ],  
            'trial_end': now +30,
            
        },
            )

        #create a setup intent
        setup_intent = self.stripe.SetupIntent.create(
             payment_method_types=["card"],

             customer=customer.id,
        )
        subscription = self.stripe.Subscription.create(**subscription_payload)


        # Sync the Stripe API return data to the database,
        # this way we don't need to wait for a webhook-triggered sync
        Subscription.sync_from_stripe_data(subscription)
        request.session['created_subscription_id'] = subscription.get('id')

        # Note we're sending the Subscription's
        # latest invoice and client secret
        # to the front end to confirm the payment
        context['subscriptionId'] = subscription.id
        context['clientSecret'] = setup_intent['client_secret']

    except Exception as e:
        response = JsonResponse({})
        response.status_code = 400
        return response

    return JsonResponse(context)

And here's the relevant javascript!

var stripe = Stripe($('#public-key').val());
var elements = stripe.elements();
var style = {
   base: {
     color: "#32325d",
     }
   };

var card = elements.create("card", { style: style });
card.mount("#card-element");

//Capture modal payment button click
$(document).on('click', '#submit-payment-btn', function (e) {
e.preventDefault();
//Send an ajax call to backend to create a subscription
$(this).prop('disabled', true);
let spinnerHtml = '<div class="spinner-border text-light"></div>';
let origButtonHtml = $(this).html();
$(this).html(spinnerHtml);

$.ajax({
url: $(this).data('create-sub-url'),
type: 'POST',
data: {
  csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val(),
  'price_id': $(this).data('price-id'),
  'coupon_id': $("#coupon_id").val()
},
success: function (result) {
  if(!result.clientSecret)
  {
      console.log("result not okay")
      window.location.href = '/'
  }
  else{

    $('#client-secret').val(result.clientSecret);
    // Confirm payment intent.
    console.log('set up confirmed');
    stripe.confirmCardSetup(result.clientSecret, {
      payment_method: {
        card: card,
        billing_details: {
          name: $('#cardholder-name').val(),
        },
      }
    }).then((result) => {
      if (result.error) {
        alert('Payment failed:'. result.error.message);
      } else {
        window.location.href = '/'
        
      }
    });
  }

},
error: function (result){
  $('#submit-payment-btn').html(origButtonHtml);
  if(result.responseJSON.invalid_coupon)
  {
    if($(".coupon-error").length == 0)
      $('.coupon-div').append('<p class="coupon-error text-center" style="color:red">Invalid coupon code</p>')
  }
  else{
    $('#payment-modal').modal('hide');
    alert('Something Went Wrong!')
  }
 }
 }
 );
 })

Thanks for any help or point in the right direction! I've been trying to solve this for hours!

LBJ33
  • 425
  • 11
  • 29
  • What error messages do you get and where? Are there any log entries with more details? – pts Dec 26 '22 at 18:24
  • This looks like a question Stripe support is paid to answer. You may want to contact them. – pts Dec 26 '22 at 18:26
  • 1
    Thanks, I will attempt to contact Stripe support as well! Didn't think about that as I'm sure it's a programming issue on my end, but they can probably help with that as well. I don't actually see any error. Although combing through the payment failed event, it seems although there is a payment method and a payment intent, there is no default payment method for the customer. So I will have to try and figure out how to set the payment method as default I guess! – LBJ33 Dec 27 '22 at 02:16
  • 1
    Stripe has been unable to help thus far, but I think I have it narrowed down. It seems payment is failing as it is attempting to charge the default payment method, but the customer does not have a default payment method. The ConfirmCardSetup appears to add the payment method to customer, but does not set it to default payment method for some reason. – LBJ33 Dec 27 '22 at 20:17

0 Answers0