Template
Add shop, POS sync, event ticketing, and shipping catalog apps.
Clients can run in-house retail without Shopify while keeping the same Docker/Django/Postgres stack and data-ownership promise. Closes #5.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core import mail
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from events.models import Event, Ticket, TicketOrder
|
||||
from events.services import EventsError, create_ticket_order, mark_paid
|
||||
|
||||
|
||||
def _event(**kwargs):
|
||||
defaults = dict(
|
||||
title="Friday Night Prerelease",
|
||||
starts_at=timezone.now() + timezone.timedelta(days=7),
|
||||
venue="Main shop",
|
||||
capacity=8,
|
||||
price=Decimal("25.00"),
|
||||
is_published=True,
|
||||
)
|
||||
defaults.update(kwargs)
|
||||
return Event.objects.create(**defaults)
|
||||
|
||||
|
||||
class EventPublicTests(TestCase):
|
||||
def test_list_hides_drafts_and_past(self):
|
||||
_event(title="Live prerelease")
|
||||
_event(title="Draft night", is_published=False)
|
||||
_event(
|
||||
title="Last week",
|
||||
starts_at=timezone.now() - timezone.timedelta(days=2),
|
||||
)
|
||||
response = Client().get(reverse("events:list"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Live prerelease")
|
||||
self.assertNotContains(response, "Draft night")
|
||||
self.assertNotContains(response, "Last week")
|
||||
|
||||
def test_buy_form_renders(self):
|
||||
event = _event()
|
||||
response = Client().get(reverse("events:buy", kwargs={"slug": event.slug}))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Pay with Stripe")
|
||||
|
||||
|
||||
class EventCapacityTests(TestCase):
|
||||
def test_capacity_blocks_overbook(self):
|
||||
event = _event(capacity=2)
|
||||
create_ticket_order(event, email="a@example.com", quantity=2)
|
||||
with self.assertRaises(EventsError):
|
||||
create_ticket_order(event, email="b@example.com", quantity=1)
|
||||
|
||||
def test_mark_paid_issues_tickets_and_email(self):
|
||||
event = _event(capacity=4)
|
||||
order = create_ticket_order(
|
||||
event, email="fan@example.com", customer_name="Lee", quantity=2
|
||||
)
|
||||
mark_paid(order)
|
||||
order.refresh_from_db()
|
||||
self.assertEqual(order.status, TicketOrder.Status.PAID)
|
||||
self.assertEqual(Ticket.objects.filter(order=order).count(), 2)
|
||||
self.assertEqual(event.tickets_sold, 2)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertIn(event.title, mail.outbox[0].subject)
|
||||
|
||||
|
||||
class EventPortalTests(TestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user("host", password="test-pass-123")
|
||||
self.client = Client()
|
||||
self.client.login(username="host", password="test-pass-123")
|
||||
|
||||
def test_list_requires_login(self):
|
||||
self.assertEqual(Client().get(reverse("events_portal:event_list")).status_code, 302)
|
||||
|
||||
def test_create_published_event(self):
|
||||
starts = (timezone.now() + timezone.timedelta(days=3)).strftime("%Y-%m-%dT%H:%M")
|
||||
response = self.client.post(
|
||||
reverse("events_portal:event_new"),
|
||||
{
|
||||
"title": "Commander night",
|
||||
"starts_at": starts,
|
||||
"venue": "Back room",
|
||||
"capacity": "16",
|
||||
"price": "10.00",
|
||||
"is_published": "on",
|
||||
},
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
event = Event.objects.get()
|
||||
self.assertEqual(event.slug, "commander-night")
|
||||
self.assertTrue(event.is_published)
|
||||
self.assertEqual(event.capacity, 16)
|
||||
Reference in New Issue
Block a user