Stripe Subscription使用stripe.Subscription.create函数在Django中不提供client_secret。

huangapple go评论93阅读模式
英文:

Stripe Subscription using stripe.Subscription.create function does not provide client_secret with Django

问题

以下是您要翻译的代码部分:

  1. As suggested [here][1], I am using stripe.Subscription.create function to create a subscription for the users in my Django DRM and expect to have a client secret that is associated with the subscription and the related payment_intent.
  2. However following is the error that I get :
  3. customer.clientsecret=stripe_subscription.latest_invoice.payment_intent.client_secret
  4. AttributeError: 'NoneType' object has no attribute 'client_secret'
  5. Below is the code that I am executing in the backend :
  6. stripe_customer = stripe.Customer.create(email=instance.email)
  7. customer.product = Product.objects.get(plan=0) # Free plan price id
  8. customer.stripe_customer_id = stripe_customer['id']
  9. stripe_subscription = stripe.Subscription.create(
  10. customer=customer.stripe_customer_id,
  11. items=[{"price": customer.product.stripe_plan_id},],
  12. payment_behavior='default_incomplete',
  13. payment_settings={'save_default_payment_method': 'on_subscription'},
  14. expand=['latest_invoice.payment_intent'],
  15. )
  16. customer.clientsecret=stripe_subscription.latest_invoice.payment_intent.client_secret

希望这有所帮助。如果您需要进一步的翻译或解释,请随时提出。

英文:

As suggested here , I am using stripe.Subscription.create function to create a subscription for the users in my Django DRM and expect to have a client secret that is associated with the subscription and the related payment_intent.

However following is the error that I get :

  1. customer.clientsecret=stripe_subscription.latest_invoice.payment_intent.client_secret

AttributeError: 'NoneType' object has no attribute 'client_secret'

Below is the code that I am executing in the backend :

  1. stripe_customer = stripe.Customer.create(email=instance.email)
  2. customer.product = Product.objects.get(plan=0) # Free plan price id
  3. customer.stripe_customer_id = stripe_customer['id']
  4. stripe_subscription = stripe.Subscription.create(
  5. customer=customer.stripe_customer_id,
  6. items=[{"price": customer.product.stripe_plan_id},],
  7. payment_behavior='default_incomplete',
  8. payment_settings={'save_default_payment_method': 'on_subscription'},
  9. expand=['latest_invoice.payment_intent'],
  10. )
  11. customer.clientsecret=stripe_subscription.latest_invoice.payment_intent.client_secret

Here below is the definition for Customer model :

  1. class Customer(models.Model):
  2. user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
  3. stripe_customer_id = models.CharField(max_length=40, default="")
  4. product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
  5. stripe_subscription_id = models.CharField(max_length=40, default="")
  6. clientsecret = models.CharField(max_length=80, default="")
  7. active = models.BooleanField(default=True)
  8. @property
  9. def get_created_date(self):
  10. subscription = stripe.Subscription.retrieve(self.stripe_subscription_id)
  11. return datetime.fromtimestamp(subscription.created)
  12. @property
  13. def get_next_billing_date(self):
  14. subscription = stripe.Subscription.retrieve(self.stripe_subscription_id)
  15. return datetime.fromtimestamp(subscription.current_period_end)
  16. def __str__(self):
  17. return self.user.username

The customers are created and associated with users when a new user signs up :

  1. def post_save_customer_create(sender, instance, created, *args, **kwargs):
  2. customer, created = Customer.objects.get_or_create(user=instance)
  3. ...

And here is the question : "How can I get a valid client_secret for the subscription that I create ?"

The value of the stripe_subscription is as below, and as you can see that latest_invoice is there, but payment_intent is null :

  1. {
  2. "application": null,
  3. "application_fee_percent": null,
  4. "automatic_tax": {
  5. "enabled": false
  6. },
  7. "billing_cycle_anchor": 1677632660,
  8. "billing_thresholds": null,
  9. "cancel_at": null,
  10. "cancel_at_period_end": false,
  11. "canceled_at": null,
  12. "collection_method": "charge_automatically",
  13. "created": 1677632660,
  14. "currency": "usd",
  15. "current_period_end": 1680311060,
  16. "current_period_start": 1677632660,
  17. "customer": "cus_NRX9a1XQtjWJPd",
  18. "days_until_due": null,
  19. "default_payment_method": null,
  20. "default_source": null,
  21. "default_tax_rates": [],
  22. "description": null,
  23. "discount": null,
  24. "ended_at": null,
  25. "id": "sub_1Mge5gLS6SANVcyCOTRj2dLw",
  26. "items": {
  27. "data": [
  28. {
  29. "billing_thresholds": null,
  30. "created": 1677632660,
  31. "id": "si_NRXAdvOPbsuzfz",
  32. "metadata": {},
  33. "object": "subscription_item",
  34. "plan": {
  35. "active": true,
  36. "aggregate_usage": null,
  37. "amount": 0,
  38. "amount_decimal": "0",
  39. "billing_scheme": "per_unit",
  40. "created": 1673957019,
  41. "currency": "usd",
  42. "id": "price_1MRDt9LS6SANVcyCvUMav5Fr",
  43. "interval": "month",
  44. "interval_count": 1,
  45. "livemode": false,
  46. "metadata": {},
  47. "nickname": "Free",
  48. "object": "plan",
  49. "product": "prod_NBb5jZ3Sg3Knrl",
  50. "tiers": null,
  51. "tiers_mode": null,
  52. "transform_usage": null,
  53. "trial_period_days": null,
  54. "usage_type": "licensed"
  55. },
  56. "price": {
  57. "active": true,
  58. "billing_scheme": "per_unit",
  59. "created": 1673957019,
  60. "currency": "usd",
  61. "custom_unit_amount": null,
  62. "id": "price_1MRDt9LS6SANVcyCvUMav5Fr",
  63. "livemode": false,
  64. "lookup_key": null,
  65. "metadata": {},
  66. "nickname": "Free",
  67. "object": "price",
  68. "product": "prod_NBb5jZ3Sg3Knrl",
  69. "recurring": {
  70. "aggregate_usage": null,
  71. "interval": "month",
  72. "interval_count": 1,
  73. "trial_period_days": null,
  74. "usage_type": "licensed"
  75. },
  76. "tax_behavior": "unspecified",
  77. "tiers_mode": null,
  78. "transform_quantity": null,
  79. "type": "recurring",
  80. "unit_amount": 0,
  81. "unit_amount_decimal": "0"
  82. },
  83. "quantity": 1,
  84. "subscription": "sub_1Mge5gLS6SANVcyCOTRj2dLw",
  85. "tax_rates": []
  86. }
  87. ],
  88. "has_more": false,
  89. "object": "list",
  90. "total_count": 1,
  91. "url": "/v1/subscription_items?subscription=sub_1Mge5gLS6SANVcyCOTRj2dLw"
  92. },
  93. "latest_invoice": {
  94. "account_country": "GB",
  95. "account_name": "Su Technology Ltd",
  96. "account_tax_ids": null,
  97. "amount_due": 0,
  98. "amount_paid": 0,
  99. "amount_remaining": 0,
  100. "amount_shipping": 0,
  101. "application": null,
  102. "application_fee_amount": null,
  103. "attempt_count": 0,
  104. "attempted": true,
  105. "auto_advance": false,
  106. "automatic_tax": {
  107. "enabled": false,
  108. "status": null
  109. },
  110. "billing_reason": "subscription_create",
  111. "charge": null,
  112. "collection_method": "charge_automatically",
  113. "created": 1677632660,
  114. "currency": "usd",
  115. "custom_fields": null,
  116. "customer": "cus_NRX9a1XQtjWJPd",
  117. "customer_address": null,
  118. "customer_email": "bulkanutku@gmail.com",
  119. "customer_name": null,
  120. "customer_phone": null,
  121. "customer_shipping": null,
  122. "customer_tax_exempt": "none",
  123. "customer_tax_ids": [],
  124. "default_payment_method": null,
  125. "default_source": null,
  126. "default_tax_rates": [],
  127. "description": null,
  128. "discount": null,
  129. "discounts": [],
  130. "due_date": null,
  131. "ending_balance": 0,
  132. "footer": null,
  133. "from_invoice": null,
  134. "hosted_invoice_url": "https://invoice.stripe.com/i/acct_1GJetwLS6SANVcyC/test_YWNjdF8xR0pldHdMUzZTQU5WY3lDLF9OUlhBQjBaaVZMQk5FSFFFcTBydVB5bzNpVnlORWk1LDY4MTczNDYw0200gE9zTwdN?s=ap",
  135. "id": "in_1Mge5gLS6SANVcyCtGvBkugu",
  136. "invoice_pdf": "https://pay.stripe.com/invoice/acct_1GJetwLS6SANVcyC/test_YWNjdF8xR0pldHdMUzZTQU5WY3lDLF9OUlhBQjBaaVZMQk5FSFFFcTBydVB5bzNpVnlORWk1LDY4MTczNDYw0200gE9zTwdN/pdf?s=ap",
  137. "last_finalization_error": null,
  138. "latest_revision": null,
  139. "lines": {
  140. "data": [
  141. {
  142. "amount": 0,
  143. "amount_excluding_tax": 0,
  144. "currency": "usd",
  145. "description": "1 \u00d7 videoo.io (at $0.00 / month)",
  146. "discount_amounts": [],
  147. "discountable": true,
  148. "discounts": [],
  149. "id": "il_1Mge5gLS6SANVcyCTgQ4Jyt4",
  150. "livemode": false,
  151. "metadata": {},
  152. "object": "line_item",
  153. "period": {
  154. "end": 1680311060,
  155. "start": 1677632660
  156. },
  157. "plan": {
  158. "active": true,
  159. "aggregate_usage": null,
  160. "amount": 0,
  161. "amount_decimal": "0",
  162. "billing_scheme": "per_unit",
  163. "created": 1673957019,
  164. "currency": "usd",
  165. "id": "price_1MRDt9LS6SANVcyCvUMav5Fr",
  166. "interval": "month",
  167. "interval_count": 1,
  168. "livemode": false,
  169. "metadata": {},
  170. "nickname": "Free",
  171. "object": "plan",
  172. "product": "prod_NBb5jZ3Sg3Knrl",
  173. "tiers": null,
  174. "tiers_mode": null,
  175. "transform_usage": null,
  176. "trial_period_days": null,
  177. "usage_type": "licensed"
  178. },
  179. "price": {
  180. "active": true,
  181. "billing_scheme": "per_unit",
  182. "created": 1673957019,
  183. "currency": "usd",
  184. "custom_unit_amount": null,
  185. "id": "price_1MRDt9LS6SANVcyCvUMav5Fr",
  186. "livemode": false,
  187. "lookup_key": null,
  188. "metadata": {},
  189. "nickname": "Free",
  190. "object": "price",
  191. "product": "prod_NBb5jZ3Sg3Knrl",
  192. "recurring": {
  193. "aggregate_usage": null,
  194. "interval": "month",
  195. "interval_count": 1,
  196. "trial_period_days": null,
  197. "usage_type": "licensed"
  198. },
  199. "tax_behavior": "unspecified",
  200. "tiers_mode": null,
  201. "transform_quantity": null,
  202. "type": "recurring",
  203. "unit_amount": 0,
  204. "unit_amount_decimal": "0"
  205. },
  206. "proration": false,
  207. "proration_details": {
  208. "credited_items": null
  209. },
  210. "quantity": 1,
  211. "subscription": "sub_1Mge5gLS6SANVcyCOTRj2dLw",
  212. "subscription_item": "si_NRXAdvOPbsuzfz",
  213. "tax_amounts": [],
  214. "tax_rates": [],
  215. "type": "subscription",
  216. "unit_amount_excluding_tax": "0"
  217. }
  218. ],
  219. "has_more": false,
  220. "object": "list",
  221. "total_count": 1,
  222. "url": "/v1/invoices/in_1Mge5gLS6SANVcyCtGvBkugu/lines"
  223. },
  224. "livemode": false,
  225. "metadata": {},
  226. "next_payment_attempt": null,
  227. "number": "E86AFCCB-0313",
  228. "object": "invoice",
  229. "on_behalf_of": null,
  230. "paid": true,
  231. "paid_out_of_band": false,
  232. "payment_intent": null,
  233. "payment_settings": {
  234. "default_mandate": null,
  235. "payment_method_options": null,
  236. "payment_method_types": null
  237. },
  238. "period_end": 1677632660,
  239. "period_start": 1677632660,
  240. "post_payment_credit_notes_amount": 0,
  241. "pre_payment_credit_notes_amount": 0,
  242. "quote": null,
  243. "receipt_number": null,
  244. "rendering_options": null,
  245. "shipping_cost": null,
  246. "shipping_details": null,
  247. "starting_balance": 0,
  248. "statement_descriptor": null,
  249. "status": "paid",
  250. "status_transitions": {
  251. "finalized_at": 1677632660,
  252. "marked_uncollectible_at": null,
  253. "paid_at": 1677632660,
  254. "voided_at": null
  255. },
  256. "subscription": "sub_1Mge5gLS6SANVcyCOTRj2dLw",
  257. "subtotal": 0,
  258. "subtotal_excluding_tax": 0,
  259. "tax": null,
  260. "tax_percent": null,
  261. "test_clock": null,
  262. "total": 0,
  263. "total_discount_amounts": [],
  264. "total_excluding_tax": 0,
  265. "total_tax_amounts": [],
  266. "transfer_data": null,
  267. "webhooks_delivered_at": 1677632660
  268. },
  269. "livemode": false,
  270. "metadata": {},
  271. "next_pending_invoice_item_invoice": null,
  272. "object": "subscription",
  273. "on_behalf_of": null,
  274. "pause_collection": null,
  275. "payment_settings": {
  276. "payment_method_options": null,
  277. "payment_method_types": null,
  278. "save_default_payment_method": "on_subscription"
  279. },
  280. "pending_invoice_item_interval": null,
  281. "pending_setup_intent": "seti_1Mge5gLS6SANVcyCiD2a3pQM",
  282. "pending_update": null,
  283. "plan": {
  284. "active": true,
  285. "aggregate_usage": null,
  286. "amount": 0,
  287. "amount_decimal": "0",
  288. "billing_scheme": "per_unit",
  289. "created": 1673957019,
  290. "currency": "usd",
  291. "id": "price_1MRDt9LS6SANVcyCvUMav5Fr",
  292. "interval": "month",
  293. "interval_count": 1,
  294. "livemode": false,
  295. "metadata": {},
  296. "nickname": "Free",
  297. "object": "plan",
  298. "product": "prod_NBb5jZ3Sg3Knrl",
  299. "tiers": null,
  300. "tiers_mode": null,
  301. "transform_usage": null,
  302. "trial_period_days": null,
  303. "usage_type": "licensed"
  304. },
  305. "quantity": 1,
  306. "schedule": null,
  307. "start_date": 1677632660,
  308. "status": "active",
  309. "tax_percent": null,
  310. "test_clock": null,
  311. "transfer_data": null,
  312. "trial_end": null,
  313. "trial_settings": {
  314. "end_behavior": {
  315. "missing_payment_method": "create_invoice"
  316. }
  317. },
  318. "trial_start": null
  319. }

答案1

得分: 1

因为发票金额为$0,所以没有需要支付的内容,因此没有PaymentIntent。

根据您尝试完成的任务,您可以改为使用“pending_setup_intent”和该对象上的“client_secret”,然后在前端使用“stripe.confirmCardSetup(…)”来收集付款详细信息,而无需收费。

https://stripe.com/docs/billing/subscriptions/overview#using-setupintents

英文:

> and as you can see that latest_invoice is there, but payment_intent is null

Because the Invoice is for $0 so there is nothing to pay, so no PaymentIntent.

Depending on what you're trying to do, you can use the pending_setup_intent instead and the client_secret of that object on the frontend with stripe.confirmCardSetup(...) to collect payment details without charging them.

https://stripe.com/docs/billing/subscriptions/overview#using-setupintents

huangapple
  • 本文由 发表于 2023年3月1日 08:49:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75598670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定