diff --git a/CHANGELOG b/CHANGELOG index 824b7fd937..efa9f761ed 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Add webhook for payment intent canceled + Version 5.6.0 - 2020-05-04 * Bug fixes (see mercurial logs for details) * Add configuration for max_network_retries diff --git a/payment.py b/payment.py index a950dd823c..3f8a05484d 100644 --- a/payment.py +++ b/payment.py @@ -1065,6 +1065,8 @@ class Account(ModelSQL, ModelView): return self.webhook_payment_intent_amount_capturable_updated(data) elif type_ == 'payment_intent.payment_failed': return self.webhook_payment_intent_payment_failed(data) + elif type_ == 'payment_intent.canceled': + return self.webhook_payment_intent_canceled(data) return None def webhook_charge_succeeded(self, payload, _event='charge.succeeded'): @@ -1360,6 +1362,25 @@ class Account(ModelSQL, ModelView): Payment.fail([payment]) return bool(payments) + def webhook_payment_intent_canceled(self, payload): + pool = Pool() + Payment = pool.get('account.payment') + + payment_intent = payload['object'] + payments = Payment.search([ + ('stripe_payment_intent_id', '=', payment_intent['id']), + ]) + if not payments: + logger.error( + "payment_intent.canceled: No payment '%s'", + payment_intent['id']) + for payment in payments: + # TODO: remove when https://bugs.tryton.org/issue4080 + with Transaction().set_context(company=payment.company.id): + payment = Payment(payment.id) + Payment.fail([payment]) + return bool(payments) + @classmethod @ModelView.button def new_identifier(cls, accounts): diff --git a/tests/scenario_account_payment_stripe_intent.rst b/tests/scenario_account_payment_stripe_intent.rst index 83d9c0abf4..cb7c929602 100644 --- a/tests/scenario_account_payment_stripe_intent.rst +++ b/tests/scenario_account_payment_stripe_intent.rst @@ -142,3 +142,31 @@ Refund the payment:: >>> payment.reload() >>> payment.state 'failed' + +Cancel payment intent:: + + >>> payment = Payment() + >>> payment.journal = payment_journal + >>> payment.kind = 'receivable' + >>> payment.party = party + >>> payment.amount = Decimal('42') + >>> payment.description = 'Testing canceled' + >>> payment.stripe_customer = customer + >>> payment.stripe_customer_payment_method = payment_method.id + >>> payment.stripe_capture = False + >>> payment.click('approve') + >>> payment.state + 'approved' + + >>> process_payment = Wizard('account.payment.process', [payment]) + >>> process_payment.execute('process') + >>> payment.state + 'processing' + + >>> _ = stripe.PaymentIntent.cancel(payment.stripe_payment_intent_id) + + >>> time.sleep(1) + >>> cron_fetch_events.click('run_once') + >>> payment.reload() + >>> payment.state + 'failed'