Mark order as paid immediately

This commit is contained in:
Raphael Michel
2019-04-15 12:55:27 +02:00
parent 0f58e1c396
commit 874b38db17
5 changed files with 41 additions and 17 deletions

View File

@@ -1159,7 +1159,7 @@ class OrderPayment(models.Model):
self.order.log_action('pretix.event.order.overpaid', {}, user=user, auth=auth) self.order.log_action('pretix.event.order.overpaid', {}, user=user, auth=auth)
order_paid.send(self.order.event, order=self.order) order_paid.send(self.order.event, order=self.order)
def confirm(self, count_waitinglist=True, send_mail=True, force=False, user=None, auth=None, mail_text=''): def confirm(self, count_waitinglist=True, send_mail=True, force=False, user=None, auth=None, mail_text='', lock=True):
""" """
Marks the payment as complete. If possible, this also marks the order as paid if no further Marks the payment as complete. If possible, this also marks the order as paid if no further
payment is required payment is required
@@ -1218,7 +1218,7 @@ class OrderPayment(models.Model):
if payment_sum - refund_sum < self.order.total: if payment_sum - refund_sum < self.order.total:
return return
if self.order.status == Order.STATUS_PENDING and self.order.expires > now() + timedelta(hours=12): if (self.order.status == Order.STATUS_PENDING and self.order.expires > now() + timedelta(hours=12)) or not lock:
# Performance optimization. In this case, there's really no reason to lock everything and an atomic # Performance optimization. In this case, there's really no reason to lock everything and an atomic
# database transaction is more than enough. # database transaction is more than enough.
with transaction.atomic(): with transaction.atomic():

View File

@@ -567,6 +567,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
meta_info: dict=None, sales_channel: str='web'): meta_info: dict=None, sales_channel: str='web'):
fees, pf = _get_fees(positions, payment_provider, address, meta_info, event) fees, pf = _get_fees(positions, payment_provider, address, meta_info, event)
total = sum([c.price for c in positions]) + sum([c.value for c in fees]) total = sum([c.price for c in positions]) + sum([c.value for c in fees])
p = None
with transaction.atomic(): with transaction.atomic():
order = Order( order = Order(
@@ -600,7 +601,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
fee.save() fee.save()
if payment_provider and not order.require_approval: if payment_provider and not order.require_approval:
order.payments.create( p = order.payments.create(
state=OrderPayment.PAYMENT_STATE_CREATED, state=OrderPayment.PAYMENT_STATE_CREATED,
provider=payment_provider.identifier, provider=payment_provider.identifier,
amount=total, amount=total,
@@ -616,7 +617,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
order.log_action('pretix.event.order.consent', data={'msg': msg}) order.log_action('pretix.event.order.consent', data={'msg': msg})
order_placed.send(event, order=order) order_placed.send(event, order=order)
return order return order, p
def _perform_order(event: str, payment_provider: str, position_ids: List[str], def _perform_order(event: str, payment_provider: str, position_ids: List[str],
@@ -648,8 +649,12 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
if len(position_ids) != len(positions): if len(position_ids) != len(positions):
raise OrderError(error_messages['internal']) raise OrderError(error_messages['internal'])
_check_positions(event, now_dt, positions, address=addr) _check_positions(event, now_dt, positions, address=addr)
order = _create_order(event, email, positions, now_dt, pprov, order, payment = _create_order(event, email, positions, now_dt, pprov,
locale=locale, address=addr, meta_info=meta_info, sales_channel=sales_channel) locale=locale, address=addr, meta_info=meta_info, sales_channel=sales_channel)
free_order_flow = payment and payment_provider == 'free' and order.total == Decimal('0.00')
if free_order_flow:
payment.confirm(send_mail=False, lock=False)
invoice = order.invoices.last() # Might be generated by plugin already invoice = order.invoices.last() # Might be generated by plugin already
if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order): if event.settings.get('invoice_generate') == 'True' and invoice_qualified(order):
@@ -664,7 +669,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
if order.require_approval: if order.require_approval:
email_template = event.settings.mail_text_order_placed_require_approval email_template = event.settings.mail_text_order_placed_require_approval
log_entry = 'pretix.event.order.email.order_placed_require_approval' log_entry = 'pretix.event.order.email.order_placed_require_approval'
elif payment_provider == 'free': elif free_order_flow:
email_template = event.settings.mail_text_order_free email_template = event.settings.mail_text_order_free
log_entry = 'pretix.event.order.email.order_free' log_entry = 'pretix.event.order.email.order_free'
else: else:

View File

@@ -14,7 +14,7 @@ from django.utils.translation import (
from django.views.generic.base import TemplateResponseMixin from django.views.generic.base import TemplateResponseMixin
from pretix.base.models import Order from pretix.base.models import Order
from pretix.base.models.orders import InvoiceAddress from pretix.base.models.orders import InvoiceAddress, OrderPayment
from pretix.base.services.cart import ( from pretix.base.services.cart import (
get_fees, set_cart_addons, update_tax_rates, get_fees, set_cart_addons, update_tax_rates,
) )
@@ -721,7 +721,7 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
return self.get_step_url(self.request) return self.get_step_url(self.request)
def get_order_url(self, order): def get_order_url(self, order):
payment = order.payments.first() payment = order.payments.filter(state__in=[OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_PENDING]).first()
if not payment: if not payment:
return eventreverse(self.request.event, 'presale:event.order', kwargs={ return eventreverse(self.request.event, 'presale:event.order', kwargs={
'order': order.code, 'order': order.code,

View File

@@ -41,7 +41,7 @@ def test_expiry_days(event):
event.settings.set('payment_term_weekdays', False) event.settings.set('payment_term_weekdays', False)
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 5 assert (order.expires - today).days == 5
@@ -52,14 +52,14 @@ def test_expiry_weekdays(event):
event.settings.set('payment_term_weekdays', True) event.settings.set('payment_term_weekdays', True)
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 6 assert (order.expires - today).days == 6
assert order.expires.weekday() == 0 assert order.expires.weekday() == 0
today = make_aware(datetime(2016, 9, 19, 15, 0, 0, 0)) today = make_aware(datetime(2016, 9, 19, 15, 0, 0, 0))
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 7 assert (order.expires - today).days == 7
assert order.expires.weekday() == 0 assert order.expires.weekday() == 0
@@ -72,12 +72,12 @@ def test_expiry_last(event):
event.settings.set('payment_term_last', now() + timedelta(days=3)) event.settings.set('payment_term_last', now() + timedelta(days=3))
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 3 assert (order.expires - today).days == 3
event.settings.set('payment_term_last', now() + timedelta(days=7)) event.settings.set('payment_term_last', now() + timedelta(days=7))
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 5 assert (order.expires - today).days == 5
@@ -93,7 +93,7 @@ def test_expiry_last_relative(event):
)) ))
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 3 assert (order.expires - today).days == 3
@@ -124,7 +124,7 @@ def test_expiry_last_relative_subevents(event):
)) ))
order = _create_order(event, email='dummy@example.org', positions=[cp1, cp2], order = _create_order(event, email='dummy@example.org', positions=[cp1, cp2],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
assert (order.expires - today).days == 6 assert (order.expires - today).days == 6
@@ -136,7 +136,7 @@ def test_expiry_dst(event):
today = tz.localize(datetime(2016, 10, 29, 12, 0, 0)).astimezone(utc) today = tz.localize(datetime(2016, 10, 29, 12, 0, 0)).astimezone(utc)
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, payment_provider=FreeOrderProvider(event), now_dt=today, payment_provider=FreeOrderProvider(event),
locale='de') locale='de')[0]
localex = order.expires.astimezone(tz) localex = order.expires.astimezone(tz)
assert (localex.hour, localex.minute) == (23, 59) assert (localex.hour, localex.minute) == (23, 59)

View File

@@ -907,6 +907,24 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
self.assertEqual(OrderPosition.objects.count(), 1) self.assertEqual(OrderPosition.objects.count(), 1)
self.assertEqual(OrderPosition.objects.first().price, 42) self.assertEqual(OrderPosition.objects.first().price, 42)
def test_free_order(self):
self.ticket.free_price = True
self.ticket.save()
cr1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=0, expires=now() + timedelta(minutes=10)
)
self._set_session('payment', 'free')
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
doc = BeautifulSoup(response.rendered_content, "lxml")
self.assertEqual(len(doc.select(".thank-you")), 1)
self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists())
self.assertEqual(Order.objects.count(), 1)
self.assertEqual(OrderPosition.objects.count(), 1)
self.assertEqual(OrderPosition.objects.first().price, 0)
self.assertEqual(Order.objects.first().status, Order.STATUS_PAID)
def test_confirm_in_time(self): def test_confirm_in_time(self):
cr1 = CartPosition.objects.create( cr1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket, event=self.event, cart_id=self.session_key, item=self.ticket,
@@ -920,6 +938,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists()) self.assertFalse(CartPosition.objects.filter(id=cr1.id).exists())
self.assertEqual(Order.objects.count(), 1) self.assertEqual(Order.objects.count(), 1)
self.assertEqual(OrderPosition.objects.count(), 1) self.assertEqual(OrderPosition.objects.count(), 1)
self.assertEqual(Order.objects.first().status, Order.STATUS_PENDING)
def test_subevent_confirm_expired_available(self): def test_subevent_confirm_expired_available(self):
self.event.has_subevents = True self.event.has_subevents = True