feat(events): harden registration checkout lifecycle

This commit is contained in:
2026-10-01 12:26:49 +03:30
parent 1daa755543
commit 962238c32c
29 changed files with 3048 additions and 207 deletions

View File

@@ -3,7 +3,7 @@ import io
import json
import tempfile
import uuid
from datetime import timedelta
from datetime import datetime, time as datetime_time, timedelta
from types import SimpleNamespace
from PIL import Image
from django.core.files.uploadedfile import SimpleUploadedFile
@@ -110,6 +110,115 @@ class TestEventsAPIIntegrationTests:
assert response.status_code == 200
assert any((item['id'] == event.id for item in response.json()))
def test_browse_events_returns_numbered_pages_and_global_price_ceiling(self):
self._create_event(title='Price ceiling 650k toman', price=6500000)
self._create_event(title='Price ceiling 4.3m toman', price=43000000)
for index in range(13):
self._create_event(title=f'Browse page event {index}', price=100000)
first_page = self.client.get('/api/events/browse/', {'page': 1})
second_page = self.client.get('/api/events/browse/', {'page': 2})
assert first_page.status_code == 200
assert first_page.json()['count'] == 17
assert first_page.json()['page'] == 1
assert first_page.json()['page_size'] == 12
assert first_page.json()['total_pages'] == 2
assert len(first_page.json()['results']) == 12
assert second_page.json()['page'] == 2
assert len(second_page.json()['results']) == 5
assert first_page.json()['price_ceiling'] == 5000000
assert 'address' in first_page.json()['results'][0]
def test_browse_events_upcoming_includes_future_events_that_cannot_register(self):
now = timezone.now()
open_event = self._create_event(
title='Browse open event',
start_time=now + timedelta(days=4),
end_time=now + timedelta(days=4, hours=2),
registration_start_date=now - timedelta(days=1),
registration_end_date=now + timedelta(days=2),
)
not_started = self._create_event(
title='Browse not started event',
start_time=now + timedelta(days=5),
end_time=now + timedelta(days=5, hours=2),
registration_start_date=now + timedelta(days=1),
)
closed = self._create_event(
title='Browse closed event',
start_time=now + timedelta(days=6),
end_time=now + timedelta(days=6, hours=2),
registration_end_date=now - timedelta(minutes=1),
)
full = self._create_event(
title='Browse full event',
start_time=now + timedelta(days=7),
end_time=now + timedelta(days=7, hours=2),
capacity=1,
)
self._create_registration(full, self.user, status=Registration.StatusChoices.CONFIRMED)
upcoming = self.client.get('/api/events/browse/', {'state': 'upcoming', 'search': 'Browse'}).json()
open_results = self.client.get('/api/events/browse/', {'state': 'open', 'search': 'Browse'}).json()
upcoming_ids = {item['id'] for item in upcoming['results']}
open_ids = {item['id'] for item in open_results['results']}
assert {not_started.id, closed.id, full.id}.issubset(upcoming_ids)
assert open_event.id not in upcoming_ids
assert open_ids == {open_event.id}
def test_browse_events_filters_start_dates_inclusive_and_combines_type_price_and_free(self):
selected_day = timezone.localdate()
local_timezone = timezone.get_current_timezone()
def at(day, hour, minute):
return timezone.make_aware(datetime.combine(day, datetime_time(hour, minute)), local_timezone)
start_day = self._create_event(
title='Date range probe free',
event_type=Event.TypeChoices.ONLINE,
price=0,
start_time=at(selected_day, 0, 0),
end_time=at(selected_day, 2, 0),
)
end_day = self._create_event(
title='Date range probe paid online',
event_type=Event.TypeChoices.ONLINE,
price=300000,
start_time=at(selected_day, 23, 59),
end_time=at(selected_day + timedelta(days=1), 1, 0),
)
self._create_event(
title='Date range probe paid onsite',
event_type=Event.TypeChoices.ON_SITE,
price=300000,
start_time=at(selected_day, 12, 0),
end_time=at(selected_day, 14, 0),
)
outside_day = self._create_event(
title='Date range probe outside',
event_type=Event.TypeChoices.ONLINE,
price=300000,
start_time=at(selected_day + timedelta(days=1), 0, 0),
end_time=at(selected_day + timedelta(days=1), 2, 0),
)
params = {
'search': 'Date range probe',
'date_from': selected_day.isoformat(),
'date_to': selected_day.isoformat(),
'event_type': Event.TypeChoices.ONLINE,
'price_min': 10000,
'price_max': 40000,
}
paid_results = self.client.get('/api/events/browse/', params).json()
free_results = self.client.get('/api/events/browse/', {**params, 'free_only': 'true'}).json()
assert {item['id'] for item in paid_results['results']} == {end_day.id}
assert {item['id'] for item in free_results['results']} == {start_day.id}
assert outside_day.id not in {item['id'] for item in paid_results['results']}
def test_list_events_handles_comma_status_parameter(self):
event = self._create_event(title='Comma Event', status=Event.StatusChoices.PUBLISHED)
results = list_events(None, status=f'{Event.StatusChoices.PUBLISHED},{Event.StatusChoices.DRAFT}', event_type=None, search=None, limit=10, offset=0)