add Basic tier, monthly/yearly billing, and supplier detail redesign
- New Basic tier (€39/mo or €349/yr): verified directory listing with enquiry form, contact sidebar, services checklist, social links, no leads - Monthly + yearly billing for all paid tiers; yearly defaults selected in signup wizard with CSS-only price toggle (no JS state) - Redesigned supplier_detail.html: navy hero with court-grid pattern, two-column body+sidebar for Basic+, tier-adaptive CTA strips - Supplier enquiry form: HTMX-powered, rate-limited 5/24h, email relayed via worker task; supplier_enquiries table tracks all submissions - New supplier columns: services_offered, contact_role, linkedin_url, instagram_url, youtube_url (migration 0012) - _lead_tier_required decorator restricts lead feed to growth/pro; Basic users see overview + listing tabs only - Admin: basic tier in dropdown, new fields in form/detail + enquiry count - setup_paddle.py: adds 4 new products with yearly interval support - Webhook handler strips _monthly/_yearly suffixes, Basic gets 0 credits and is_verified=1; existing growth/pro webhooks unchanged - Sort order: pro > growth > basic > free - 572 tests pass (+2 new for basic tier + yearly webhook variants) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -296,6 +296,55 @@ class TestSupplierSubscriptionActivated:
|
||||
assert sup[0][0] == 1 # highlight
|
||||
assert sup[0][1] == 1 # is_verified
|
||||
|
||||
async def test_basic_plan_sets_tier_zero_credits_and_verified(
|
||||
self, client, db, supplier, paddle_products, test_user,
|
||||
):
|
||||
"""Basic plan: tier='basic', 0 credits, is_verified=1, no ledger entry."""
|
||||
payload = make_supplier_activation_payload(
|
||||
items=[],
|
||||
supplier_id=supplier["id"],
|
||||
plan="supplier_basic",
|
||||
user_id=test_user["id"],
|
||||
)
|
||||
resp = await _post_webhook(client, payload)
|
||||
assert resp.status_code == 200
|
||||
|
||||
row = await db.execute_fetchall(
|
||||
"SELECT tier, credit_balance, monthly_credits, is_verified FROM suppliers WHERE id = ?",
|
||||
(supplier["id"],),
|
||||
)
|
||||
assert row[0][0] == "basic"
|
||||
assert row[0][1] == 0
|
||||
assert row[0][2] == 0
|
||||
assert row[0][3] == 1
|
||||
|
||||
# No credit ledger entry for Basic (0 credits)
|
||||
ledger = await db.execute_fetchall(
|
||||
"SELECT id FROM credit_ledger WHERE supplier_id = ?",
|
||||
(supplier["id"],),
|
||||
)
|
||||
assert len(ledger) == 0
|
||||
|
||||
async def test_yearly_plan_derives_correct_tier(
|
||||
self, client, db, supplier, paddle_products, test_user,
|
||||
):
|
||||
"""Yearly plan key suffix is stripped; tier derives correctly."""
|
||||
payload = make_supplier_activation_payload(
|
||||
items=[("pri_growth", 1)],
|
||||
supplier_id=supplier["id"],
|
||||
plan="supplier_growth_yearly", # yearly variant
|
||||
user_id=test_user["id"],
|
||||
)
|
||||
resp = await _post_webhook(client, payload)
|
||||
assert resp.status_code == 200
|
||||
|
||||
row = await db.execute_fetchall(
|
||||
"SELECT tier, credit_balance FROM suppliers WHERE id = ?",
|
||||
(supplier["id"],),
|
||||
)
|
||||
assert row[0][0] == "growth"
|
||||
assert row[0][1] == 30
|
||||
|
||||
async def test_no_supplier_id_is_noop(
|
||||
self, client, db, supplier, paddle_products, test_user,
|
||||
):
|
||||
|
||||
Reference in New Issue
Block a user