# # This file is part of pretix (Community Edition). # # Copyright (C) 2014-2020 Raphael Michel and contributors # Copyright (C) 2020-today pretix GmbH and contributors # # This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General # Public License as published by the Free Software Foundation in version 3 of the License. # # ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are # applicable granting you additional permissions and placing additional restrictions on your usage of this software. # Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive # this file, see . # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more # details. # # You should have received a copy of the GNU Affero General Public License along with this program. If not, see # . # # This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of # the Apache License 2.0 can be obtained at . # # This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A # full history of changes and contributors is available at . # # This file contains Apache-licensed contributions copyrighted by: Flavia Bastos # # Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under the License. import datetime import re from decimal import Decimal from bs4 import BeautifulSoup from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.utils.timezone import now from django_scopes import scopes_disabled from pretix.base.models import ( Event, Item, ItemCategory, ItemVariation, Order, OrderPosition, Organizer, Question, Quota, ) from pretix.base.models.orders import OrderFee, OrderPayment from pretix.base.reldate import RelativeDate, RelativeDateWrapper from pretix.base.services.invoices import generate_invoice class BaseOrdersTest(TestCase): @scopes_disabled() def setUp(self): super().setUp() self.orga = Organizer.objects.create(name='CCC', slug='ccc', plugins='pretix.plugins.banktransfer') self.event = Event.objects.create( organizer=self.orga, name='30C3', slug='30c3', date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), plugins='pretix.plugins.stripe,pretix.plugins.banktransfer,tests.testdummy', live=True ) self.event.settings.set('payment_banktransfer__enabled', True) self.event.settings.set('ticketoutput_testdummy__enabled', True) self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0) self.quota_shirts = Quota.objects.create(event=self.event, name='Shirts', size=2) self.shirt = Item.objects.create(event=self.event, name='T-Shirt', category=self.category, default_price=12) self.quota_shirts.items.add(self.shirt) self.shirt_red = ItemVariation.objects.create(item=self.shirt, default_price=14, value="Red") self.shirt_blue = ItemVariation.objects.create(item=self.shirt, value="Blue") self.quota_shirts.variations.add(self.shirt_red) self.quota_shirts.variations.add(self.shirt_blue) self.quota_tickets = Quota.objects.create(event=self.event, name='Tickets', size=5) self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', category=self.category, default_price=23, admission=True, personalized=True) self.quota_tickets.items.add(self.ticket) self.event.settings.set('attendee_names_asked', True) self.question = Question.objects.create(question='Foo', type=Question.TYPE_STRING, event=self.event, required=False) self.ticket.questions.add(self.question) self.order = Order.objects.create( status=Order.STATUS_PENDING, event=self.event, email='admin@localhost', datetime=now() - datetime.timedelta(days=3), expires=now() + datetime.timedelta(days=11), total=Decimal("23"), sales_channel=self.orga.sales_channels.get(identifier="web"), locale='en' ) self.ticket_pos = OrderPosition.objects.create( order=self.order, item=self.ticket, variation=None, price=Decimal("23"), attendee_name_parts={'full_name': "Peter"} ) self.deleted_pos = OrderPosition.objects.create( order=self.order, item=self.ticket, variation=None, price=Decimal("23"), attendee_name_parts={'full_name': "Lukas"}, canceled=True ) self.not_my_order = Order.objects.create( status=Order.STATUS_PENDING, event=self.event, email='user@localhost', datetime=now() - datetime.timedelta(days=3), expires=now() + datetime.timedelta(days=11), total=Decimal("23"), sales_channel=self.orga.sales_channels.get(identifier="web"), ) class OrdersTest(BaseOrdersTest): def test_unknown_order(self): response = self.client.get( '/%s/%s/order/ABCDE/123/' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/%s/123/' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/ABCDE/123/pay' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/%s/123/pay' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/ABCDE/123/pay/confirm' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/%s/123/pay/confirm' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/ABCDE/123/modify' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/%s/123/modify' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/ABCDE/123/cancel' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/%s/123/cancel' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.post( '/%s/%s/order/ABCDE/123/cancel/do' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.post( '/%s/%s/order/%s/123/cancel/do' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 def test_unknown_position(self): response = self.client.get( '/%s/%s/ticket/ABCDE/1/123/' % (self.orga.slug, self.event.slug) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/1/123/' % (self.orga.slug, self.event.slug, self.order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/1/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/1/123/' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.deleted_pos.positionid, self.deleted_pos.web_secret) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/1/123/modify' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.deleted_pos.positionid, self.deleted_pos.web_secret) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/1/123/change' % (self.orga.slug, self.event.slug, self.not_my_order.code) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.deleted_pos.positionid, self.deleted_pos.web_secret) ) assert response.status_code == 404 def test_orders_confirm_email(self): response = self.client.get( '/%s/%s/order/%s/%s/open/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, 'aabbccdd') ) assert response.status_code == 302 self.order.refresh_from_db() assert not self.order.email_known_to_work response = self.client.get( '/%s/%s/order/%s/%s/open/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.order.email_confirm_secret()) ) assert response.status_code == 302 self.order.refresh_from_db() assert self.order.email_known_to_work def test_orders_detail(self): response = self.client.get( '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 doc = BeautifulSoup(response.content.decode(), "lxml") assert len(doc.select(".cart-row")) > 0 assert "pending" in doc.select(".order-details")[0].text.lower() assert "Peter" in response.content.decode() assert "Lukas" not in response.content.decode() def test_ticket_detail(self): response = self.client.get( '/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret) ) assert response.status_code == 200 doc = BeautifulSoup(response.content.decode(), "lxml") assert len(doc.select(".cart-row")) > 0 assert "pending" in doc.select(".order-details")[0].text.lower() assert "Peter" in response.content.decode() assert "Lukas" not in response.content.decode() def test_orders_modify_invalid(self): self.order.status = Order.STATUS_CANCELED self.order.save() self.client.get( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) with scopes_disabled(): self.order = Order.objects.get(id=self.order.id) assert self.order.status == Order.STATUS_CANCELED def test_orders_modify_attendee_optional(self): self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', False) response = self.client.get( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_0"]' % self.ticket_pos.id)), 1) # Not all fields filled out, expect success response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-attendee_name_parts_0' % self.ticket_pos.id: '', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) with scopes_disabled(): self.ticket_pos = OrderPosition.objects.get(id=self.ticket_pos.id) assert self.ticket_pos.attendee_name in (None, '') def test_orders_modify_attendee_required(self): self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', True) response = self.client.get( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_0"]' % self.ticket_pos.id)), 1) assert "Peter" in response.content.decode() assert "Lukas" not in response.content.decode() # Not all required fields filled out, expect failure response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-attendee_name_parts_0' % self.ticket_pos.id: '', }, follow=True) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertGreaterEqual(len(doc.select('.has-error')), 1) response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-attendee_name_parts_0' % self.ticket_pos.id: 'Peter', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) with scopes_disabled(): self.ticket_pos = OrderPosition.objects.get(id=self.ticket_pos.id) assert self.ticket_pos.attendee_name == 'Peter' def test_orders_questions_optional(self): self.event.settings.set('attendee_names_asked', False) self.event.settings.set('attendee_names_required', False) response = self.client.get( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertEqual(len(doc.select('input[name="%s-question_%s"]' % ( self.ticket_pos.id, self.question.id))), 1) # Not all fields filled out, expect success response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): '', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) with scopes_disabled(): assert not self.ticket_pos.answers.filter(question=self.question).exists() def test_orders_questions_required(self): self.event.settings.set('attendee_names_asked', False) self.event.settings.set('attendee_names_required', False) self.question.required = True self.question.save() response = self.client.get('/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertEqual(len(doc.select('input[name="%s-question_%s"]' % ( self.ticket_pos.id, self.question.id))), 1) # Not all required fields filled out, expect failure response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): '', 'transmission_type': 'email', }, follow=True) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertGreaterEqual(len(doc.select('.has-error')), 1) response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) with scopes_disabled(): assert self.ticket_pos.answers.get(question=self.question).answer == 'ABC' def test_modify_invoice_address_validated(self): self.event.settings.set('invoice_reissue_after_modify', True) self.event.settings.set('invoice_address_asked', True) with scopes_disabled(): generate_invoice(self.order) response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) # Only questions changed with scopes_disabled(): assert self.order.invoices.count() == 1 response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC', 'zipcode': 'XXINVALIDXX', 'street': 'Main Street', 'city': 'Heidelberg', 'country': 'DE', 'transmission_type': 'email', }, follow=True) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertGreaterEqual(len(doc.select('.has-error')), 1) def test_modify_invoice_regenerate(self): self.event.settings.set('invoice_reissue_after_modify', True) self.event.settings.set('invoice_address_asked', True) with scopes_disabled(): generate_invoice(self.order) response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) # Only questions changed with scopes_disabled(): assert self.order.invoices.count() == 1 response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC', 'zipcode': '12345', 'street': 'Main Street', 'city': 'Heidelberg', 'country': 'DE', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) with scopes_disabled(): assert self.order.invoices.count() == 3 self.event.settings.set('invoice_reissue_after_modify', False) response = self.client.post( '/%s/%s/order/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { '%s-question_%s' % (self.ticket_pos.id, self.question.id): 'ABC', 'zipcode': '54321', 'street': 'Main Street', 'city': 'Heidelberg', 'country': 'DE', 'transmission_type': 'email', }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) with scopes_disabled(): assert self.order.invoices.count() == 3 def test_orders_attendee_modify_invalid(self): self.order.status = Order.STATUS_CANCELED self.order.save() self.event.settings.set('allow_modifications', 'attendee') r = self.client.get( '/%s/%s/ticket/%s/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret) ) assert r.status_code == 302 def test_orders_attendee_modify_forbidden(self): self.event.settings.set('allow_modifications', 'order') r = self.client.get( '/%s/%s/ticket/%s/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret) ) assert r.status_code == 302 def test_orders_attendee_modify_attendee_optional(self): self.event.settings.set('allow_modifications', 'attendee') self.event.settings.set('attendee_names_asked', True) self.event.settings.set('attendee_names_required', False) response = self.client.get( '/%s/%s/ticket/%s/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret) ) doc = BeautifulSoup(response.content.decode(), "lxml") self.assertEqual(len(doc.select('input[name="%s-attendee_name_parts_0"]' % self.ticket_pos.id)), 1) # Not all fields filled out, expect success response = self.client.post( '/%s/%s/ticket/%s/%s/%s/modify' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret), { 'transmission_type': 'email', } ) print(response.content.decode()) self.assertRedirects(response, '/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret), target_status_code=200) with scopes_disabled(): self.ticket_pos = OrderPosition.objects.get(id=self.ticket_pos.id) assert self.ticket_pos.attendee_name in (None, '') def test_orders_cancel_invalid(self): self.order.status = Order.STATUS_PAID self.order.save() r = self.client.post( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) assert 'btn-danger' not in r.content.decode() self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID def test_orders_cancel(self): response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_CANCELED def test_orders_cancel_paid(self): self.event.settings.cancel_allow_user_paid = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_CANCELED def test_orders_cancel_paid_request(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_require_approval = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('23.00') with scopes_disabled(): assert not self.order.refunds.exists() r = self.order.cancellation_requests.get() assert r.cancellation_fee == Decimal('3.00') def test_orders_cancel_partially_paid_no_selfservice(self): self.order.status = Order.STATUS_PENDING self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total - Decimal("1.00"), state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_require_approval = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 302 def test_orders_cancel_free_no_request(self): self.order.status = Order.STATUS_PAID self.order.total = Decimal('0.00') self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_require_approval = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_CANCELED with scopes_disabled(): assert not self.order.refunds.exists() assert not self.order.cancellation_requests.exists() def test_orders_cancel_free_ignore_fixed_fee(self): self.order.status = Order.STATUS_PAID self.order.total = Decimal('0.00') self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_require_approval = True self.event.settings.cancel_allow_user_paid_adjust_fees = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'cancel_fee': '3.00' }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_CANCELED with scopes_disabled(): assert not self.order.refunds.exists() assert not self.order.cancellation_requests.exists() def test_orders_cancel_paid_fee_autorefund_gift_card_optional(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_refund_as_giftcard = 'option' response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'manually' not in response.content.decode() assert "gift card" in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'giftcard': 'true' }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) assert "gift card" in response.content.decode() self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('3.00') with scopes_disabled(): r = self.order.refunds.get() assert r.provider == "giftcard" assert r.amount == Decimal('20.00') def test_orders_cancel_paid_fee_autorefund_gift_card_force(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_refund_as_giftcard = 'force' response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'manually' not in response.content.decode() assert "gift card" in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment_giftcard-code': 'false' }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) assert "gift card" in response.content.decode() self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('3.00') with scopes_disabled(): r = self.order.refunds.get() assert r.provider == "giftcard" assert r.amount == Decimal('20.00') def test_orders_cancel_autorefund_gift_card_customer(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): customer = self.orga.customers.create(email='john@example.org', is_verified=True) customer.set_password('foo') customer.save() self.order.customer = customer self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_refund_as_giftcard = 'option' gc = customer.usable_gift_cards() assert len(gc) == 0 response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'manually' not in response.content.decode() assert "gift card" in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'giftcard': 'true' }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) assert "gift card" in response.content.decode() self.order.refresh_from_db() assert self.order.status == Order.STATUS_CANCELED with scopes_disabled(): r = self.order.refunds.get() assert r.provider == "giftcard" assert r.amount == Decimal('23.00') gc = customer.usable_gift_cards() assert len(gc) == 1 def test_orders_cancel_unpaid_fee(self): self.order.status = Order.STATUS_PENDING self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CREATED) self.event.settings.cancel_allow_user = True self.event.settings.cancel_allow_user_paid = False self.event.settings.cancel_allow_user_unpaid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_keep = Decimal('7.00') response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'manually' not in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PENDING assert self.order.total == Decimal('3.00') with scopes_disabled(): assert self.order.refunds.count() == 0 def test_orders_cancel_paid_fee_autorefund(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'manually' not in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('3.00') with scopes_disabled(): assert self.order.refunds.count() == 1 def test_orders_cancel_paid_custom_fee_autorefund(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_adjust_fees = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'cancel_fee': '6.00' }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('6.00') with scopes_disabled(): assert self.order.refunds.count() == 1 def test_orders_cancel_paid_custom_fee_limit(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') self.event.settings.cancel_allow_user_paid_adjust_fees = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'cancel_fee': '2.00' }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('23.00') with scopes_disabled(): assert self.order.refunds.count() == 0 def test_orders_cancel_paid_fee_no_autorefund(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): self.order.payments.create(provider='testdummy', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED) self.event.settings.cancel_allow_user_paid = True self.event.settings.cancel_allow_user_paid_keep = Decimal('3.00') response = self.client.get( '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'cancellation fee of €3.00' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 assert 'manually' in response.content.decode() assert '20.00' in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PAID assert self.order.total == Decimal('3.00') with scopes_disabled(): assert self.order.refunds.count() == 0 def test_orders_cancel_forbidden_if_any_payment_made(self): self.event.settings.set('cancel_allow_user', True) self.event.settings.set('cancel_allow_user_paid', False) with scopes_disabled(): self.order.payments.create( state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=12, provider='manual', ) self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PENDING def test_orders_cancel_paid_checkin_list(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): cl = self.event.checkin_lists.create(name="Foo") self.order.positions.first().checkins.create(list=cl) self.event.settings.cancel_allow_user_paid = True response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 302 cl.consider_tickets_used = False cl.save() response = self.client.get( '/%s/%s/order/%s/%s/cancel' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 def test_orders_cancel_forbidden(self): self.event.settings.set('cancel_allow_user', False) self.client.post( '/%s/%s/order/%s/%s/cancel/do' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { }, follow=True) self.order.refresh_from_db() assert self.order.status == Order.STATUS_PENDING def test_invoice_create_notallowed(self): self.event.settings.set('invoice_generate', 'no') response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True) assert 'alert-danger' in response.content.decode() def test_invoice_create_onlypaid(self): self.event.settings.set('invoice_generate', 'user_paid') response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True) assert 'alert-danger' in response.content.decode() self.order.status = Order.STATUS_PAID self.order.save() response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True) assert 'alert-success' in response.content.decode() with scopes_disabled(): assert self.order.invoices.exists() def test_invoice_create_duplicate(self): self.event.settings.set('invoice_generate', 'user') with scopes_disabled(): generate_invoice(self.order) response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True) assert 'alert-danger' in response.content.decode() def test_invoice_create_wrong_secret(self): self.event.settings.set('invoice_generate', 'user') with scopes_disabled(): generate_invoice(self.order) response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, '1234'), {}) assert 404 == response.status_code def test_invoice_create_require_payment(self): self.event.settings.set('invoice_generate', 'user') response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True) assert 'alert-danger' in response.content.decode() with scopes_disabled(): assert not self.order.invoices.exists() def test_invoice_create_ok(self): self.event.settings.set('invoice_generate', 'user') with scopes_disabled(): self.order.payments.create(provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=self.order.total) response = self.client.post( '/%s/%s/order/%s/%s/invoice' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True) assert 'alert-success' in response.content.decode() with scopes_disabled(): assert self.order.invoices.exists() def test_orders_download_pending(self): self.event.settings.set('ticket_download', True) del self.event.settings['ticket_download_date'] self.order.status = Order.STATUS_PENDING self.order.save() self.event.settings.set('ticket_download_pending', True) response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) assert response.status_code == 200 def test_orders_download_pending_only_approved(self): self.event.settings.set('ticket_download', True) del self.event.settings['ticket_download_date'] self.order.status = Order.STATUS_PENDING self.order.require_approval = True self.order.save() self.event.settings.set('ticket_download_pending', True) response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), ) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) def test_ticket_download(self): self.event.settings.set('ticket_download', True) del self.event.settings['ticket_download_date'] self.order.status = Order.STATUS_PAID self.order.save() response = self.client.post( '/%s/%s/ticket/%s/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret, self.ticket_pos.pk), follow=True) assert response.status_code == 200 def test_orders_download(self): self.event.settings.set('ticket_download', True) del self.event.settings['ticket_download_date'] response = self.client.post( '/%s/%s/order/%s/%s/download/%d/pdf' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) response = self.client.post( '/%s/%s/order/ABC/123/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.ticket_pos.pk) ) assert response.status_code == 404 response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.order.status = Order.STATUS_PAID self.order.save() response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) assert response.status_code == 200 self.event.settings.set('ticket_download_date', now() + datetime.timedelta(days=1)) response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) self.event.date_from = now() + datetime.timedelta(days=3) self.event.save() self.event.settings.set('ticket_download_date', RelativeDateWrapper(RelativeDate( base_date_name='date_from', days=2, time=None, minutes=None ))) response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) del self.event.settings['ticket_download_date'] response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) assert response.status_code == 200 self.event.settings.set('ticket_download', False) response = self.client.post( '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, self.ticket_pos.pk), follow=True ) self.assertRedirects(response, '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), target_status_code=200) def test_change_paymentmethod_wrong_secret(self): response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, '123')) assert response.status_code == 404 def test_change_paymentmethod_wrong_state(self): self.order.status = Order.STATUS_PAID self.order.save() response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), follow=True ) assert 'alert-danger' in response.content.decode() def test_change_paymentmethod_expired_not_available(self): self.order.status = Order.STATUS_EXPIRED self.order.save() self.quota_tickets.size = 0 self.quota_tickets.save() response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), follow=True ) assert 'alert-danger' in response.content.decode() def test_pay_wrong_payment_state(self): with scopes_disabled(): p = self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CANCELED, amount=Decimal('10.00'), ) response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/complete' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() def test_pay_expired_not_available(self): self.order.status = Order.STATUS_EXPIRED self.order.save() self.quota_tickets.size = 0 self.quota_tickets.save() with scopes_disabled(): p = self.order.payments.create( provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=Decimal('10.00'), ) response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/complete' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() def test_pay_wrong_order_state(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): p = self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_PENDING, amount=Decimal('10.00'), ) response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() response = self.client.get( '/%s/%s/order/%s/%s/pay/%d/complete' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), follow=True ) assert 'alert-danger' in response.content.decode() def test_pay_change_link(self): self.order.status = Order.STATUS_PAID self.order.save() with scopes_disabled(): p = self.order.payments.create( provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=self.order.total, ) response = self.client.get( '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), follow=True ) assert '/pay/change' not in response.content.decode() self.order.status = Order.STATUS_PENDING self.order.save() p.state = OrderPayment.PAYMENT_STATE_PENDING p.save() response = self.client.get( '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), follow=True ) assert '/pay/change' in response.content.decode() p.provider = 'testdummy' p.save() response = self.client.get( '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), follow=True ) assert '/pay/change' not in response.content.decode() def test_change_paymentmethod_partial(self): self.event.settings.set('payment_banktransfer__enabled', True) self.event.settings.set('payment_testdummy__enabled', True) self.event.settings.set('payment_testdummy__fee_reverse_calc', False) self.event.settings.set('payment_testdummy__fee_percent', '10.00') with scopes_disabled(): self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('10.00'), ) generate_invoice(self.order) response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Test dummy' in response.content.decode() assert '+ €1.30' in response.content.decode() self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'testdummy' } ) self.order.refresh_from_db() with scopes_disabled(): assert self.order.payments.last().provider == 'testdummy' fee = self.order.fees.filter(fee_type=OrderFee.FEE_TYPE_PAYMENT).last() assert fee.value == Decimal('1.30') assert self.order.total == Decimal('23.00') + fee.value assert self.order.invoices.count() == 3 p = self.order.payments.last() assert p.provider == 'testdummy' assert p.state == OrderPayment.PAYMENT_STATE_CREATED assert p.amount == Decimal('14.30') def test_change_paymentmethod_partial_with_previous_fee(self): self.event.settings.set('payment_banktransfer__enabled', True) self.event.settings.set('payment_testdummy__enabled', True) self.event.settings.set('payment_testdummy__fee_reverse_calc', False) self.event.settings.set('payment_testdummy__fee_percent', '10.00') with scopes_disabled(): f = self.order.fees.create( fee_type=OrderFee.FEE_TYPE_PAYMENT, value='1.40' ) self.order.total += Decimal('1.4') self.order.save() self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('11.40'), fee=f ) generate_invoice(self.order) response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Test dummy' in response.content.decode() assert '+ €1.30' in response.content.decode() self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'testdummy' } ) self.order.refresh_from_db() with scopes_disabled(): assert self.order.payments.last().provider == 'testdummy' fee = self.order.fees.filter(fee_type=OrderFee.FEE_TYPE_PAYMENT).last() assert fee.value == Decimal('1.30') assert self.order.total == Decimal('24.40') + fee.value assert self.order.invoices.count() == 3 p = self.order.payments.last() assert p.provider == 'testdummy' assert p.state == OrderPayment.PAYMENT_STATE_CREATED assert p.amount == Decimal('14.30') self.client.get( '/%s/%s/order/%s/%s/pay/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), {} ) self.client.get( '/%s/%s/order/%s/%s/pay/%s/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), {} ) p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CREATED def test_change_paymentmethod_to_same(self): with scopes_disabled(): p_old = self.order.payments.create( provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=Decimal('10.00'), ) self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'banktransfer' } ) self.order.refresh_from_db() with scopes_disabled(): p_new = self.order.payments.last() assert p_new.provider == 'banktransfer' assert p_new.id != p_old.id assert p_new.state == OrderPayment.PAYMENT_STATE_CREATED p_old.refresh_from_db() assert p_old.state == OrderPayment.PAYMENT_STATE_CANCELED def test_change_paymentmethod_cancel_old(self): self.event.settings.set('payment_banktransfer__enabled', True) with scopes_disabled(): p_old = self.order.payments.create( provider='testdummy', state=OrderPayment.PAYMENT_STATE_CREATED, amount=Decimal('10.00'), ) self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'banktransfer' } ) self.order.refresh_from_db() with scopes_disabled(): p_new = self.order.payments.last() assert p_new.provider == 'banktransfer' assert p_new.id != p_old.id assert p_new.state == OrderPayment.PAYMENT_STATE_CREATED p_old.refresh_from_db() assert p_old.state == OrderPayment.PAYMENT_STATE_CANCELED def test_change_paymentmethod_delete_fee(self): self.event.settings.set('payment_banktransfer__enabled', True) self.event.settings.set('payment_testdummy__enabled', True) self.event.settings.set('payment_testdummy__fee_reverse_calc', False) self.event.settings.set('payment_testdummy__fee_percent', '0.00') with scopes_disabled(): f = self.order.fees.create( fee_type=OrderFee.FEE_TYPE_PAYMENT, value='1.40' ) self.order.total += Decimal('1.4') self.order.save() p0 = self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CREATED, amount=Decimal('24.40'), fee=f ) generate_invoice(self.order) response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Test dummy' in response.content.decode() assert '- €1.40' in response.content.decode() self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'testdummy' } ) with scopes_disabled(): self.order.refresh_from_db() assert self.order.payments.last().provider == 'testdummy' assert not self.order.fees.filter(fee_type=OrderFee.FEE_TYPE_PAYMENT).exists() assert self.order.total == Decimal('23.00') assert self.order.invoices.count() == 3 p0.refresh_from_db() assert p0.state == OrderPayment.PAYMENT_STATE_CANCELED p = self.order.payments.last() assert p.provider == 'testdummy' assert p.state == OrderPayment.PAYMENT_STATE_CREATED assert p.amount == Decimal('23.00') def test_change_paymentmethod_available(self): self.event.settings.set('payment_banktransfer__enabled', True) self.event.settings.set('payment_testdummy__enabled', True) self.event.settings.set('payment_testdummy__fee_abs', '12.00') with scopes_disabled(): generate_invoice(self.order) self.order.payments.create( provider='banktransfer', state=OrderPayment.PAYMENT_STATE_PENDING, amount=self.order.total, ) response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Test dummy' in response.content.decode() assert '+ €12.00' in response.content.decode() self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'testdummy' } ) self.order.refresh_from_db() with scopes_disabled(): p = self.order.payments.last() assert p.provider == 'testdummy' assert p.state == OrderPayment.PAYMENT_STATE_CREATED p0 = self.order.payments.first() assert p0.state == OrderPayment.PAYMENT_STATE_CANCELED assert p0.provider == 'banktransfer' fee = self.order.fees.get(fee_type=OrderFee.FEE_TYPE_PAYMENT) assert fee.value == Decimal('12.00') assert self.order.total == Decimal('23.00') + fee.value assert self.order.invoices.count() == 3 def test_change_paymentmethod_giftcard_partial(self): with scopes_disabled(): self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('10.00'), ) gc = self.orga.issued_gift_cards.create(currency="EUR") gc.transactions.create(value=10, acceptor=self.orga) response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Gift card' in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) with scopes_disabled(): p = self.order.payments.last() self.assertRedirects( response, '/%s/%s/order/%s/%s/pay/%s/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), ) self.client.post( '/%s/%s/order/%s/%s/pay/%s/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), {} ) self.order.refresh_from_db() p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED assert self.order.status == Order.STATUS_PENDING assert gc.value == Decimal('0.00') assert self.order.pending_sum == Decimal('3.00') def test_change_paymentmethod_giftcard_swap_card(self): with scopes_disabled(): self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('10.00'), ) gc = self.orga.issued_gift_cards.create(currency="EUR") gc.transactions.create(value=10, acceptor=self.orga) self.ticket.issue_giftcard = True self.ticket.save() response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) assert "You cannot pay with gift cards when buying a gift card." in response.content.decode() def test_change_paymentmethod_giftcard_wrong_currency(self): with scopes_disabled(): gc = self.orga.issued_gift_cards.create(currency="USD") gc.transactions.create(value=10, acceptor=self.orga) response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) assert "This gift card does not support this currency." in response.content.decode() def test_change_paymentmethod_giftcard_in_test_mode(self): with scopes_disabled(): self.order.testmode = True self.order.save() gc = self.orga.issued_gift_cards.create(currency="EUR") gc.transactions.create(value=10, acceptor=self.orga) response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) assert "Only test gift cards can be used in test mode." in response.content.decode() def test_change_paymentmethod_giftcard_not_in_test_mode(self): with scopes_disabled(): gc = self.orga.issued_gift_cards.create(currency="EUR", testmode=True) gc.transactions.create(value=10, acceptor=self.orga) response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) assert "This gift card can only be used in test mode." in response.content.decode() def test_change_paymentmethod_giftcard_empty(self): with scopes_disabled(): gc = self.orga.issued_gift_cards.create(currency="EUR") response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) assert "All credit on this gift card has been used." in response.content.decode() def test_change_paymentmethod_giftcard_wrong_organizer(self): with scopes_disabled(): o = Organizer.objects.create(slug='Foo', name='bar') self.orga.issued_gift_cards.create(currency="EUR") gc = o.issued_gift_cards.create(currency="EUR") gc.transactions.create(value=10, acceptor=self.orga) response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) assert "This gift card is not known." in response.content.decode() def test_change_paymentmethod_giftcard(self): with scopes_disabled(): self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('10.00'), ) gc = self.orga.issued_gift_cards.create(currency="EUR") gc.transactions.create(value=100, acceptor=self.orga) response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Gift card' in response.content.decode() response = self.client.post( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), { 'payment': 'giftcard', 'payment_giftcard-code': gc.secret } ) with scopes_disabled(): p = self.order.payments.last() self.assertRedirects( response, '/%s/%s/order/%s/%s/pay/%s/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), ) self.client.post( '/%s/%s/order/%s/%s/pay/%s/confirm' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, p.pk), {} ) self.order.refresh_from_db() p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED assert self.order.status == Order.STATUS_PAID assert gc.value == Decimal('87.00') def test_change_paymentmethod_customeraccount_giftcard_offered(self): with scopes_disabled(): self.orga.settings.customer_accounts = True customer = self.orga.customers.create(email='john@example.org', is_verified=True) customer.set_password('foo') customer.save() self.order.customer = customer self.order.payments.create( provider='manual', state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('10.00'), ) gc = self.orga.issued_gift_cards.create(currency="EUR", customer=customer) gc.transactions.create(value=100, acceptor=self.orga) ugc = customer.usable_gift_cards() assert len(ugc) == 1 r = self.client.post('/%s/account/login' % (self.orga.slug), { 'email': 'john@example.org', 'password': 'foo', }) assert r.status_code == 302 r = self.client.get('/%s/account/' % (self.orga.slug)) assert r.status_code == 200 response = self.client.get( '/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), ) assert 'Gift card' in response.content.decode() assert '1 available' in response.content.decode() def test_answer_download_token(self): with scopes_disabled(): q = self.event.questions.create(question="Foo", type="F") q.items.add(self.ticket) a = self.ticket_pos.answers.create(question=q, answer="file") val = SimpleUploadedFile("testfile.txt", b"file_content") a.file.save("testfile.txt", val) a.save() self.event.settings.set('ticket_download', True) del self.event.settings['ticket_download_date'] response = self.client.get( '/%s/%s/order/%s/%s/answer/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, a.pk) ) assert response.status_code == 404 response = self.client.get( '/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret) ) assert response.status_code == 200 match = re.search(r"\?token=([^'\"&]+)", response.content.decode()) assert match response = self.client.get( '/%s/%s/order/%s/%s/answer/%s/?token=%s' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, a.pk, match.group(1)) ) assert response.status_code == 200 client2 = self.client_class() response = client2.get( '/%s/%s/order/%s/%s/answer/%s/?token=%s' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret, a.pk, match.group(1)) ) assert response.status_code == 404