mirror of
https://github.com/pretix/pretix.git
synced 2026-01-27 01:02:28 +00:00
1964 lines
72 KiB
Python
1964 lines
72 KiB
Python
#
|
|
# This file is part of pretix (Community Edition).
|
|
#
|
|
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
|
# Copyright (C) 2020-2021 rami.io 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 <https://pretix.eu/about/en/license>.
|
|
#
|
|
# 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
|
|
# <https://www.gnu.org/licenses/>.
|
|
#
|
|
import copy
|
|
import datetime
|
|
import json
|
|
from decimal import Decimal
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
from django.core import mail as djmail
|
|
from django.utils.timezone import now
|
|
from django_countries.fields import Country
|
|
from django_scopes import scopes_disabled
|
|
from stripe import error
|
|
from tests.plugins.stripe.test_checkout import apple_domain_create
|
|
from tests.plugins.stripe.test_provider import MockedCharge
|
|
|
|
from pretix.base.models import InvoiceAddress, Order, OrderPosition
|
|
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
|
|
|
|
|
@pytest.fixture
|
|
def item(event):
|
|
return event.items.create(name="Budget Ticket", default_price=23)
|
|
|
|
|
|
@pytest.fixture
|
|
def item2(event2):
|
|
return event2.items.create(name="Budget Ticket", default_price=23)
|
|
|
|
|
|
@pytest.fixture
|
|
def taxrule(event):
|
|
return event.tax_rules.create(rate=Decimal('19.00'))
|
|
|
|
|
|
@pytest.fixture
|
|
def question(event, item):
|
|
q = event.questions.create(question="T-Shirt size", type="S", identifier="ABC")
|
|
q.items.add(item)
|
|
q.options.create(answer="XL", identifier="LVETRWVU")
|
|
return q
|
|
|
|
|
|
@pytest.fixture
|
|
def question2(event2, item2):
|
|
q = event2.questions.create(question="T-Shirt size", type="S", identifier="ABC")
|
|
q.items.add(item2)
|
|
return q
|
|
|
|
|
|
@pytest.fixture
|
|
def quota(event, item):
|
|
q = event.quotas.create(name="Budget Quota", size=200)
|
|
q.items.add(item)
|
|
return q
|
|
|
|
|
|
@pytest.fixture
|
|
def order(event, item, taxrule, question):
|
|
testtime = datetime.datetime(2017, 12, 1, 10, 0, 0, tzinfo=datetime.timezone.utc)
|
|
event.plugins += ",pretix.plugins.stripe"
|
|
event.save()
|
|
|
|
with mock.patch('django.utils.timezone.now') as mock_now:
|
|
mock_now.return_value = testtime
|
|
o = Order.objects.create(
|
|
code='FOO', event=event, email='dummy@dummy.test',
|
|
status=Order.STATUS_PENDING, secret="k24fiuwvu8kxz3y1",
|
|
datetime=datetime.datetime(2017, 12, 1, 10, 0, 0, tzinfo=datetime.timezone.utc),
|
|
expires=datetime.datetime(2017, 12, 10, 10, 0, 0, tzinfo=datetime.timezone.utc),
|
|
sales_channel=event.organizer.sales_channels.get(identifier="web"),
|
|
total=23, locale='en'
|
|
)
|
|
p1 = o.payments.create(
|
|
provider='stripe',
|
|
state='refunded',
|
|
amount=Decimal('23.00'),
|
|
payment_date=testtime,
|
|
)
|
|
o.refunds.create(
|
|
provider='stripe',
|
|
state='done',
|
|
source='admin',
|
|
amount=Decimal('23.00'),
|
|
execution_date=testtime,
|
|
payment=p1,
|
|
)
|
|
o.payments.create(
|
|
provider='banktransfer',
|
|
state='pending',
|
|
amount=Decimal('23.00'),
|
|
)
|
|
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
|
|
tax_value=Decimal('0.05'), tax_rule=taxrule)
|
|
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
|
|
tax_value=Decimal('0.05'), tax_rule=taxrule, canceled=True)
|
|
InvoiceAddress.objects.create(order=o, company="Sample company", country=Country('NZ'),
|
|
vat_id="DE123", vat_id_validated=True, custom_field="Custom info")
|
|
op = OrderPosition.objects.create(
|
|
order=o,
|
|
item=item,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={"full_name": "Peter", "_scheme": "full"},
|
|
secret="z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
|
pseudonymization_id="ABCDEFGHKL",
|
|
positionid=1,
|
|
)
|
|
OrderPosition.objects.create(
|
|
order=o,
|
|
item=item,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={"full_name": "Peter", "_scheme": "full"},
|
|
secret="YBiYJrmF5ufiTLdV1iDf",
|
|
pseudonymization_id="JKLM",
|
|
canceled=True,
|
|
positionid=2,
|
|
)
|
|
op.answers.create(question=question, answer='S')
|
|
return o
|
|
|
|
|
|
@pytest.fixture
|
|
def order2(event2, item2):
|
|
testtime = datetime.datetime(2017, 12, 1, 10, 0, 0, tzinfo=datetime.timezone.utc)
|
|
|
|
with mock.patch('django.utils.timezone.now') as mock_now:
|
|
mock_now.return_value = testtime
|
|
o = Order.objects.create(
|
|
code='BAR', event=event2, email='dummy@dummy.test',
|
|
status=Order.STATUS_PENDING, secret="asd436cvbfd1",
|
|
datetime=datetime.datetime(2017, 12, 1, 10, 0, 0, tzinfo=datetime.timezone.utc),
|
|
expires=datetime.datetime(2017, 12, 10, 10, 0, 0, tzinfo=datetime.timezone.utc),
|
|
sales_channel=event2.organizer.sales_channels.get(identifier="web"),
|
|
total=23, locale='en'
|
|
)
|
|
o.payments.create(
|
|
provider='banktransfer',
|
|
state='pending',
|
|
amount=Decimal('23.00'),
|
|
)
|
|
OrderPosition.objects.create(
|
|
order=o,
|
|
item=item2,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={"full_name": "Peter", "_scheme": "full"},
|
|
secret="asdlfksdgdfgxcbfgdhfg",
|
|
pseudonymization_id="AC892345",
|
|
positionid=1,
|
|
)
|
|
return o
|
|
|
|
|
|
@pytest.fixture
|
|
def clist_autocheckin(event):
|
|
c = event.checkin_lists.create(name="Default", all_products=True)
|
|
c.auto_checkin_sales_channels.add(event.organizer.sales_channels.get(identifier="web"))
|
|
return c
|
|
|
|
|
|
TEST_ORDERPOSITION_RES = {
|
|
"id": 1,
|
|
"order": "FOO",
|
|
"positionid": 1,
|
|
"item": 1,
|
|
"variation": None,
|
|
"price": "23.00",
|
|
"attendee_name_parts": {"full_name": "Peter", "_scheme": "full"},
|
|
"attendee_name": "Peter",
|
|
"attendee_email": None,
|
|
"voucher": None,
|
|
"voucher_budget_use": None,
|
|
"discount": None,
|
|
"tax_rate": "0.00",
|
|
"tax_value": "0.00",
|
|
"tax_rule": None,
|
|
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
|
|
"addon_to": None,
|
|
"pseudonymization_id": "ABCDEFGHKL",
|
|
"checkins": [],
|
|
"downloads": [],
|
|
"seat": None,
|
|
"company": None,
|
|
"street": None,
|
|
"zipcode": None,
|
|
"city": None,
|
|
"country": None,
|
|
"state": None,
|
|
"valid_from": None,
|
|
"valid_until": None,
|
|
"blocked": None,
|
|
"answers": [
|
|
{
|
|
"question": 1,
|
|
"answer": "S",
|
|
"question_identifier": "ABC",
|
|
"options": [],
|
|
"option_identifiers": []
|
|
}
|
|
],
|
|
"subevent": None,
|
|
"canceled": False,
|
|
}
|
|
TEST_PAYMENTS_RES = [
|
|
{
|
|
"local_id": 1,
|
|
"created": "2017-12-01T10:00:00Z",
|
|
"payment_date": "2017-12-01T10:00:00Z",
|
|
"provider": "stripe",
|
|
"payment_url": None,
|
|
"details": {
|
|
"id": None,
|
|
"payment_method": None
|
|
},
|
|
"state": "refunded",
|
|
"amount": "23.00"
|
|
},
|
|
{
|
|
"local_id": 2,
|
|
"created": "2017-12-01T10:00:00Z",
|
|
"payment_date": None,
|
|
"provider": "banktransfer",
|
|
"payment_url": None,
|
|
"details": {},
|
|
"state": "pending",
|
|
"amount": "23.00"
|
|
}
|
|
]
|
|
TEST_REFUNDS_RES = [
|
|
{
|
|
"local_id": 1,
|
|
"payment": 1,
|
|
"source": "admin",
|
|
"created": "2017-12-01T10:00:00Z",
|
|
"execution_date": "2017-12-01T10:00:00Z",
|
|
"comment": None,
|
|
"provider": "stripe",
|
|
"details": {"id": None},
|
|
"state": "done",
|
|
"amount": "23.00"
|
|
},
|
|
]
|
|
TEST_ORDER_RES = {
|
|
"code": "FOO",
|
|
"event": "dummy",
|
|
"status": "n",
|
|
"testmode": False,
|
|
"secret": "k24fiuwvu8kxz3y1",
|
|
"email": "dummy@dummy.test",
|
|
"phone": None,
|
|
"locale": "en",
|
|
"customer": None,
|
|
"datetime": "2017-12-01T10:00:00Z",
|
|
"expires": "2017-12-10T10:00:00Z",
|
|
"payment_date": "2017-12-01",
|
|
"sales_channel": "web",
|
|
"fees": [
|
|
{
|
|
"canceled": False,
|
|
"fee_type": "payment",
|
|
"value": "0.25",
|
|
"description": "",
|
|
"internal_type": "",
|
|
"tax_rate": "19.00",
|
|
"tax_value": "0.05"
|
|
}
|
|
],
|
|
"url": "http://example.com/dummy/dummy/order/FOO/k24fiuwvu8kxz3y1/",
|
|
"payment_provider": "banktransfer",
|
|
"total": "23.00",
|
|
"comment": "",
|
|
"api_meta": {},
|
|
"custom_followup_at": None,
|
|
"checkin_attention": False,
|
|
"checkin_text": None,
|
|
"invoice_address": {
|
|
"last_modified": "2017-12-01T10:00:00Z",
|
|
"is_business": False,
|
|
"company": "Sample company",
|
|
"name": "",
|
|
"name_parts": {},
|
|
"street": "",
|
|
"zipcode": "",
|
|
"city": "",
|
|
"country": "NZ",
|
|
"state": "",
|
|
"internal_reference": "",
|
|
"custom_field": "Custom info",
|
|
"vat_id": "DE123",
|
|
"vat_id_validated": True
|
|
},
|
|
"require_approval": False,
|
|
"valid_if_pending": False,
|
|
"positions": [TEST_ORDERPOSITION_RES],
|
|
"downloads": [],
|
|
"payments": TEST_PAYMENTS_RES,
|
|
"refunds": TEST_REFUNDS_RES,
|
|
}
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_list_filter_subevent_date(token_client, organizer, event, order, item, taxrule, subevent, question):
|
|
res = copy.deepcopy(TEST_ORDER_RES)
|
|
with scopes_disabled():
|
|
res["positions"][0]["id"] = order.positions.first().pk
|
|
p = order.positions.first()
|
|
p.subevent = subevent
|
|
p.save()
|
|
fee = order.fees.first()
|
|
res["positions"][0]["item"] = item.pk
|
|
res["positions"][0]["subevent"] = subevent.pk
|
|
res["positions"][0]["answers"][0]["question"] = question.pk
|
|
res["last_modified"] = order.last_modified.isoformat().replace('+00:00', 'Z')
|
|
res["fees"][0]["tax_rule"] = taxrule.pk
|
|
res["fees"][0]["id"] = fee.pk
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?subevent_after={}'.format(
|
|
organizer.slug, event.slug,
|
|
(subevent.date_from + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert resp.status_code == 200
|
|
assert [] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?subevent_after={}'.format(
|
|
organizer.slug, event.slug,
|
|
(subevent.date_from - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert resp.status_code == 200
|
|
assert [res] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?subevent_before={}'.format(
|
|
organizer.slug, event.slug,
|
|
(subevent.date_from - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert resp.status_code == 200
|
|
assert [] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?subevent_before={}'.format(
|
|
organizer.slug, event.slug,
|
|
(subevent.date_from + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert resp.status_code == 200
|
|
assert [res] == resp.data['results']
|
|
|
|
# Test distinct-ness of results
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=order,
|
|
item=item,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
canceled=False,
|
|
positionid=3,
|
|
subevent=subevent,
|
|
)
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orders/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
|
assert len(resp.data['results']) == 1
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_list(token_client, organizer, event, order, item, taxrule, question):
|
|
res = dict(TEST_ORDER_RES)
|
|
with scopes_disabled():
|
|
res["positions"][0]["id"] = order.positions.first().pk
|
|
res["fees"][0]["id"] = order.fees.first().pk
|
|
res["positions"][0]["item"] = item.pk
|
|
res["positions"][0]["answers"][0]["question"] = question.pk
|
|
res["last_modified"] = order.last_modified.isoformat().replace('+00:00', 'Z')
|
|
res["fees"][0]["tax_rule"] = taxrule.pk
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/'.format(organizer.slug, event.slug))
|
|
assert resp.status_code == 200
|
|
assert [res] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?code=FOO'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?code=BAR'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?testmode=false'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?testmode=true'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?status=n'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?status=p'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orders/?email=dummy@dummy.test'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orders/?email=foo@example.org'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=banktransfer'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=manual'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=web'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=bar'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=en'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=de'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?modified_since={}'.format(
|
|
organizer.slug, event.slug,
|
|
(order.last_modified - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?modified_since={}'.format(
|
|
organizer.slug, event.slug, order.last_modified.isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?modified_since={}'.format(
|
|
organizer.slug, event.slug,
|
|
(order.last_modified + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
|
organizer.slug, event.slug,
|
|
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
|
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
|
|
organizer.slug, event.slug,
|
|
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
|
organizer.slug, event.slug,
|
|
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
|
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [] == resp.data['results']
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
|
|
organizer.slug, event.slug,
|
|
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
|
|
))
|
|
assert [res] == resp.data['results']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_positions=false'.format(organizer.slug, event.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results'][0]['positions']) == 1
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_positions=true'.format(organizer.slug, event.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results'][0]['positions']) == 2
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_fees=false'.format(organizer.slug, event.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results'][0]['fees']) == 1
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_fees=true'.format(organizer.slug, event.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results'][0]['fees']) == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_detail(token_client, organizer, event, order, item, taxrule, question):
|
|
res = dict(TEST_ORDER_RES)
|
|
with scopes_disabled():
|
|
res["positions"][0]["id"] = order.positions.first().pk
|
|
res["fees"][0]["id"] = order.fees.first().pk
|
|
res["positions"][0]["item"] = item.pk
|
|
res["fees"][0]["tax_rule"] = taxrule.pk
|
|
res["positions"][0]["answers"][0]["question"] = question.pk
|
|
res["last_modified"] = order.last_modified.isoformat().replace('+00:00', 'Z')
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert resp.status_code == 200
|
|
assert json.loads(json.dumps(res)) == json.loads(json.dumps(resp.data))
|
|
|
|
order.status = 'p'
|
|
order.save()
|
|
event.settings.ticketoutput_pdf__enabled = True
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert len(resp.data['downloads']) == 1
|
|
assert len(resp.data['positions'][0]['downloads']) == 1
|
|
|
|
order.status = 'n'
|
|
order.save()
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert len(resp.data['downloads']) == 0
|
|
assert len(resp.data['positions'][0]['downloads']) == 0
|
|
|
|
event.settings.ticket_download_pending = True
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert len(resp.data['downloads']) == 1
|
|
assert len(resp.data['positions'][0]['downloads']) == 1
|
|
|
|
assert len(resp.data['positions']) == 1
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?include_canceled_positions=true'.format(organizer.slug, event.slug, order.code))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['positions']) == 2
|
|
|
|
assert len(resp.data['fees']) == 1
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?include_canceled_fees=true'.format(organizer.slug, event.slug, order.code))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['fees']) == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_organizer_level(token_client, organizer, team, event, event2, order, order2):
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/'.format(organizer.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results']) == 2
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/?subevent_after=2020-01-01T00:00:00Z'.format(organizer.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results']) == 0
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/FOO/'.format(organizer.slug))
|
|
assert resp.status_code == 200
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/BAR/'.format(organizer.slug))
|
|
assert resp.status_code == 200
|
|
|
|
with scopes_disabled():
|
|
team.all_events = False
|
|
team.save()
|
|
team.limit_events.set([event2])
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/'.format(organizer.slug))
|
|
assert resp.status_code == 200
|
|
assert len(resp.data['results']) == 1
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/FOO/'.format(organizer.slug))
|
|
assert resp.status_code == 404
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/orders/BAR/'.format(organizer.slug))
|
|
assert resp.status_code == 200
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_include_exclude_fields(token_client, organizer, event, order, item, taxrule, question):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?exclude=positions.secret'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert 'email' in resp.data
|
|
assert 'url' in resp.data
|
|
assert 'positions' in resp.data
|
|
assert 'subevent' in resp.data['positions'][0]
|
|
assert 'secret' not in resp.data['positions'][0]
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?exclude=positions'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert 'email' in resp.data
|
|
assert 'url' in resp.data
|
|
assert 'positions' not in resp.data
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?exclude=email&exclude=url'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert 'email' not in resp.data
|
|
assert 'url' not in resp.data
|
|
assert 'positions' in resp.data
|
|
assert 'secret' in resp.data['positions'][0]
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?include=email'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert 'email' in resp.data
|
|
assert 'url' not in resp.data
|
|
assert 'positions' not in resp.data
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/?include=email&include=positions&include=invoice_address.name&exclude=positions.secret'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert 'email' in resp.data
|
|
assert 'url' not in resp.data
|
|
assert 'positions' in resp.data
|
|
assert 'subevent' in resp.data['positions'][0]
|
|
assert 'secret' not in resp.data['positions'][0]
|
|
assert 'city' not in resp.data['invoice_address']
|
|
assert 'name' in resp.data['invoice_address']
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?include=email&include=positions.subevent'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert 'email' in resp.data
|
|
assert 'url' not in resp.data
|
|
assert 'positions' in resp.data
|
|
assert 'subevent' in resp.data['positions'][0]
|
|
assert 'secret' not in resp.data['positions'][0]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_list(token_client, organizer, event, order):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/payments/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert resp.status_code == 200
|
|
assert TEST_PAYMENTS_RES == resp.data['results']
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_detail(token_client, organizer, event, order):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/payments/1/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert resp.status_code == 200
|
|
assert TEST_PAYMENTS_RES[0] == resp.data
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_create_confirmed(token_client, organizer, event, order):
|
|
djmail.outbox = []
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'provider': 'banktransfer',
|
|
'state': 'confirmed',
|
|
'amount': order.total,
|
|
'send_email': False,
|
|
'info': {
|
|
'foo': 'bar'
|
|
}
|
|
})
|
|
with scopes_disabled():
|
|
p = order.payments.last()
|
|
assert resp.status_code == 201
|
|
assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED
|
|
assert p.info_data == {'foo': 'bar'}
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PAID
|
|
assert len(djmail.outbox) == 0
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_create_pending(token_client, organizer, event, order):
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'provider': 'banktransfer',
|
|
'state': 'pending',
|
|
'amount': order.total,
|
|
'info': {
|
|
'foo': 'bar'
|
|
}
|
|
})
|
|
with scopes_disabled():
|
|
p = order.payments.last()
|
|
assert resp.status_code == 201
|
|
assert p.state == OrderPayment.PAYMENT_STATE_PENDING
|
|
assert p.info_data == {'foo': 'bar'}
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_confirm(token_client, organizer, event, order):
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/confirm/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={'force': True})
|
|
with scopes_disabled():
|
|
p = order.payments.get(local_id=2)
|
|
assert resp.status_code == 200
|
|
assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED
|
|
assert len(djmail.outbox) == 1
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/confirm/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={'force': True})
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_confirm_no_email(token_client, organizer, event, order):
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/confirm/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={'force': True, 'send_email': False})
|
|
with scopes_disabled():
|
|
p = order.payments.get(local_id=2)
|
|
assert resp.status_code == 200
|
|
assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED
|
|
assert len(djmail.outbox) == 0
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_cancel(token_client, organizer, event, order):
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/cancel/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
with scopes_disabled():
|
|
p = order.payments.get(local_id=2)
|
|
assert resp.status_code == 200
|
|
assert p.state == OrderPayment.PAYMENT_STATE_CANCELED
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/cancel/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_refund_fail(token_client, organizer, event, order, monkeypatch):
|
|
with scopes_disabled():
|
|
order.payments.last().confirm()
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/refund/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'amount': '25.00',
|
|
'mark_canceled': False
|
|
})
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'amount': ['Invalid refund amount, only 23.00 are available to refund.']}
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/refund/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'amount': '20.00',
|
|
'mark_canceled': False
|
|
})
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'amount': ['Partial refund not available for this payment method.']}
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/refund/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'mark_canceled': False
|
|
})
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'amount': ['Full refund not available for this payment method.']}
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/refund/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'amount': '23.00',
|
|
'mark_canceled': False
|
|
})
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'amount': ['Full refund not available for this payment method.']}
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/1/refund/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'amount': '23.00',
|
|
'mark_canceled': False
|
|
})
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'detail': 'Invalid state of payment.'}
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_refund_success(token_client, organizer, event, order, monkeypatch):
|
|
|
|
def refund_create(*args, **kwargs):
|
|
r = MockedCharge()
|
|
r.id = 'foo'
|
|
r.status = 'succeeded'
|
|
return r
|
|
|
|
def charge_retr(*args, **kwargs):
|
|
c = MockedCharge()
|
|
c.refunds.create = refund_create
|
|
return c
|
|
|
|
with scopes_disabled():
|
|
p1 = order.payments.create(
|
|
provider='stripe',
|
|
state='confirmed',
|
|
amount=Decimal('23.00'),
|
|
payment_date=order.datetime,
|
|
info=json.dumps({
|
|
'id': 'ch_123345345'
|
|
})
|
|
)
|
|
monkeypatch.setattr("stripe.ApplePayDomain.create", apple_domain_create)
|
|
monkeypatch.setattr("stripe.Charge.retrieve", charge_retr)
|
|
monkeypatch.setattr("stripe.Refund.create", refund_create)
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/{}/refund/'.format(
|
|
organizer.slug, event.slug, order.code, p1.local_id
|
|
), format='json', data={
|
|
'amount': '23.00',
|
|
'mark_canceled': False,
|
|
})
|
|
assert resp.status_code == 200
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=resp.data['local_id'])
|
|
assert r.provider == "stripe"
|
|
assert r.state == OrderRefund.REFUND_STATE_DONE
|
|
assert r.source == OrderRefund.REFUND_SOURCE_ADMIN
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_payment_refund_unavailable(token_client, organizer, event, order, monkeypatch):
|
|
def charge_retr(*args, **kwargs):
|
|
def refund_create(amount):
|
|
raise error.APIConnectionError(message='Foo')
|
|
|
|
c = MockedCharge()
|
|
c.refunds.create = refund_create
|
|
return c
|
|
|
|
with scopes_disabled():
|
|
p1 = order.payments.create(
|
|
provider='stripe',
|
|
state='confirmed',
|
|
amount=Decimal('23.00'),
|
|
payment_date=order.datetime,
|
|
info=json.dumps({
|
|
'id': 'ch_123345345'
|
|
})
|
|
)
|
|
monkeypatch.setattr("stripe.Charge.retrieve", charge_retr)
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/{}/refund/'.format(
|
|
organizer.slug, event.slug, order.code, p1.local_id
|
|
), format='json', data={
|
|
'amount': '23.00',
|
|
'mark_canceled': False,
|
|
})
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'detail': 'External error: We had trouble communicating with Stripe. Please try again and contact support if the problem persists.'}
|
|
with scopes_disabled():
|
|
r = order.refunds.last()
|
|
assert r.provider == "stripe"
|
|
assert r.state == OrderRefund.REFUND_STATE_FAILED
|
|
assert r.source == OrderRefund.REFUND_SOURCE_ADMIN
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_list(token_client, organizer, event, order):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert resp.status_code == 200
|
|
assert TEST_REFUNDS_RES == resp.data['results']
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_detail(token_client, organizer, event, order):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/'.format(organizer.slug, event.slug,
|
|
order.code))
|
|
assert resp.status_code == 200
|
|
assert TEST_REFUNDS_RES[0] == resp.data
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_done(token_client, organizer, event, order):
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=1)
|
|
r.state = 'transit'
|
|
r.save()
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/done/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=1)
|
|
assert resp.status_code == 200
|
|
assert r.state == OrderRefund.REFUND_STATE_DONE
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/done/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_process_mark_refunded(token_client, organizer, event, order):
|
|
with scopes_disabled():
|
|
p = order.payments.get(local_id=1)
|
|
p.create_external_refund()
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/2/process/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={'mark_canceled': True})
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=1)
|
|
assert resp.status_code == 200
|
|
assert r.state == OrderRefund.REFUND_STATE_DONE
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_CANCELED
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/2/process/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={'mark_canceled': True})
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_process_mark_pending(token_client, organizer, event, order):
|
|
with scopes_disabled():
|
|
p = order.payments.get(local_id=1)
|
|
p.create_external_refund()
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/2/process/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={'mark_canceled': False})
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=1)
|
|
assert resp.status_code == 200
|
|
assert r.state == OrderRefund.REFUND_STATE_DONE
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_cancel(token_client, organizer, event, order):
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=1)
|
|
r.state = 'transit'
|
|
r.save()
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/cancel/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=1)
|
|
assert resp.status_code == 200
|
|
assert r.state == OrderRefund.REFUND_STATE_CANCELED
|
|
|
|
resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/cancel/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_orderposition_list(token_client, organizer, event, order, item, subevent, subevent2, question):
|
|
i2 = copy.copy(item)
|
|
i2.pk = None
|
|
i2.save()
|
|
with scopes_disabled():
|
|
var = item.variations.create(value="Children")
|
|
var2 = item.variations.create(value="Children")
|
|
res = copy.copy(TEST_ORDERPOSITION_RES)
|
|
op = order.positions.first()
|
|
op.variation = var
|
|
op.save()
|
|
res["id"] = op.pk
|
|
res["item"] = item.pk
|
|
res["variation"] = var.pk
|
|
res["answers"][0]["question"] = question.pk
|
|
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug))
|
|
assert resp.status_code == 200
|
|
assert [res] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=n'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=p'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, item.pk))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?item__in={},{}'.format(
|
|
organizer.slug, event.slug, item.pk, i2.pk
|
|
))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, i2.pk))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var.pk))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var2.pk))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Peter'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=peter'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Mark'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w'.format(
|
|
organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=abc123'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=ABCDEFGHKL'.format(
|
|
organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=FOO'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?search=FO'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?search=z3fsn8j'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?search=Peter'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?search=5f4h6w'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?order=FOO'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?order=BAR'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=false'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
|
|
assert [] == resp.data['results']
|
|
|
|
with scopes_disabled():
|
|
cl = event.checkin_lists.create(name="Default")
|
|
c = op.checkins.create(datetime=datetime.datetime(2017, 12, 26, 10, 0, 0, tzinfo=datetime.timezone.utc), list=cl)
|
|
op.checkins.create(datetime=datetime.datetime(2017, 12, 26, 10, 0, 0, tzinfo=datetime.timezone.utc), list=cl, successful=False)
|
|
res['checkins'] = [{ # successful only
|
|
'id': c.pk,
|
|
'datetime': '2017-12-26T10:00:00Z',
|
|
'list': cl.pk,
|
|
'auto_checked_in': False,
|
|
'device': None,
|
|
'gate': None,
|
|
'type': 'entry'
|
|
}]
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
|
|
assert [res] == resp.data['results']
|
|
|
|
op.subevent = subevent
|
|
op.save()
|
|
res['subevent'] = subevent.pk
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent__in={},{}'.format(organizer.slug, event.slug,
|
|
subevent.pk, subevent2.pk))
|
|
assert [res] == resp.data['results']
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug,
|
|
subevent.pk + 1))
|
|
assert [] == resp.data['results']
|
|
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=false'.format(organizer.slug, event.slug))
|
|
assert len(resp.data['results']) == 1
|
|
resp = token_client.get(
|
|
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=true'.format(organizer.slug, event.slug))
|
|
assert len(resp.data['results']) == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_orderposition_detail(token_client, organizer, event, order, item, question):
|
|
res = dict(TEST_ORDERPOSITION_RES)
|
|
with scopes_disabled():
|
|
op = order.positions.first()
|
|
res["id"] = op.pk
|
|
res["item"] = item.pk
|
|
res["answers"][0]["question"] = question.pk
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug,
|
|
op.pk))
|
|
assert resp.status_code == 200
|
|
assert res == resp.data
|
|
|
|
order.status = 'p'
|
|
order.save()
|
|
event.settings.ticketoutput_pdf__enabled = True
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug,
|
|
op.pk))
|
|
assert len(resp.data['downloads']) == 1
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_orderposition_detail_canceled(token_client, organizer, event, order, item, question):
|
|
with scopes_disabled():
|
|
op = order.all_positions.filter(canceled=True).first()
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug,
|
|
op.pk))
|
|
assert resp.status_code == 404
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/?include_canceled_positions=true'.format(
|
|
organizer.slug, event.slug, op.pk))
|
|
assert resp.status_code == 200
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_orderposition_delete(token_client, organizer, event, order, item, question):
|
|
with scopes_disabled():
|
|
op = order.positions.first()
|
|
resp = token_client.delete('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(
|
|
organizer.slug, event.slug, op.pk
|
|
))
|
|
assert resp.status_code == 400
|
|
assert resp.data == ['This operation would leave the order empty. Please cancel the order itself instead.']
|
|
|
|
with scopes_disabled():
|
|
op2 = OrderPosition.objects.create(
|
|
order=order,
|
|
item=item,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={"full_name": "Peter", "_scheme": "full"},
|
|
secret="foobar",
|
|
pseudonymization_id="BAZ",
|
|
)
|
|
order.refresh_from_db()
|
|
order.total = Decimal('46')
|
|
order.save()
|
|
assert order.positions.count() == 2
|
|
|
|
resp = token_client.delete('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(
|
|
organizer.slug, event.slug, op2.pk
|
|
))
|
|
assert resp.status_code == 204
|
|
with scopes_disabled():
|
|
assert order.positions.count() == 1
|
|
assert order.all_positions.count() == 3
|
|
order.refresh_from_db()
|
|
assert order.total == Decimal('23.25')
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_pending(token_client, organizer, event, order):
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_paid/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert len(djmail.outbox) == 1
|
|
assert resp.data['status'] == Order.STATUS_PAID
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_canceled(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_paid/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_CANCELED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_expired_quota_free(token_client, organizer, event, order, quota):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
with scopes_disabled():
|
|
order.create_transactions()
|
|
assert order.transactions.count() == 0
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_paid/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
),
|
|
format='json',
|
|
data={
|
|
'send_email': False
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
order.refresh_from_db()
|
|
assert len(djmail.outbox) == 0
|
|
assert order.status == Order.STATUS_PAID
|
|
with scopes_disabled():
|
|
assert order.transactions.count() == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_expired_quota_fill(token_client, organizer, event, order, quota):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
quota.size = 0
|
|
quota.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_paid/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_EXPIRED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_locked(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_paid/?_debug_flag=fail-locking'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 409
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_EXPIRED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_reactivate(token_client, organizer, event, order, quota):
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
with scopes_disabled():
|
|
order.create_transactions()
|
|
assert order.transactions.count() == 0
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/reactivate/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_PENDING
|
|
with scopes_disabled():
|
|
assert order.transactions.count() == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_reactivate_invalid(token_client, organizer, event, order):
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/reactivate/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_canceled_pending(token_client, organizer, event, order):
|
|
with scopes_disabled():
|
|
order.create_transactions()
|
|
assert order.transactions.count() == 2
|
|
djmail.outbox = []
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_CANCELED
|
|
assert len(djmail.outbox) == 1
|
|
with scopes_disabled():
|
|
assert order.transactions.count() == 4
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_canceled_pending_fee_not_allowed(token_client, organizer, event, order):
|
|
djmail.outbox = []
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), data={
|
|
'cancellation_fee': '700.00'
|
|
}
|
|
)
|
|
assert resp.status_code == 400
|
|
assert resp.data == {'detail': 'The cancellation fee cannot be higher than the total amount of this order.'}
|
|
assert len(djmail.outbox) == 0
|
|
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), data={
|
|
'cancellation_fee': '7.00'
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_PENDING
|
|
assert len(djmail.outbox) == 1
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_canceled_pending_no_email(token_client, organizer, event, order):
|
|
djmail.outbox = []
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'send_email': False
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_CANCELED
|
|
assert len(djmail.outbox) == 0
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_canceled_expired(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_CANCELED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_canceled_keep_fee(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PAID
|
|
order.save()
|
|
with scopes_disabled():
|
|
order.create_transactions()
|
|
assert order.transactions.count() == 2
|
|
with scopes_disabled():
|
|
order.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=order.total)
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), data={
|
|
'cancellation_fee': '6.00'
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_PAID
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PAID
|
|
assert order.total == Decimal('6.00')
|
|
with scopes_disabled():
|
|
assert order.transactions.count() == 4
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_refunded(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PAID
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_refunded/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_CANCELED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_canceled_refunded(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_refunded/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_CANCELED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_unpaid(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PAID
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_pending/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_PENDING
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_canceled_unpaid(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_pending/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_CANCELED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_pending_expired(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PENDING
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_expired/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_EXPIRED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_mark_paid_expired(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PAID
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/mark_expired/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PAID
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_extend_paid(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PAID
|
|
order.save()
|
|
newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d")
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'expires': newdate
|
|
}
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PAID
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_extend_pending(token_client, organizer, event, order):
|
|
order.status = Order.STATUS_PENDING
|
|
order.save()
|
|
newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d")
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'expires': newdate
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
assert order.expires.astimezone(event.timezone).strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_extend_expired_quota_empty(token_client, organizer, event, order, quota):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
quota.size = 0
|
|
quota.save()
|
|
newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d")
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'expires': newdate
|
|
}
|
|
)
|
|
assert resp.status_code == 400
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_EXPIRED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_extend_expired_quota_ignore(token_client, organizer, event, order, quota):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
quota.size = 0
|
|
quota.save()
|
|
newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d")
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'expires': newdate,
|
|
'force': True
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
assert order.expires.astimezone(event.timezone).strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_extend_expired_quota_waiting_list(token_client, organizer, event, order, item, quota):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
quota.size = 1
|
|
quota.save()
|
|
with scopes_disabled():
|
|
event.waitinglistentries.create(item=item, email='foo@bar.com')
|
|
newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d")
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'expires': newdate,
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
assert order.expires.astimezone(event.timezone).strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_extend_expired_quota_left(token_client, organizer, event, order, quota):
|
|
order.status = Order.STATUS_EXPIRED
|
|
order.save()
|
|
quota.size = 2
|
|
quota.save()
|
|
with scopes_disabled():
|
|
order.create_transactions()
|
|
assert order.transactions.count() == 0
|
|
newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d")
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data={
|
|
'expires': newdate,
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
assert order.expires.astimezone(event.timezone).strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59"
|
|
with scopes_disabled():
|
|
assert order.transactions.count() == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_pending_approve(token_client, organizer, event, order):
|
|
order.require_approval = True
|
|
order.save()
|
|
with scopes_disabled():
|
|
order.create_transactions()
|
|
assert order.transactions.count() == 0
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/approve/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_PENDING
|
|
assert not resp.data['require_approval']
|
|
with scopes_disabled():
|
|
assert order.transactions.count() == 2
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_invalid_state_approve(token_client, organizer, event, order):
|
|
order.require_approval = True
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/approve/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
order.require_approval = False
|
|
order.status = Order.STATUS_PENDING
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/approve/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_pending_deny(token_client, organizer, event, order):
|
|
order.require_approval = True
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/deny/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.data['status'] == Order.STATUS_CANCELED
|
|
assert resp.data['require_approval']
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_invalid_state_deny(token_client, organizer, event, order):
|
|
order.require_approval = True
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/deny/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
order.require_approval = False
|
|
order.status = Order.STATUS_PENDING
|
|
order.save()
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/deny/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
REFUND_CREATE_PAYLOAD = {
|
|
"state": "created",
|
|
"provider": "manual",
|
|
"amount": "23.00",
|
|
"source": "admin",
|
|
"payment": 2,
|
|
"info": {
|
|
"foo": "bar",
|
|
}
|
|
}
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_create(token_client, organizer, event, order):
|
|
res = copy.deepcopy(REFUND_CREATE_PAYLOAD)
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data=res
|
|
)
|
|
assert resp.status_code == 201
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=resp.data['local_id'])
|
|
assert r.provider == "manual"
|
|
assert r.amount == Decimal("23.00")
|
|
assert r.state == "created"
|
|
assert r.source == "admin"
|
|
assert r.info_data == {"foo": "bar"}
|
|
assert r.payment.local_id == 2
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_PENDING
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_create_mark_refunded(token_client, organizer, event, order):
|
|
res = copy.deepcopy(REFUND_CREATE_PAYLOAD)
|
|
res['mark_canceled'] = True
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data=res
|
|
)
|
|
assert resp.status_code == 201
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=resp.data['local_id'])
|
|
assert r.provider == "manual"
|
|
assert r.amount == Decimal("23.00")
|
|
assert r.state == "created"
|
|
assert r.source == "admin"
|
|
assert r.info_data == {"foo": "bar"}
|
|
assert r.payment.local_id == 2
|
|
order.refresh_from_db()
|
|
assert order.status == Order.STATUS_CANCELED
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_create_webhook_sent(token_client, organizer, event, order):
|
|
res = copy.deepcopy(REFUND_CREATE_PAYLOAD)
|
|
res['state'] = "done"
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data=res
|
|
)
|
|
assert resp.status_code == 201
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=resp.data['local_id'])
|
|
assert r.provider == "manual"
|
|
assert r.amount == Decimal("23.00")
|
|
assert r.state == "done"
|
|
assert r.execution_date
|
|
with scopes_disabled():
|
|
assert order.all_logentries().get(action_type="pretix.event.order.refund.done")
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_optional_fields(token_client, organizer, event, order):
|
|
res = copy.deepcopy(REFUND_CREATE_PAYLOAD)
|
|
del res['info']
|
|
del res['payment']
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data=res
|
|
)
|
|
assert resp.status_code == 201
|
|
with scopes_disabled():
|
|
r = order.refunds.get(local_id=resp.data['local_id'])
|
|
assert r.provider == "manual"
|
|
assert r.amount == Decimal("23.00")
|
|
assert r.state == "created"
|
|
assert r.source == "admin"
|
|
|
|
del res['state']
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data=res
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_refund_create_invalid_payment(token_client, organizer, event, order):
|
|
res = copy.deepcopy(REFUND_CREATE_PAYLOAD)
|
|
res['payment'] = 7
|
|
resp = token_client.post(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/refunds/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
), format='json', data=res
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_delete(token_client, organizer, event, order):
|
|
resp = token_client.delete(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 403
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_delete_test_mode(token_client, organizer, event, order):
|
|
order.testmode = True
|
|
order.save()
|
|
resp = token_client.delete(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 204
|
|
with scopes_disabled():
|
|
assert not Order.objects.filter(code=order.code).exists()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_delete_test_mode_voucher(token_client, organizer, event, order, item):
|
|
order.testmode = True
|
|
order.save()
|
|
with scopes_disabled():
|
|
q = event.quotas.create(name="Quota")
|
|
q.items.add(item)
|
|
voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=1)
|
|
op = order.positions.first()
|
|
op.voucher = voucher
|
|
op.save()
|
|
|
|
assert voucher.redeemed == 1
|
|
|
|
resp = token_client.delete(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 204
|
|
with scopes_disabled():
|
|
assert not Order.objects.filter(code=order.code).exists()
|
|
voucher.refresh_from_db()
|
|
assert voucher.redeemed == 0
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_delete_test_mode_voucher_cancelled_position(token_client, organizer, event, order, item):
|
|
order.testmode = True
|
|
order.save()
|
|
with scopes_disabled():
|
|
q = event.quotas.create(name="Quota")
|
|
q.items.add(item)
|
|
voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42)
|
|
op = order.all_positions.last()
|
|
op.voucher = voucher
|
|
op.save()
|
|
|
|
resp = token_client.delete(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 204
|
|
with scopes_disabled():
|
|
assert not Order.objects.filter(code=order.code).exists()
|
|
voucher.refresh_from_db()
|
|
assert voucher.redeemed == 42
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_order_delete_test_mode_voucher_cancelled_order(token_client, organizer, event, order, item):
|
|
with scopes_disabled():
|
|
order.testmode = True
|
|
order.status = Order.STATUS_CANCELED
|
|
order.save()
|
|
q = event.quotas.create(name="Quota")
|
|
q.items.add(item)
|
|
voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42)
|
|
op = order.positions.first()
|
|
op.voucher = voucher
|
|
op.save()
|
|
|
|
resp = token_client.delete(
|
|
'/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
)
|
|
)
|
|
assert resp.status_code == 204
|
|
with scopes_disabled():
|
|
assert not Order.objects.filter(code=order.code).exists()
|
|
voucher.refresh_from_db()
|
|
assert voucher.redeemed == 42
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_revoked_secret_list(token_client, organizer, event):
|
|
r = event.revoked_secrets.create(secret="abcd")
|
|
res = {
|
|
"id": r.id,
|
|
"secret": "abcd",
|
|
"created": r.created.isoformat().replace("+00:00", "Z")
|
|
}
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/revokedsecrets/'.format(
|
|
organizer.slug, event.slug,
|
|
))
|
|
assert resp.status_code == 200
|
|
assert [res] == resp.data['results']
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_blocked_secret_list(token_client, organizer, event):
|
|
r = event.blocked_secrets.create(secret="abcd", blocked=True)
|
|
res = {
|
|
"id": r.id,
|
|
"secret": "abcd",
|
|
"blocked": True,
|
|
"updated": r.updated.isoformat().replace("+00:00", "Z")
|
|
}
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/blockedsecrets/'.format(
|
|
organizer.slug, event.slug,
|
|
))
|
|
assert resp.status_code == 200
|
|
assert [res] == resp.data['results']
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_queries):
|
|
# order detail
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/?pdf_data=true'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert resp.data['positions'][0].get('pdf_data')
|
|
assert resp.data['positions'][0]['pdf_data']['positionid'] == '1'
|
|
assert resp.data['positions'][0]['pdf_data']['order'] == order.code
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
|
organizer.slug, event.slug, order.code
|
|
))
|
|
assert resp.status_code == 200
|
|
assert not resp.data['positions'][0].get('pdf_data')
|
|
|
|
# order list
|
|
with django_assert_max_num_queries(30):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?pdf_data=true'.format(
|
|
organizer.slug, event.slug
|
|
))
|
|
assert resp.status_code == 200
|
|
assert resp.data['results'][0]['positions'][0].get('pdf_data')
|
|
assert resp.data['results'][0]['positions'][0]['pdf_data']['positionid'] == '1'
|
|
assert resp.data['results'][0]['positions'][0]['pdf_data']['order'] == order.code
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/'.format(
|
|
organizer.slug, event.slug
|
|
))
|
|
assert resp.status_code == 200
|
|
assert not resp.data['results'][0]['positions'][0].get('pdf_data')
|
|
|
|
# position list
|
|
with django_assert_max_num_queries(33):
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/?pdf_data=true'.format(
|
|
organizer.slug, event.slug
|
|
))
|
|
assert resp.status_code == 200
|
|
assert resp.data['results'][0].get('pdf_data')
|
|
assert resp.data['results'][0]['pdf_data']['positionid'] == '1'
|
|
assert resp.data['results'][0]['pdf_data']['order'] == order.code
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/'.format(
|
|
organizer.slug, event.slug
|
|
))
|
|
assert resp.status_code == 200
|
|
assert not resp.data['results'][0].get('pdf_data')
|
|
|
|
posid = resp.data['results'][0]['id']
|
|
|
|
# position detail
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/?pdf_data=true'.format(
|
|
organizer.slug, event.slug, posid
|
|
))
|
|
assert resp.status_code == 200
|
|
assert resp.data.get('pdf_data')
|
|
assert resp.data['pdf_data']['positionid'] == '1'
|
|
assert resp.data['pdf_data']['order'] == order.code
|
|
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(
|
|
organizer.slug, event.slug, posid
|
|
))
|
|
assert resp.status_code == 200
|
|
assert not resp.data.get('pdf_data')
|