New check-in features (#3022)

This commit is contained in:
Raphael Michel
2023-02-09 09:46:46 +01:00
committed by GitHub
parent 7b0d07065f
commit 6902725f3c
69 changed files with 1606 additions and 183 deletions

View File

@@ -98,6 +98,42 @@ class EventCancelTests(TestCase):
self.order.refresh_from_db()
assert self.order.status == Order.STATUS_CANCELED
@classscope(attr='o')
def test_cancel_auto_refund_skip_blocked(self):
gc = self.o.issued_gift_cards.create(currency="EUR")
p1 = self.order.payments.create(
amount=Decimal('46.00'),
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
provider='giftcard',
info='{"gift_card": %d}' % gc.pk
)
self.order.status = Order.STATUS_PAID
self.order.save()
self.op1.blocked = ["admin"]
self.op1.save()
cancel_event(
self.event.pk, subevent=None,
auto_refund=True, keep_fee_fixed="0.00", keep_fee_percentage="0.00", keep_fee_per_ticket="",
send=True, send_subject="Event canceled", send_message="Event canceled :-(",
user=None
)
self.op1.refresh_from_db()
assert not self.op1.canceled
self.op2.refresh_from_db()
assert self.op2.canceled
r = self.order.refunds.get()
assert r.state == OrderRefund.REFUND_STATE_DONE
assert r.amount == Decimal('23.00')
assert r.source == OrderRefund.REFUND_SOURCE_ADMIN
assert r.payment == p1
assert self.order.all_logentries().filter(action_type='pretix.event.order.refund.created').exists()
assert not self.order.all_logentries().filter(action_type='pretix.event.order.refund.requested').exists()
assert gc.value == Decimal('23.00')
@classscope(attr='o')
def test_cancel_auto_refund(self):
gc = self.o.issued_gift_cards.create(currency="EUR")
@@ -524,6 +560,24 @@ class SubEventCancelTests(TestCase):
self.order.refresh_from_db()
assert self.order.status == Order.STATUS_CANCELED
@classscope(attr='o')
def test_cancel_skip_blocked(self):
self.op2.subevent = self.se1
self.op2.blocked = ["admin"]
self.op2.save()
cancel_event(
self.event.pk, subevent=self.se1.pk,
auto_refund=True, keep_fee_fixed="0.00", keep_fee_percentage="0.00", keep_fee_per_ticket="",
send=True, send_subject="Event canceled", send_message="Event canceled :-(",
user=None
)
self.order.refresh_from_db()
assert self.order.status == Order.STATUS_PENDING
self.op1.refresh_from_db()
assert self.op1.canceled
self.op2.refresh_from_db()
assert not self.op2.canceled
@classscope(attr='o')
def test_cancel_all_subevents(self):
cancel_event(

View File

@@ -115,6 +115,50 @@ def test_checkin_canceled_position(position, clist):
assert position.checkins.count() == 0
@pytest.mark.django_db
def test_checkin_blocked_position(position, clist):
position.blocked = ["admin"]
position.save()
with pytest.raises(CheckInError) as excinfo:
perform_checkin(position, clist, {})
assert excinfo.value.code == 'blocked'
assert position.checkins.count() == 0
with pytest.raises(CheckInError) as excinfo:
perform_checkin(position, clist, {}, type=Checkin.TYPE_EXIT)
assert excinfo.value.code == 'blocked'
assert position.checkins.count() == 0
@pytest.mark.django_db
def test_checkin_valid_from(event, position, clist):
position.valid_from = event.timezone.localize(datetime(2020, 1, 1, 12, 0, 0))
position.save()
with freeze_time("2020-01-01 10:45:00"):
with pytest.raises(CheckInError) as excinfo:
perform_checkin(position, clist, {})
assert excinfo.value.code == 'invalid_time'
assert excinfo.value.reason == 'This ticket is only valid after 2020-01-01 12:00.'
assert position.checkins.count() == 0
perform_checkin(position, clist, {}, type=Checkin.TYPE_EXIT)
assert position.checkins.count() == 1
@pytest.mark.django_db
def test_checkin_valid_until(event, position, clist):
position.valid_until = event.timezone.localize(datetime(2020, 1, 1, 9, 0, 0))
position.save()
with freeze_time("2020-01-01 10:45:00"):
with pytest.raises(CheckInError) as excinfo:
perform_checkin(position, clist, {})
assert excinfo.value.code == 'invalid_time'
assert excinfo.value.reason == 'This ticket was only valid before 2020-01-01 09:00.'
assert position.checkins.count() == 0
perform_checkin(position, clist, {}, type=Checkin.TYPE_EXIT)
assert position.checkins.count() == 1
@pytest.mark.django_db
def test_checkin_invalid_product(position, clist):
clist.all_products = False
@@ -162,6 +206,30 @@ def test_unpaid(position, clist):
assert excinfo.value.code == 'unpaid'
@pytest.mark.django_db
def test_unpaid_but_valid(position, clist):
o = position.order
o.status = Order.STATUS_PENDING
o.valid_if_pending = True
o.save()
clist.include_pending = False
clist.save()
perform_checkin(position, clist, {})
@pytest.mark.django_db
def test_require_approval(position, clist):
o = position.order
o.status = Order.STATUS_PENDING
o.require_approval = True
o.save()
clist.include_pending = False
clist.save()
with pytest.raises(CheckInError) as excinfo:
perform_checkin(position, clist, {}, ignore_unpaid=True)
assert excinfo.value.code == 'unpaid'
@pytest.mark.django_db
def test_unpaid_include_pending_ignore(position, clist):
o = position.order
@@ -173,7 +241,7 @@ def test_unpaid_include_pending_ignore(position, clist):
@pytest.mark.django_db
def test_unpaid_ignore_without_include_pendung(position, clist):
def test_unpaid_ignore_without_include_pending(position, clist):
o = position.order
o.status = Order.STATUS_PENDING
o.save()

View File

@@ -1310,7 +1310,7 @@ class OrderTestCase(BaseQuotaTestCase):
assert self.order.user_cancel_allowed
@classscope(attr='o')
def test_can_cancel_checked_in(self):
def test_can_not_cancel_checked_in(self):
self.order.status = Order.STATUS_PAID
self.order.save()
self.event.settings.cancel_allow_user = False
@@ -1322,6 +1322,17 @@ class OrderTestCase(BaseQuotaTestCase):
)
assert not self.order.user_cancel_allowed
@classscope(attr='o')
def test_can_not_cancel_blocked(self):
self.order.status = Order.STATUS_PAID
self.order.save()
self.event.settings.cancel_allow_user = False
self.event.settings.cancel_allow_user_paid = True
assert self.order.user_cancel_allowed
self.op1.blocked = ["admin"]
self.op1.save()
assert not self.order.user_cancel_allowed
@classscope(attr='o')
def test_can_cancel_order_multiple(self):
item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23,

View File

@@ -679,6 +679,19 @@ def test_import_seat(user, event, item):
assert not s3.is_available()
@pytest.mark.django_db
@scopes_disabled()
def test_import_validity(user, event, item):
settings = dict(DEFAULT_SETTINGS)
settings['item'] = 'static:{}'.format(item.pk)
settings['valid_until'] = 'csv:J'
import_orders.apply(
args=(event.pk, inputfile_factory().id, settings, 'en', user.pk)
).get()
assert OrderPosition.objects.first().valid_until.isoformat() == '2021-06-28T11:00:00+00:00'
@pytest.mark.django_db
@scopes_disabled()
def test_import_subevent_invalid(user, event, item):

View File

@@ -44,6 +44,7 @@ from pretix.base.payment import (
FreeOrderProvider, GiftCardPayment, PaymentException,
)
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
from pretix.base.secrets import assign_ticket_secret
from pretix.base.services.invoices import generate_invoice
from pretix.base.services.orders import (
OrderChangeManager, OrderError, _create_order, approve_order, cancel_order,
@@ -567,6 +568,17 @@ class PaymentReminderTests(TestCase):
self.event.settings.mail_days_order_expire_warning = 10
send_expiry_warnings(sender=self.event)
assert len(djmail.outbox) == 1
assert "only guarantee your order" in djmail.outbox[0].body
@classscope(attr='o')
def test_sent_no_expiry(self):
self.order.valid_if_pending = True
self.order.save()
self.event.settings.mail_days_order_expire_warning = 10
send_expiry_warnings(sender=self.event)
assert len(djmail.outbox) == 1
assert "only guarantee your order" not in djmail.outbox[0].body
assert "required to pay" in djmail.outbox[0].body
@classscope(attr='o')
def test_sent_not_immediately_after_purchase(self):
@@ -2904,6 +2916,62 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.used_membership is None
assert self.op1.item == self.ticket
@classscope(attr='o')
def test_add_block(self):
self.ocm.add_block(self.op1, "admin")
self.ocm.commit()
self.op1.refresh_from_db()
assert self.op1.blocked == ["admin"]
bs = self.op1.blocked_secrets.get()
assert bs.secret == self.op1.secret
assert bs.blocked
@classscope(attr='o')
def test_remove_block(self):
self.op1.blocked = ["admin"]
self.op1.save()
bs = self.op1.blocked_secrets.create(event=self.event, secret=self.op1.secret, blocked=True)
self.ocm.remove_block(self.op1, "admin")
self.ocm.commit()
self.op1.refresh_from_db()
assert self.op1.blocked is None
bs.refresh_from_db()
assert not bs.blocked
@classscope(attr='o')
def test_set_valid_from(self):
old_secret = self.op1.secret
dt = make_aware(datetime(2016, 9, 20, 15, 0, 0, 0))
self.ocm.change_valid_from(self.op1, dt)
self.ocm.commit()
self.op1.refresh_from_db()
assert self.op1.valid_from == dt
assert self.op1.secret == old_secret
@classscope(attr='o')
def test_set_valid_until(self):
self.event.settings.ticket_secret_generator = "pretix_sig1"
assign_ticket_secret(self.event, self.op1, force_invalidate=True, save=True)
old_secret = self.op1.secret
dt = make_aware(datetime(2022, 9, 20, 15, 0, 0, 0))
self.ocm.change_valid_until(self.op1, dt)
self.ocm.commit()
self.op1.refresh_from_db()
assert self.op1.secret != old_secret
@classscope(attr='o')
def test_unset_valid_from_until(self):
self.op1.valid_from = make_aware(datetime(2016, 9, 20, 15, 0, 0, 0))
self.op1.valid_until = make_aware(datetime(2016, 9, 20, 15, 0, 0, 0))
self.op1.save()
self.ocm.change_valid_from(self.op1, None)
self.ocm.change_valid_until(self.op1, None)
self.ocm.commit()
self.op1.refresh_from_db()
assert self.op1.valid_from is None
assert self.op1.valid_until is None
@pytest.mark.django_db
def test_autocheckin(clist_autocheckin, event):