diff --git a/modules/account_payment_stripe/payment.py b/modules/account_payment_stripe/payment.py index a0d1395daa..294df64dda 100644 --- a/modules/account_payment_stripe/payment.py +++ b/modules/account_payment_stripe/payment.py @@ -626,6 +626,7 @@ class Payment(StripeCustomerMethodMixin, CheckoutMixin, metaclass=PoolMeta): try: return stripe.PaymentIntent.retrieve( self.stripe_payment_intent_id, + expand=['latest_charge'], api_key=self.journal.stripe_account.secret_key, stripe_version=STRIPE_VERSION) except (stripe.error.RateLimitError, @@ -651,6 +652,35 @@ class Payment(StripeCustomerMethodMixin, CheckoutMixin, metaclass=PoolMeta): stripe.error.APIConnectionError) as e: logger.warning(str(e)) + @classmethod + def stripe_pull(cls, payments): + "Update payments with Stripe charges" + for payment in payments: + charge = payment.stripe_charge_ + if payment_intent := payment.stripe_payment_intent: + charge = payment_intent.latest_charge + if charge: + payment.stripe_update(charge) + + def stripe_update(self, charge): + assert ( + (charge.id == self.stripe_charge_id) + or (charge.payment_intent.id == self.stripe_payment_intent_id)) + amount = charge.amount - charge.amount_refunded + if (self.state not in {'succeeded', 'failed'} + or self.stripe_amount != amount + or (not amount and self.state != 'failed')): + if self.state == 'succeeded': + self.__class__.proceed([self]) + self.stripe_captured = charge.captured + self.stripe_amount = amount + self.save() + if self.amount: + if charge.status == 'succeeded' and charge.captured: + self.__class__.succeed([self]) + else: + self.__class__.fail([self]) + class Refund(Workflow, ModelSQL, ModelView): "Stripe Payment Refund" @@ -1082,8 +1112,10 @@ class Account(ModelSQL, ModelView): def webhook_charge_refund_updated(self, payload): pool = Pool() + Payment = pool.get('account.payment') Refund = pool.get('account.payment.stripe.refund') + payments = [] rf = payload['object'] refunds = Refund.search([ ('stripe_refund_id', '=', rf['id']), @@ -1098,7 +1130,9 @@ class Account(ModelSQL, ModelView): elif rf['status'] in {'failed', 'canceled'}: refund.stripe_error_code = rf['failure_reason'] Refund.fail([refund]) + payments.append(refund.payment) refund.save() + Payment.stripe_pull(payments) return bool(refunds) def webhook_charge_failed(self, payload, _event='charge.failed'):