From fef7778af91581318cff5fd40c10532c91343256 Mon Sep 17 00:00:00 2001 From: Martin Gross Date: Tue, 27 Jun 2023 12:00:40 +0200 Subject: [PATCH] Update the payment due date for banktransfers, when the order is changed --- pretix_mollie/payment.py | 41 ++++++++++++++++++++++++++++++++++++++-- pretix_mollie/signals.py | 20 +++++++++++++++----- pretix_mollie/tasks.py | 13 +++++++++++++ 3 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 pretix_mollie/tasks.py diff --git a/pretix_mollie/payment.py b/pretix_mollie/payment.py index a4b43c3..60e6496 100644 --- a/pretix_mollie/payment.py +++ b/pretix_mollie/payment.py @@ -2,7 +2,6 @@ import json import logging import textwrap -import urllib.parse from collections import OrderedDict from datetime import timedelta @@ -600,7 +599,7 @@ def execute_payment(self, request: HttpRequest, payment: OrderPayment, retry=Tru def _get_payment_body(self, payment): body = super()._get_payment_body(payment) - body['dueDate'] = (payment.order.expires.date() + timedelta(days=1)).isoformat() + body['dueDate'] = self.get_due_date(payment) return body def order_pending_mail_render(self, order, payment) -> str: @@ -670,6 +669,44 @@ def payment_form_render(self, request) -> str: ctx = {'request': request, 'event': self.event, 'settings': self.settings} return template.render(ctx) + def get_due_date(self, payment): + # The due date is a little bit fuzzy, since we can (according to the Mollie API) only transmit YYYY-MM-DD, + # but internally they will convert it to UTC. + # An order.expiry of 05.07.2023 23:59 (GMT+02) would normally be communicated to Mollie as 2023-07-06. Upon + # an API-request, Mollie would however return "expiresAt": "2023-07-08T04:00:00+00:00" + # Takin into consideration GMT+2/UTC, this still gives an extra 2 hours - but we can't do anything about it. + return (payment.order.expires.date() + timedelta(days=1)).isoformat() + + def update_payment_due(self, payment, retry=True): + payment_id = payment.info_data.get('id') + body = { + 'dueDate': self.get_due_date(payment), + } + + try: + req = requests.patch( + 'https://api.mollie.com/v2/payments/{}'.format(payment_id), + json=body, + headers=self.request_headers + ) + req.raise_for_status() + payment.info_data = req.json() + except HTTPError: + logger.exception('Mollie error: %s' % req.text) + try: + payment.info_data = req.json() + + if payment.info_data.get('status') == 401 and retry: + # Token might be expired, let's retry! + if refresh_mollie_token(self.event, False): + return self.update_payment_due(payment, retry=False) + except: + payment.info_data = { + 'error': True, + 'detail': req.text + } + raise PaymentException(_('Mollie reported an error: {}').format(payment.info_data.get('detail'))) + class MollieBelfius(MollieMethod): method = 'belfius' diff --git a/pretix_mollie/signals.py b/pretix_mollie/signals.py index b504e15..a3203a5 100644 --- a/pretix_mollie/signals.py +++ b/pretix_mollie/signals.py @@ -2,23 +2,22 @@ import time from collections import OrderedDict -import requests from django import forms from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ from django_scopes import scopes_disabled from pretix.base.forms import SecretKeySettingsField -from pretix.base.models import Event_SettingsStore -from pretix.base.settings import GlobalSettingsObject, settings_hierarkey +from pretix.base.models import Event_SettingsStore, Order, OrderPayment +from pretix.base.settings import settings_hierarkey from pretix.base.signals import ( logentry_display, periodic_task, register_global_settings, - register_payment_providers, + register_payment_providers, order_modified, ) -from pretix.helpers.urls import build_absolute_uri from .forms import MollieKeyValidator from .utils import refresh_mollie_token +from .tasks import extend_payment_deadline logger = logging.getLogger(__name__) @@ -101,3 +100,14 @@ def refresh_mollie_tokens(sender, **kwargs): if rt not in seen: refresh_mollie_token(es.object, True) seen.add(rt) + + +@receiver(order_modified, dispatch_uid='mollie_order_modified') +def order_placed(order, **kwargs): + payment = order.payments.last() + if ( + order.status == Order.STATUS_PENDING + and payment.provider == 'mollie_banktransfer' + and payment.state in (OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_PENDING) + ): + extend_payment_deadline.apply_async(args=(payment.pk,)) diff --git a/pretix_mollie/tasks.py b/pretix_mollie/tasks.py new file mode 100644 index 0000000..1eb0ff4 --- /dev/null +++ b/pretix_mollie/tasks.py @@ -0,0 +1,13 @@ +from django_scopes import scopes_disabled + +from pretix.base.models import OrderPayment +from pretix.celery_app import app + + +@app.task() +@scopes_disabled() +def extend_payment_deadline(payment): + payment = OrderPayment.objects.get(pk=payment) + pprov = payment.payment_provider + + pprov.update_payment_due(payment)