feat: add invoicing system and subscription tier enforcement

Phase 1 OMS implementation:

Invoicing:
- Add Invoice and VendorInvoiceSettings database models
- Full EU VAT support (27 countries, OSS, B2B reverse charge)
- Invoice PDF generation with WeasyPrint + Jinja2 templates
- Vendor invoice API endpoints for settings, creation, PDF download

Subscription Tiers:
- Add VendorSubscription model with 4 tiers (Essential/Professional/Business/Enterprise)
- Tier limit enforcement for orders, products, team members
- Feature gating based on subscription tier
- Automatic trial subscription creation for new vendors
- Integrate limit checks into order creation (direct and Letzshop sync)

Marketing:
- Update pricing documentation with 4-tier structure
- Revise back-office positioning strategy
- Update homepage with Veeqo-inspired Letzshop-focused messaging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-24 18:15:27 +01:00
parent 4d9b816072
commit 6232bb47f6
23 changed files with 4342 additions and 241 deletions

View File

@@ -15,6 +15,7 @@ from sqlalchemy import String, and_, func, or_
from sqlalchemy.orm import Session
from app.services.order_service import order_service as unified_order_service
from app.services.subscription_service import subscription_service
from models.database.letzshop import (
LetzshopFulfillmentQueue,
LetzshopHistoricalImportJob,
@@ -792,6 +793,7 @@ class LetzshopOrderService:
"updated": 0,
"skipped": 0,
"errors": 0,
"limit_exceeded": 0,
"products_matched": 0,
"products_not_found": 0,
"eans_processed": set(),
@@ -800,6 +802,10 @@ class LetzshopOrderService:
"error_messages": [],
}
# Get subscription usage upfront for batch efficiency
usage = subscription_service.get_usage(self.db, vendor_id)
orders_remaining = usage.orders_remaining # None = unlimited
for i, shipment in enumerate(shipments):
shipment_id = shipment.get("id")
if not shipment_id:
@@ -844,11 +850,24 @@ class LetzshopOrderService:
else:
stats["skipped"] += 1
else:
# Check tier limit before creating order
if orders_remaining is not None and orders_remaining <= 0:
stats["limit_exceeded"] += 1
stats["error_messages"].append(
f"Shipment {shipment_id}: Order limit reached"
)
continue
# Create new order using unified service
try:
self.create_order(vendor_id, shipment)
self.db.commit() # noqa: SVC-006 - background task needs incremental commits
stats["imported"] += 1
# Decrement remaining count for batch efficiency
if orders_remaining is not None:
orders_remaining -= 1
except Exception as e:
self.db.rollback() # Rollback failed order
stats["errors"] += 1