Template
Add shopper accounts, reviews, tracking, and seed_demo (#9)
Closes #9. Shop-gated buyer accounts, purchase reviews, Stripe customer ids, shipment tracking, slim public contact form, and a template-neutral seed_demo command.
This commit is contained in:
+103
-2
@@ -1,5 +1,6 @@
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core import mail
|
||||
@@ -13,6 +14,7 @@ from shop.services import (
|
||||
add_to_cart,
|
||||
adjust_stock,
|
||||
available_qty,
|
||||
create_checkout_session,
|
||||
create_order_from_cart,
|
||||
mark_paid,
|
||||
next_order_number,
|
||||
@@ -116,7 +118,9 @@ class ShopInventoryTests(TestCase):
|
||||
class ShopPortalTests(TestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user("merchant", password="test-pass-123")
|
||||
self.user = User.objects.create_user(
|
||||
"merchant", password="test-pass-123", is_staff=True
|
||||
)
|
||||
self.client = Client()
|
||||
self.client.login(username="merchant", password="test-pass-123")
|
||||
|
||||
@@ -175,7 +179,9 @@ def _sold_order(product, *, qty=1, paid_at=None, status=None, number=None):
|
||||
class ShopSalesDashboardTests(TestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user("merchant", password="test-pass-123")
|
||||
self.user = User.objects.create_user(
|
||||
"merchant", password="test-pass-123", is_staff=True
|
||||
)
|
||||
self.client = Client()
|
||||
self.client.login(username="merchant", password="test-pass-123")
|
||||
self.dragon = _product(name="Dragon", sku="DRAGON", price=Decimal("18.00"))
|
||||
@@ -252,3 +258,98 @@ class ShopSalesDashboardTests(TestCase):
|
||||
self.assertContains(products, "Sales")
|
||||
sales = self.client.get(reverse("shop_portal:sales"))
|
||||
self.assertContains(sales, 'class="active"')
|
||||
|
||||
|
||||
class ShopCustomerAccountTests(TestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.user = User.objects.create_user(
|
||||
username="buyer@example.com",
|
||||
email="buyer@example.com",
|
||||
password="s3cure-pass-123",
|
||||
)
|
||||
self.product = _product()
|
||||
self.client = Client()
|
||||
self.client.login(username="buyer@example.com", password="s3cure-pass-123")
|
||||
|
||||
def test_checkout_attaches_user_and_uses_stripe_customer(self):
|
||||
session = self.client.session
|
||||
add_to_cart(session, self.product, 1)
|
||||
session.save()
|
||||
captured = {}
|
||||
|
||||
class FakeCustomer:
|
||||
id = "cus_abc"
|
||||
|
||||
class FakeCheckout:
|
||||
id = "cs_abc"
|
||||
url = "https://stripe.test/pay"
|
||||
|
||||
class FakeStripe:
|
||||
class Customer:
|
||||
@staticmethod
|
||||
def create(**kwargs):
|
||||
captured["customer"] = kwargs
|
||||
return FakeCustomer()
|
||||
|
||||
class checkout:
|
||||
class Session:
|
||||
@staticmethod
|
||||
def create(**kwargs):
|
||||
captured["session"] = kwargs
|
||||
return FakeCheckout()
|
||||
|
||||
with patch("shop.services._stripe", return_value=FakeStripe):
|
||||
order = create_order_from_cart(
|
||||
self.client.session,
|
||||
email="buyer@example.com",
|
||||
user=self.user,
|
||||
)
|
||||
url = create_checkout_session(
|
||||
order,
|
||||
success_url="https://example.test/ok",
|
||||
cancel_url="https://example.test/no",
|
||||
)
|
||||
self.assertEqual(url, "https://stripe.test/pay")
|
||||
self.assertEqual(order.user, self.user)
|
||||
self.assertEqual(captured["session"]["customer"], "cus_abc")
|
||||
self.assertNotIn("customer_email", captured["session"])
|
||||
self.assertEqual(
|
||||
captured["session"]["payment_intent_data"]["setup_future_usage"],
|
||||
"on_session",
|
||||
)
|
||||
self.user.customer_profile.refresh_from_db()
|
||||
self.assertEqual(self.user.customer_profile.stripe_customer_id, "cus_abc")
|
||||
|
||||
def test_review_requires_purchase(self):
|
||||
blocked = self.client.post(
|
||||
reverse("shop:review", kwargs={"slug": self.product.slug}),
|
||||
{"rating": "5", "title": "Nope", "body": "Did not buy"},
|
||||
)
|
||||
self.assertEqual(blocked.status_code, 302)
|
||||
self.assertEqual(self.product.reviews.count(), 0)
|
||||
|
||||
order = _sold_order(self.product)
|
||||
order.user = self.user
|
||||
order.email = self.user.email
|
||||
order.save(update_fields=["user", "email"])
|
||||
ok = self.client.post(
|
||||
reverse("shop:review", kwargs={"slug": self.product.slug}),
|
||||
{"rating": "5", "title": "Great", "body": "Loved it"},
|
||||
)
|
||||
self.assertEqual(ok.status_code, 302)
|
||||
review = self.product.reviews.get()
|
||||
self.assertEqual(review.rating, 5)
|
||||
self.assertEqual(review.user, self.user)
|
||||
detail = self.client.get(self.product.get_absolute_url())
|
||||
self.assertContains(detail, "Great")
|
||||
self.assertContains(detail, "You already reviewed")
|
||||
|
||||
def test_order_history_hides_other_users(self):
|
||||
mine = _sold_order(self.product, number="ORD-MINE")
|
||||
mine.user = self.user
|
||||
mine.save(update_fields=["user"])
|
||||
_sold_order(self.product, number="ORD-THEIRS")
|
||||
page = self.client.get(reverse("account:orders"))
|
||||
self.assertContains(page, "ORD-MINE")
|
||||
self.assertNotContains(page, "ORD-THEIRS")
|
||||
|
||||
Reference in New Issue
Block a user