Problem/Motivation
Custom and contrib modules cannot customise the payment intent.
https://stripe.com/docs/api/payment_intents/create
Steps to reproduce
Proposed resolution
Add new Event when create PaymentIntent object.
Remaining tasks
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #26 | commerce_stripe-payment-intent-event-3256552-26.patch | 5.45 KB | johnpitcairn |
Comments
Comment #2
krzysztof domańskiComment #4
jonathanshawWhy is it necessary add this additional event to customise the intent when it is created?
#3170903: Allow customising the payment intent allows us to customise the intent.
If it was important to customise the intent before it was confirmed, we could modify #3170903: Allow customising the payment intent to do that, by still using the same event but calling it before confirmation.
Comment #5
krzysztof domańskiSome properties (e.g. 'application_fee_amount') can only be set when creating payment intent.
Comment #6
jonathanshawThat makes sense. This would seem to heavily overlap with #3170903: Allow customising the payment intent and I'm not sure we need both.
I think we should close #3170903: Allow customising the payment intent as a duplicate, and then in this issue deprecate the existing transaction data event.
We should also have some somewhat-related follow-up issues:
- to allow OrderPaymentIntentSubscriber to update the intent properly when the order changes.
- to trigger OrderPaymentIntentSubscriber if the payment changes, as that could also affect the intent.
That way we get:
- a single recommended solution for customising the intent, providing metadata, etc
- no BC issues that might just possibly come from changing the point at which the event info is added to the intent
- we don't have to update the intent so an API call is saved
- a clean new event API for customising the event, rather than carrying forward the legacy TransactionData event
I'm happy to review and RTBC if you'll do the fixing @Krzysztof. Or I can fix and you can review.
We will also need to respond to situations where the intent needs to be updated. So let's call this simply a 'PaymentIntentEvent'.
I would call this $intentAttributes, using Stripe's terminology.
In https://www.drupal.org/project/commerce_stripe/issues/3171408 and other issues we found it necessary to pass the payment object to CreatePaymentIntent(), so let's also add this here as an optional constructor argument with associated getter.
I think this might need to use NestedArray::mergeDeep()
Comment #7
jonathanshawThe maintainer @jsacksick has said elsewhere that we should extend commerce's EventBase for forwards-compatability:
Comment #8
johnpitcairn commentedComment #9
johnpitcairn commentedI'm not sure #3121771: Fix TransactionData event, include description and initial metadata can really be called duplicate. The original
TransactionDataEventwas dispatched after payment intent creation at Stripe, and it would preserve that behavior. At that stage the payment entity has itsstateset andremoteIdcaptured, the commerce payment entity has been saved, and events resulting from that dispatched.Comment #10
johnpitcairn commentedThe event constant should be:Comment #11
johnpitcairn commentedWorking on the points from #6, #7 and #10.
I think we need to also pass $intent_array to the event constructor, right? Otherwise event subscribers cannot inspect the existing intent attributes.
Comment #12
johnpitcairn commentedComment #13
johnpitcairn commentedNew patch addressing #6, #7, and passing in the attributes array for inspection.
Comment #14
johnpitcairn commentedA remaining question is whether the full intent array should be passed in like this and any modifications accepted.
If that's OK, then we don't need to merge arrays at all, because we can just get the entire modified intent attributes array back from the event.
If we are intending that the properties already in the intent array should not be modifiable, and the intent array is not passed in, then there's nothing stopping subscribers from adding those properties to the (empty) intent attributes array anyway - the code after the event dispatch will overwrite the originals, regardless of whether we use
array_merge()orNestedArray::mergeDeep(). Right?What is preferred here?
Comment #15
johnpitcairn commentedAlternate patch that will apply over #3259211: Provide more parameters to createPaymentIntent().
Comment #16
jonathanshawNice.
+1
From #6:
I think we should close #3170903: Allow customising the payment intent as a duplicate, and then in this issue deprecate the existing transaction data event.Need to do deprecation.
Comment #17
jonathanshawI think we can simply do $intent_array = $event->getIntentAttributes() here.
And then in PaymentIntentEvent let's add an addIntentAttributes() method that uses NestedArray::mergeDeep() to merge the added attributes to the ones originally provided to the event. It's just a convenience so the event subscribers don't have to call getIntentAttributes(), merge deep with whatever additional attributes they want, and then call setIntentAttributes().
Comment #18
mhawwari commentedNeeded to use this patch for adding an intent description.
I applied the approach in #17 and added a new addIntentAttributes() method. I also just added a @deprecated tag for #16
The only concern here is if we should dispatch the event in the same place the transaction data event is being dispatched in the createPayment() method and pass the payment object if a project needed to pass info about the drupal payment to stripe.
Comment #19
mhawwari commentedI guess we can pass an empty intent array to only update attributes added from the event subscriber and that can avoid updating all the intent attributes in createPayment() after payment save. So we can pass
new PaymentIntentEvent($order, [], $payment)to replacenew TransactionDataEvent($payment).Comment #20
johnpitcairn commentedNo. See #5.
Comment #21
johnpitcairn commentedPaymentIntentEventis missing ausestatement forNestedArray.Comment #22
johnpitcairn commentedThe comments in
StripeEventsalso need attention.PaymentIntentEventis only dispatched when a payment intent is created. It does not allow modification of transaction data if a payment intent is updated.TransactionDataEventdid allow that, but is now deprecated, and it is only passed the payment at__construct(), not the intent attributes.The only place we call
PaymentIntent::update()is following theTransactionDataevent dispatch, to merge in any added metadata, and that is going to be removed.I think we can remove any mention of updating a payment intent.
Do we also need a @deprecated tag on the
TransactionDataEventclass? Subscribers are not required to use an event constant as the array key ingetSubscribedEvents().Comment #23
johnpitcairn commentedPatch as per #21-22.
Comment #24
jonathanshawI think we should call this PAYMENT_INTENT_CREATE in cae we also want to create a PAYMENT_INTENT_UPDATE in the future.
Comment #25
jonathanshawThis is not a replacement for every conceivable use case for TRANSACTION_DATA event because it is called earlier. But it should handle the 99% use cases rather better than the current approach, so I think its fine as is. We can always add further events in future if demmand is there.
Comment #26
johnpitcairn commentedOK and we'd just use the same event class when dispatching an update event.
This patch changes the event constant. Anyone relying on it will need to update their subscriber
getSubscribedEvents()method.It also adds "Will be removed in 2.x" to the deprecation notices, and the docblock clarifies that the event fires before the payment intent is created.
Comment #27
jonathanshawConstant needs changing here too.
RTBC as trivial and can be fixed on commit.
Comment #28
jsacksick commentedCommitted, thanks!
Comment #31
jsacksick commentedRealized I forgot to commit the event class... Will tag a new release once tests are green.