Benutzer kann ein Abonnementprodukt nach der Kündigung nicht erneut erwerben

I’ve got an odd problem cropped up here with a subscriber.

They have no active subscriptions in under the Billing section;

In Stripe it shows as cancelled;

image

yet they cannot resubscribe… says already purchased;

image

Have I set something up incorrectly?

1 „Gefällt mir“

That looks like you might have your webhook endpoint improperly configured. When the subscription period ends, Stripe sends a webhook which the plugin uses to remove group membership, and remove the user from being an existing customer on that product (which allows the user to purchase again).

You’ll need to make sure this is configured per the OP here: Discourse Subscriptions

One way you to confirm from your server:

./launcher enter app
rails c
u = User.find_by_username(<username>)
c = DiscourseSubscriptions::Customer.where(user_id: u.id)
subscription = DiscourseSubscriptions::Subscription.where(customer_id: c.customer_id)

Be sure to replace <username> with the actual username of the user.

If subscription returns [], there’s another issue going on. But if it returns a value, that likely confirms the missing webhook.

To delete the DiscourseSubscriptions::Subscription entry so the user can purchase the product again:

Make sure subscription has only one value by running subscription.count. If the value returned is greater than 1, you’ll have to do a bit more digging to make sure you’re deleting the correct subscription instance. If you delete the wrong one, your subscriptions data will be in an inconsistent state and likely yield weird behavior.

Once you’ve confirmed there’s only one subscription, then you can run:

subscription.destroy_all

Keep in mind that subscription is the value returned from the initial set of queries we ran in the Rails console.

Hope that helps!

2 „Gefällt mir“

Thanks @justin

• got to the last line subscription and ran it… returned this;

NoMethodError: undefined method customer_id' for #<DiscourseSubscriptions::Customer::ActiveRecord_Relation:0x000055be473772f0> from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.3.2/lib/active_record/relation/delegation.rb:110:in method_missing’

• Checked Stripe webhooks and it’s pointed to https://./s/hooks

• Events sent to webhook;

  • subscription_schedule.updated
    
  • subscription_schedule.expiring
    
  • subscription_schedule.created
    
  • subscription_schedule.canceled
    

• Stripe webhook log has one entry from setup date which looks to be establishing the events supported.

• I have an event entry in Stripe that is a cancellation of a subscription, but… the line entry says (effectively) “[subscription was canceled]” however when I click into the event, it says the event type is customer.subscription.deleted … which I notice is not listed in my webhooks event list.

Could the above be the problem?

1 „Gefällt mir“

Looks like the line should be DiscourseSubscriptions::Subscription instead of ::Customer. Try that and see what you get!

1 „Gefällt mir“

[2] pry(main)> c = DiscourseSubscriptions::Subscription.where(user_id: u.id)
=> #DiscourseSubscriptions::Subscription::ActiveRecord_Relation:0x8020
[3] pry(main)> subscription = DiscourseSubscriptions::Subscription.where(customer_id: c.customer_id)
NoMethodError: undefined method customer_id' for #<DiscourseSubscriptions::Subscription::ActiveRecord_Relation:0x000055ec51164ca0> from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.3.2/lib/active_record/relation/delegation.rb:110:in method_missing’

1 „Gefällt mir“

Sorry, I misunderstood where this was happening.

Try this instead:

./launcher enter app
rails c
u = User.find_by_username(<username>)
c = DiscourseSubscriptions::Customer.find_by(user_id: u.id)
subscription = DiscourseSubscriptions::Subscription.where(customer_id: c[:customer_id])
1 „Gefällt mir“

Ah…

[3] pry(main)> subscription = DiscourseSubscriptions::Subscription.where(customer_id: c[:customer_id])
=>

1 „Gefällt mir“

Do you think the lack of subscription data has anything to do with the customer.subscription.deleted event being missing?

Is there anything I should explore next at this point?

I’m particularly interested in focusing on why the subscription page shows “purchased” while the active subscriptions section shows no active subs… is there some other place in the database where sub info is stored which might be cleared / empty under the active subs section but somehow a “purchased” boolean is still set to true somewhere … or something like that?

1 „Gefällt mir“

Is there anything else to try here?

1 „Gefällt mir“

Make sure in Stripe the purchase is fully cancelled and not waiting to be cancelled at the end of the period. You can also look under the Admin → Plugins → Discourse Subscriptions → Subscriptions area and look for this user’s username. If they have a subscription listed there, you can cancel it immediately.

Without further looking into your Discourse instance, I’m not sure how much further I can help.

1 „Gefällt mir“

yeah it’s not active under subscriptions in the plugin area, and also not on stripe either… the only thing that indicates anything is still active is if the user goes to the subscription page, they see a little green “purchased” checkmark and “go to billing”.

image

If I go to billing as the user in question, nothing;

image

So my question is - what in the database triggers that green checkmark and can it be cleared?

If this list includes the Stripe product id as per here:

Then the front end will display it as purchased. You may need to dig around the console with these queries to find out where it’s located. I almost guarantee there’s a record hanging around there yet.

1 „Gefällt mir“

Ok, ich weiß, dass ich diesen Thread wieder aufgreife, aber 1.) das Problem wird weiterhin nicht gelöst, und 2.) ich hatte Zeit, mich wieder damit zu beschäftigen… es stellt sich heraus, dass ich ein Idiot war, der keine Anweisungen befolgen konnte. So habe ich herausgefunden, dass ich ein Dummkopf bin, und warum ich jetzt bereit bin, das zu lösen (mit etwas Hilfe).

Was ich schließlich getan habe, war, eine CSV-Datei von Stripe mit allen gekündigten Konten zu exportieren. Ich konzentrierte mich auf denselben Discourse-Benutzer, der oben in diesem Thread erwähnt wurde, der Abonnent war, gekündigt hatte, aber dann nicht wieder abonnieren konnte, weil die Abonnementseite als “gekauft” angezeigt wurde, obwohl seine Seite mit aktiven Abonnements keine Abonnements anzeigte. In den CSV-Daten wurde sein Datensatz als “gekündigt” mit den folgenden Daten angezeigt:

  • id (sub_JNWejdDo4qhLG5)
  • customer_id (cus_JmiMoqZNTzUNxt)
  • user_id (Discourse-Benutzer-ID 4981)

Dann habe ich mich mit dem App-Container verbunden, bin in die Ruby-Konsole gegangen und habe angefangen, herumzustochern. Zuerst habe ich nach seiner Kunden-ID in DiscourseSubscriptions::Customer gesucht und sie gefunden.

[3] pry(main)> DiscourseSubscriptions::Customer.where(customer_id: 'cus_JNWeiIWTs6YOwQ')
=> [#<DiscourseSubscriptions::Customer:0x000055db2d48eb40
  id: 16,
  customer_id: "cus_JNWeiIWTs6YOwQ",
  product_id: "prod_JJbwYnKz0T5Z9h",
  user_id: 3256,
  created_at: Tue, 27 Apr 2021 07:45:07.455275000 UTC +00:00,
  updated_at: Tue, 27 Apr 2021 07:45:07.455275000 UTC +00:00>]

Als Nächstes habe ich DiscourseSubscriptions::Subscription durchsucht, um zu sehen, ob dieser Benutzer Abonnements hatte, und es stellt sich heraus, ja, das hatte er;

[1] pry(main)> DiscourseSubscriptions::Subscription.where(external_id: 'sub_JNWejdDo4qhLG5')
=> [#<DiscourseSubscriptions::Subscription:0x000055854e1e1620
  id: 16,
  customer_id: 16,
  external_id: "sub_JNWejdDo4qhLG5",
  created_at: Tue, 27 Apr 2021 07:45:07.459681000 UTC +00:00,
  updated_at: Tue, 27 Apr 2021 07:45:07.459681000 UTC +00:00>]

Es scheint also, dass ich diesen Abonnementdatensatz einfach entfernen kann und alles reparieren kann… für diesen Benutzer. Tatsache ist, dass jeder gekündigte Benutzer, den ich in meinem CSV-Export überprüft habe, immer noch verbleibende Abonnements im System hatte. Offensichtlich gibt es eine Trennung irgendwo zwischen dem Stripe-Webhook und dem Abonnement-Plugin… ich weiß nur nicht wo/wie.

  • Erstens: Wie entferne ich sicher den Abonnementdatensatz für einen bestimmten Benutzer? Erklären Sie es mir, als wäre ich 5 Jahre alt. Ich bin an der Ruby-Konsolenaufforderung… wie stelle ich sicher, dass nur die Abonnementdaten des Zielbenutzers entfernt werden und ich nicht die Abonnementdaten aller lösche?

  • Zweitens: Wie behebe ich den Mechanismus des Webhooks für die Abonnementkündigung?

Ihre Hilfe wird sehr geschätzt!

UPDATE:

Ok, ich bin ein wenig weiter gekommen… ich habe herausgefunden, wie ich .delete_by verwenden kann, um nur Abonnementdaten für den Zielbenutzer zu entfernen.

[1] pry(main)> DiscourseSubscriptions::Subscription.delete_by(external_id: 'sub_JNWejdDo4qhLG5')
[2] pry(main)> DiscourseSubscriptions::Subscription.where(external_id: 'sub_JNWejdDo4qhLG5')
=> []

Der Kunden-Datensatz hat jedoch immer noch eine zugeordnete product_id;

[3] pry(main)> DiscourseSubscriptions::Customer.where(customer_id: 'cus_JNWeiIWTs6YOwQ')
=> [#<DiscourseSubscriptions::Customer:0x0000560ec18e4948
  id: 16,
  customer_id: "cus_JNWeiIWTs6YOwQ",
  product_id: "prod_JJbwYnKz0T5Z9h",
  user_id: 3256,
  created_at: Tue, 27 Apr 2021 07:45:07.455275000 UTC +00:00,
  updated_at: Tue, 27 Apr 2021 07:45:07.455275000 UTC +00:00>]

Das bedeutet, dass sie immer noch das grüne Häkchen sehen und sich nicht erneut anmelden können… also habe ich “destroy_all” auf das Customer-Objekt angewendet… und es hat funktioniert! Aber natürlich nur für diesen Benutzer…

[4] pry(main)> DiscourseSubscriptions::Customer.where(customer_id: 'cus_JNWeiIWTs6YOwQ').destroy_all
=> [#<DiscourseSubscriptions::Customer:0x0000560ec19770e0
  id: 16,
  customer_id: "cus_JNWeiIWTs6YOwQ",
  product_id: "prod_JJbwYnKz0T5Z9h",
  user_id: 3256,
  created_at: Tue, 27 Apr 2021 07:45:07.455275000 UTC +00:00,
  updated_at: Tue, 27 Apr 2021 07:45:07.455275000 UTC +00:00>]

Jetzt geht es nur noch darum, zu diagnostizieren, warum der Stripe-Webhook für gekündigte Abonnements nicht funktioniert.