docs: add OMS positioning strategy and implementation plan
- Add "Lightweight OMS for Letzshop Sellers" positioning strategy - Add back-office vs marketing positioning comparison - Update pricing tiers for OMS model (Essential/Professional/Business) - Add VAT invoice feature technical specification - Add comprehensive OMS feature implementation plan - Fix code block formatting in synology doc New docs: - docs/marketing/strategy/back-office-positioning.md - docs/marketing/strategy/customer-marketing-positioning.md - docs/implementation/vat-invoice-feature.md - docs/implementation/oms-feature-plan.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,13 +55,15 @@ Git is an open-source, distributed version control system that helps you manage
|
||||
```
|
||||
Adding new repository on NAS DS223J
|
||||
|
||||
> ssh boulaht1@DS223J
|
||||
> sudo -i
|
||||
> cd /volume1/git-repos/
|
||||
> git --bare init my-repo.git
|
||||
> chown -R git-boulaht1:users my-repo.git
|
||||
> cd my-repo.git/
|
||||
|
||||
```bash
|
||||
> ssh boulaht1@DS223J
|
||||
> sudo -i
|
||||
> cd /volume1/git-repos/
|
||||
> git --bare init my-repo.git
|
||||
> chown -R git-boulaht1:users my-repo.git
|
||||
> cd my-repo.git/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ✅ **Steps to Push Local Git Repo to Synology NAS**
|
||||
|
||||
662
docs/implementation/oms-feature-plan.md
Normal file
662
docs/implementation/oms-feature-plan.md
Normal file
@@ -0,0 +1,662 @@
|
||||
# OMS Feature Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Transform Wizamart into a **"Lightweight OMS for Letzshop Sellers"** by building the missing features that justify the tier pricing structure.
|
||||
|
||||
**Goal:** Ship Essential tier quickly, then build Professional differentiators, then Business features.
|
||||
|
||||
## Design Decisions (Confirmed)
|
||||
|
||||
| Decision | Choice |
|
||||
|----------|--------|
|
||||
| Phase 1 scope | Invoicing + Tier Limits together |
|
||||
| PDF library | WeasyPrint (HTML/CSS to PDF) |
|
||||
| Invoice style | Simple & Clean (minimal design) |
|
||||
|
||||
---
|
||||
|
||||
## Current State Summary
|
||||
|
||||
### Already Production-Ready
|
||||
- Multi-tenant architecture (Company → Vendor hierarchy)
|
||||
- Letzshop order sync, confirmation, tracking
|
||||
- Inventory management with locations and reservations
|
||||
- Unified Order model (direct + marketplace)
|
||||
- Customer model with pre-calculated stats (total_orders, total_spent)
|
||||
- Team management + RBAC
|
||||
- CSV export patterns (products)
|
||||
|
||||
### Needs to be Built
|
||||
| Feature | Tier Impact | Priority |
|
||||
|---------|-------------|----------|
|
||||
| Basic LU Invoice (PDF) | Essential | P0 |
|
||||
| Tier limits enforcement | Essential | P0 |
|
||||
| Vendor VAT Settings | Professional | P1 |
|
||||
| EU VAT Invoice | Professional | P1 |
|
||||
| Incoming Stock / PO | Professional | P1 |
|
||||
| Customer CSV Export | Professional | P1 |
|
||||
| Multi-vendor view | Business | P2 |
|
||||
| Accounting export | Business | P2 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Essential Tier (Target: 1 week)
|
||||
|
||||
**Goal:** Launch Essential (€49) with basic invoicing and tier enforcement.
|
||||
|
||||
### Step 1.1: Vendor Invoice Settings (1 day)
|
||||
|
||||
**Create model for vendor billing details:**
|
||||
|
||||
```
|
||||
models/database/vendor_invoice_settings.py
|
||||
```
|
||||
|
||||
Fields:
|
||||
- `vendor_id` (FK, unique - one-to-one)
|
||||
- `company_name` (legal name for invoices)
|
||||
- `company_address`, `company_city`, `company_postal_code`, `company_country`
|
||||
- `vat_number` (e.g., "LU12345678")
|
||||
- `invoice_prefix` (default "INV")
|
||||
- `invoice_next_number` (auto-increment)
|
||||
- `payment_terms` (optional text)
|
||||
- `bank_details` (optional IBAN etc.)
|
||||
- `footer_text` (optional)
|
||||
|
||||
**Pattern to follow:** `models/database/letzshop.py` (VendorLetzshopCredentials)
|
||||
|
||||
**Files to create/modify:**
|
||||
- `models/database/vendor_invoice_settings.py` (new)
|
||||
- `models/database/__init__.py` (add import)
|
||||
- `models/database/vendor.py` (add relationship)
|
||||
- `models/schema/invoice.py` (new - Pydantic schemas)
|
||||
- `alembic/versions/xxx_add_vendor_invoice_settings.py` (migration)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.2: Basic Invoice Model (0.5 day)
|
||||
|
||||
**Create invoice storage:**
|
||||
|
||||
```
|
||||
models/database/invoice.py
|
||||
```
|
||||
|
||||
Fields:
|
||||
- `id`, `vendor_id` (FK)
|
||||
- `order_id` (FK, nullable - for manual invoices later)
|
||||
- `invoice_number` (unique per vendor)
|
||||
- `invoice_date`
|
||||
- `seller_details` (JSONB snapshot)
|
||||
- `buyer_details` (JSONB snapshot)
|
||||
- `line_items` (JSONB snapshot)
|
||||
- `subtotal_cents`, `vat_rate`, `vat_amount_cents`, `total_cents`
|
||||
- `currency` (default EUR)
|
||||
- `status` (draft, issued, paid, cancelled)
|
||||
- `pdf_generated_at`, `pdf_path` (optional)
|
||||
|
||||
**Files to create/modify:**
|
||||
- `models/database/invoice.py` (new)
|
||||
- `models/database/__init__.py` (add import)
|
||||
- `alembic/versions/xxx_add_invoices_table.py` (migration)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.3: Invoice Service - Basic LU Only (1 day)
|
||||
|
||||
**Create service for invoice generation:**
|
||||
|
||||
```
|
||||
app/services/invoice_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `create_invoice_from_order(order_id, vendor_id)` - Generate invoice from order
|
||||
- `get_invoice(invoice_id, vendor_id)` - Retrieve invoice
|
||||
- `list_invoices(vendor_id, skip, limit)` - List vendor invoices
|
||||
- `_generate_invoice_number(settings)` - Auto-increment number
|
||||
- `_snapshot_seller(settings)` - Capture vendor details
|
||||
- `_snapshot_buyer(order)` - Capture customer details
|
||||
- `_calculate_totals(order)` - Calculate with LU VAT (17%)
|
||||
|
||||
**For Essential tier:** Fixed 17% Luxembourg VAT only. EU VAT comes in Professional.
|
||||
|
||||
**Files to create:**
|
||||
- `app/services/invoice_service.py` (new)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.4: PDF Generation (1.5 days)
|
||||
|
||||
**Add WeasyPrint dependency and create PDF service:**
|
||||
|
||||
```
|
||||
app/services/invoice_pdf_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `generate_pdf(invoice)` - Returns PDF bytes
|
||||
- `_render_html(invoice)` - Jinja2 template rendering
|
||||
|
||||
**Template:**
|
||||
```
|
||||
app/templates/invoices/invoice.html
|
||||
```
|
||||
|
||||
Simple, clean invoice layout:
|
||||
- Seller details (top left)
|
||||
- Buyer details (top right)
|
||||
- Invoice number + date
|
||||
- Line items table
|
||||
- Totals with VAT breakdown
|
||||
- Footer (payment terms, bank details)
|
||||
|
||||
**Files to create/modify:**
|
||||
- `requirements.txt` (add weasyprint)
|
||||
- `app/services/invoice_pdf_service.py` (new)
|
||||
- `app/templates/invoices/invoice.html` (new)
|
||||
- `app/templates/invoices/invoice.css` (new, optional)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.5: Invoice API Endpoints (0.5 day)
|
||||
|
||||
**Create vendor invoice endpoints:**
|
||||
|
||||
```
|
||||
app/api/v1/vendor/invoices.py
|
||||
```
|
||||
|
||||
Endpoints:
|
||||
- `POST /orders/{order_id}/invoice` - Generate invoice for order
|
||||
- `GET /invoices` - List invoices
|
||||
- `GET /invoices/{invoice_id}` - Get invoice details
|
||||
- `GET /invoices/{invoice_id}/pdf` - Download PDF
|
||||
|
||||
**Files to create/modify:**
|
||||
- `app/api/v1/vendor/invoices.py` (new)
|
||||
- `app/api/v1/vendor/__init__.py` (add router)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.6: Invoice Settings UI (0.5 day)
|
||||
|
||||
**Add invoice settings to vendor settings page:**
|
||||
|
||||
Modify existing vendor settings template to add "Invoice Settings" section:
|
||||
- Company name, address fields
|
||||
- VAT number
|
||||
- Invoice prefix
|
||||
- Payment terms
|
||||
- Bank details
|
||||
|
||||
**Files to modify:**
|
||||
- `app/templates/vendor/settings.html` (add section)
|
||||
- `static/vendor/js/settings.js` (add handlers)
|
||||
- `app/api/v1/vendor/settings.py` (add endpoints if needed)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.7: Order Detail - Invoice Button (0.5 day)
|
||||
|
||||
**Add "Generate Invoice" / "Download Invoice" button to order detail:**
|
||||
|
||||
- If no invoice: Show "Generate Invoice" button
|
||||
- If invoice exists: Show "Download Invoice" link
|
||||
|
||||
**Files to modify:**
|
||||
- `app/templates/vendor/order-detail.html` (add button)
|
||||
- `static/vendor/js/order-detail.js` (add handler)
|
||||
|
||||
---
|
||||
|
||||
### Step 1.8: Tier Limits Enforcement (1 day)
|
||||
|
||||
**Create tier/subscription model:**
|
||||
|
||||
```
|
||||
models/database/vendor_subscription.py
|
||||
```
|
||||
|
||||
Fields:
|
||||
- `vendor_id` (FK, unique)
|
||||
- `tier` (essential, professional, business)
|
||||
- `orders_this_month` (counter, reset monthly)
|
||||
- `period_start`, `period_end`
|
||||
- `is_active`
|
||||
|
||||
**Create limits service:**
|
||||
|
||||
```
|
||||
app/services/tier_limits_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `check_order_limit(vendor_id)` - Returns (allowed: bool, remaining: int)
|
||||
- `increment_order_count(vendor_id)` - Called when order synced
|
||||
- `get_tier_limits(tier)` - Returns limit config
|
||||
- `reset_monthly_counters()` - Cron job
|
||||
|
||||
**Tier limits:**
|
||||
| Tier | Orders/month | Products |
|
||||
|------|--------------|----------|
|
||||
| Essential | 100 | 200 |
|
||||
| Professional | 500 | Unlimited |
|
||||
| Business | Unlimited | Unlimited |
|
||||
|
||||
**Integration points:**
|
||||
- `order_service.py` - Check limit before creating order
|
||||
- Letzshop sync - Check limit before importing
|
||||
|
||||
**Files to create/modify:**
|
||||
- `models/database/vendor_subscription.py` (new)
|
||||
- `app/services/tier_limits_service.py` (new)
|
||||
- `app/services/order_service.py` (add limit check)
|
||||
- `app/services/letzshop/order_service.py` (add limit check)
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Professional Tier (Target: 2 weeks)
|
||||
|
||||
**Goal:** Build the differentiating features that justify €99/month.
|
||||
|
||||
### Step 2.1: EU VAT Rates Table (0.5 day)
|
||||
|
||||
**Create VAT rates reference table:**
|
||||
|
||||
```
|
||||
models/database/eu_vat_rates.py
|
||||
```
|
||||
|
||||
Fields:
|
||||
- `country_code` (LU, DE, FR, etc.)
|
||||
- `country_name`
|
||||
- `standard_rate` (decimal)
|
||||
- `reduced_rate_1`, `reduced_rate_2` (optional)
|
||||
- `effective_from`, `effective_until`
|
||||
|
||||
**Seed with current EU rates (27 countries).**
|
||||
|
||||
**Files to create:**
|
||||
- `models/database/eu_vat_rates.py` (new)
|
||||
- `alembic/versions/xxx_add_eu_vat_rates.py` (migration + seed)
|
||||
|
||||
---
|
||||
|
||||
### Step 2.2: Enhanced Vendor VAT Settings (0.5 day)
|
||||
|
||||
**Add OSS fields to VendorInvoiceSettings:**
|
||||
|
||||
- `is_oss_registered` (boolean)
|
||||
- `oss_registration_country` (if different from company country)
|
||||
|
||||
**Files to modify:**
|
||||
- `models/database/vendor_invoice_settings.py` (add fields)
|
||||
- `alembic/versions/xxx_add_oss_fields.py` (migration)
|
||||
|
||||
---
|
||||
|
||||
### Step 2.3: VAT Service (1 day)
|
||||
|
||||
**Create VAT calculation service:**
|
||||
|
||||
```
|
||||
app/services/vat_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `get_vat_rate(country_code, as_of_date)` - Lookup rate
|
||||
- `determine_vat_regime(seller_country, buyer_country, buyer_vat_number, is_oss)` - Returns (regime, rate)
|
||||
- `validate_vat_number(vat_number)` - Format check (VIES integration later)
|
||||
|
||||
**VAT Decision Logic:**
|
||||
1. B2B with valid VAT number → Reverse charge (0%)
|
||||
2. Domestic sale → Domestic VAT
|
||||
3. Cross-border + OSS registered → Destination VAT
|
||||
4. Cross-border + under threshold → Origin VAT
|
||||
|
||||
**Files to create:**
|
||||
- `app/services/vat_service.py` (new)
|
||||
|
||||
---
|
||||
|
||||
### Step 2.4: Enhanced Invoice Service (1 day)
|
||||
|
||||
**Upgrade invoice service for EU VAT:**
|
||||
|
||||
- Add `vat_regime` field to invoice (domestic, oss, reverse_charge, origin)
|
||||
- Add `destination_country` field
|
||||
- Use VATService to calculate correct rate
|
||||
- Update invoice template for regime-specific text
|
||||
|
||||
**Files to modify:**
|
||||
- `models/database/invoice.py` (add fields)
|
||||
- `app/services/invoice_service.py` (use VATService)
|
||||
- `app/templates/invoices/invoice.html` (add regime text)
|
||||
- `alembic/versions/xxx_add_vat_regime_to_invoices.py`
|
||||
|
||||
---
|
||||
|
||||
### Step 2.5: Purchase Order Model (1 day)
|
||||
|
||||
**Create purchase order tracking:**
|
||||
|
||||
```
|
||||
models/database/purchase_order.py
|
||||
```
|
||||
|
||||
**PurchaseOrder:**
|
||||
- `id`, `vendor_id` (FK)
|
||||
- `po_number` (auto-generated)
|
||||
- `supplier_name` (free text for now)
|
||||
- `status` (draft, ordered, partial, received, cancelled)
|
||||
- `order_date`, `expected_date`
|
||||
- `notes`
|
||||
|
||||
**PurchaseOrderItem:**
|
||||
- `purchase_order_id` (FK)
|
||||
- `product_id` (FK)
|
||||
- `quantity_ordered`
|
||||
- `quantity_received`
|
||||
- `unit_cost_cents` (optional)
|
||||
|
||||
**Files to create:**
|
||||
- `models/database/purchase_order.py` (new)
|
||||
- `models/database/__init__.py` (add import)
|
||||
- `models/schema/purchase_order.py` (new)
|
||||
- `alembic/versions/xxx_add_purchase_orders.py`
|
||||
|
||||
---
|
||||
|
||||
### Step 2.6: Purchase Order Service (1 day)
|
||||
|
||||
**Create PO management service:**
|
||||
|
||||
```
|
||||
app/services/purchase_order_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `create_purchase_order(vendor_id, data)` - Create PO
|
||||
- `add_item(po_id, product_id, quantity)` - Add line item
|
||||
- `receive_items(po_id, items)` - Mark items received, update inventory
|
||||
- `get_incoming_stock(vendor_id)` - Summary of pending stock
|
||||
- `list_purchase_orders(vendor_id, status, skip, limit)`
|
||||
|
||||
**Integration:** When items received → call `inventory_service.adjust_inventory()`
|
||||
|
||||
**Files to create:**
|
||||
- `app/services/purchase_order_service.py` (new)
|
||||
|
||||
---
|
||||
|
||||
### Step 2.7: Purchase Order UI (1.5 days)
|
||||
|
||||
**Create PO management page:**
|
||||
|
||||
```
|
||||
app/templates/vendor/purchase-orders.html
|
||||
```
|
||||
|
||||
Features:
|
||||
- List POs with status
|
||||
- Create new PO (select products, quantities, expected date)
|
||||
- Receive items (partial or full)
|
||||
- View incoming stock summary
|
||||
|
||||
**Inventory page enhancement:**
|
||||
- Show "On Order" column in inventory list
|
||||
- Query: SUM of quantity_ordered - quantity_received for pending POs
|
||||
|
||||
**Files to create/modify:**
|
||||
- `app/templates/vendor/purchase-orders.html` (new)
|
||||
- `static/vendor/js/purchase-orders.js` (new)
|
||||
- `app/api/v1/vendor/purchase_orders.py` (new endpoints)
|
||||
- `app/routes/vendor_pages.py` (add route)
|
||||
- `app/templates/vendor/partials/sidebar.html` (add menu item)
|
||||
- `app/templates/vendor/inventory.html` (add On Order column)
|
||||
|
||||
---
|
||||
|
||||
### Step 2.8: Customer Export Service (1 day)
|
||||
|
||||
**Create customer export functionality:**
|
||||
|
||||
```
|
||||
app/services/customer_export_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `export_customers_csv(vendor_id, filters)` - Returns CSV string
|
||||
|
||||
**CSV Columns:**
|
||||
- email, first_name, last_name, phone
|
||||
- customer_number
|
||||
- total_orders, total_spent, avg_order_value
|
||||
- first_order_date, last_order_date
|
||||
- preferred_language
|
||||
- marketing_consent
|
||||
- tags (if we add tagging)
|
||||
|
||||
**Files to create:**
|
||||
- `app/services/customer_export_service.py` (new)
|
||||
|
||||
---
|
||||
|
||||
### Step 2.9: Customer Export API + UI (0.5 day)
|
||||
|
||||
**Add export endpoint:**
|
||||
|
||||
```
|
||||
GET /api/v1/vendor/customers/export?format=csv
|
||||
```
|
||||
|
||||
**Add export button to customers page:**
|
||||
- "Export to CSV" button
|
||||
- Downloads file directly
|
||||
|
||||
**Files to modify:**
|
||||
- `app/api/v1/vendor/customers.py` (add export endpoint)
|
||||
- `app/templates/vendor/customers.html` (add button)
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Business Tier (Target: 1-2 weeks)
|
||||
|
||||
**Goal:** Build features for teams and high-volume operations.
|
||||
|
||||
### Step 3.1: Multi-Vendor Consolidated View (2 days)
|
||||
|
||||
**For companies with multiple Letzshop accounts:**
|
||||
|
||||
**New page:**
|
||||
```
|
||||
app/templates/vendor/multi-vendor-dashboard.html
|
||||
```
|
||||
|
||||
Features:
|
||||
- See all vendor accounts under same company
|
||||
- Consolidated order count, revenue
|
||||
- Switch between vendor contexts
|
||||
- Unified reporting
|
||||
|
||||
**Requires:** Company-level authentication context (already exists via Company → Vendor relationship)
|
||||
|
||||
**Files to create/modify:**
|
||||
- `app/templates/vendor/multi-vendor-dashboard.html` (new)
|
||||
- `app/services/multi_vendor_service.py` (new)
|
||||
- `app/api/v1/vendor/multi_vendor.py` (new)
|
||||
|
||||
---
|
||||
|
||||
### Step 3.2: Accounting Export (1 day)
|
||||
|
||||
**Export invoices in accounting-friendly formats:**
|
||||
|
||||
```
|
||||
app/services/accounting_export_service.py
|
||||
```
|
||||
|
||||
Methods:
|
||||
- `export_invoices_csv(vendor_id, date_from, date_to)` - Simple CSV
|
||||
- `export_invoices_xml(vendor_id, date_from, date_to)` - For accounting software
|
||||
|
||||
**CSV format for accountants:**
|
||||
- invoice_number, invoice_date
|
||||
- customer_name, customer_vat
|
||||
- subtotal, vat_rate, vat_amount, total
|
||||
- currency, status
|
||||
|
||||
**Files to create:**
|
||||
- `app/services/accounting_export_service.py` (new)
|
||||
- `app/api/v1/vendor/accounting.py` (new endpoints)
|
||||
|
||||
---
|
||||
|
||||
### Step 3.3: API Access Documentation (1 day)
|
||||
|
||||
**If not already documented, create API documentation page:**
|
||||
|
||||
- Document existing vendor API endpoints
|
||||
- Add rate limiting for API tier
|
||||
- Generate API keys for vendors
|
||||
|
||||
**Files to create/modify:**
|
||||
- `docs/api/vendor-api.md` (documentation)
|
||||
- `app/services/api_key_service.py` (if needed)
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order Summary
|
||||
|
||||
### Week 1: Essential Tier
|
||||
| Day | Task | Deliverable |
|
||||
|-----|------|-------------|
|
||||
| 1 | Step 1.1 | Vendor Invoice Settings model |
|
||||
| 1 | Step 1.2 | Invoice model |
|
||||
| 2 | Step 1.3 | Invoice Service (LU only) |
|
||||
| 3-4 | Step 1.4 | PDF Generation |
|
||||
| 4 | Step 1.5 | Invoice API |
|
||||
| 5 | Step 1.6 | Invoice Settings UI |
|
||||
| 5 | Step 1.7 | Order Detail button |
|
||||
|
||||
### Week 2: Tier Limits + EU VAT Start
|
||||
| Day | Task | Deliverable |
|
||||
|-----|------|-------------|
|
||||
| 1 | Step 1.8 | Tier limits enforcement |
|
||||
| 2 | Step 2.1 | EU VAT rates table |
|
||||
| 2 | Step 2.2 | OSS fields |
|
||||
| 3 | Step 2.3 | VAT Service |
|
||||
| 4 | Step 2.4 | Enhanced Invoice Service |
|
||||
| 5 | Testing | End-to-end invoice testing |
|
||||
|
||||
### Week 3: Purchase Orders + Customer Export
|
||||
| Day | Task | Deliverable |
|
||||
|-----|------|-------------|
|
||||
| 1 | Step 2.5 | Purchase Order model |
|
||||
| 2 | Step 2.6 | Purchase Order service |
|
||||
| 3-4 | Step 2.7 | Purchase Order UI |
|
||||
| 5 | Step 2.8-2.9 | Customer Export |
|
||||
|
||||
### Week 4: Business Tier
|
||||
| Day | Task | Deliverable |
|
||||
|-----|------|-------------|
|
||||
| 1-2 | Step 3.1 | Multi-vendor view |
|
||||
| 3 | Step 3.2 | Accounting export |
|
||||
| 4 | Step 3.3 | API documentation |
|
||||
| 5 | Testing + Polish | Full testing |
|
||||
|
||||
---
|
||||
|
||||
## Key Files Reference
|
||||
|
||||
### Models to Create
|
||||
- `models/database/vendor_invoice_settings.py`
|
||||
- `models/database/invoice.py`
|
||||
- `models/database/eu_vat_rates.py`
|
||||
- `models/database/vendor_subscription.py`
|
||||
- `models/database/purchase_order.py`
|
||||
|
||||
### Services to Create
|
||||
- `app/services/invoice_service.py`
|
||||
- `app/services/invoice_pdf_service.py`
|
||||
- `app/services/vat_service.py`
|
||||
- `app/services/tier_limits_service.py`
|
||||
- `app/services/purchase_order_service.py`
|
||||
- `app/services/customer_export_service.py`
|
||||
- `app/services/accounting_export_service.py`
|
||||
|
||||
### Templates to Create
|
||||
- `app/templates/invoices/invoice.html`
|
||||
- `app/templates/vendor/purchase-orders.html`
|
||||
|
||||
### Existing Files to Modify
|
||||
- `models/database/__init__.py`
|
||||
- `models/database/vendor.py`
|
||||
- `app/services/order_service.py`
|
||||
- `app/templates/vendor/settings.html`
|
||||
- `app/templates/vendor/order-detail.html`
|
||||
- `app/templates/vendor/inventory.html`
|
||||
- `app/templates/vendor/customers.html`
|
||||
- `requirements.txt`
|
||||
|
||||
---
|
||||
|
||||
## Dependencies to Add
|
||||
|
||||
```
|
||||
# requirements.txt
|
||||
weasyprint>=60.0
|
||||
```
|
||||
|
||||
**Note:** WeasyPrint requires system dependencies:
|
||||
- `libpango-1.0-0`
|
||||
- `libpangocairo-1.0-0`
|
||||
- `libgdk-pixbuf2.0-0`
|
||||
|
||||
Add to Dockerfile if deploying via Docker.
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- `tests/unit/services/test_invoice_service.py`
|
||||
- `tests/unit/services/test_vat_service.py`
|
||||
- `tests/unit/services/test_tier_limits_service.py`
|
||||
- `tests/unit/services/test_purchase_order_service.py`
|
||||
|
||||
### Integration Tests
|
||||
- `tests/integration/api/v1/vendor/test_invoices.py`
|
||||
- `tests/integration/api/v1/vendor/test_purchase_orders.py`
|
||||
|
||||
### Manual Testing
|
||||
- Generate invoice for LU customer
|
||||
- Generate invoice for DE customer (OSS)
|
||||
- Generate invoice for B2B with VAT number (reverse charge)
|
||||
- Create PO, receive items, verify inventory update
|
||||
- Export customers CSV, import to Mailchimp
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### Essential Tier Ready When:
|
||||
- [ ] Can generate PDF invoice from order (LU VAT)
|
||||
- [ ] Invoice settings page works
|
||||
- [ ] Order detail shows invoice button
|
||||
- [ ] Tier limits enforced on order sync
|
||||
|
||||
### Professional Tier Ready When:
|
||||
- [ ] EU VAT calculated correctly by destination
|
||||
- [ ] OSS regime supported
|
||||
- [ ] Reverse charge for B2B supported
|
||||
- [ ] Purchase orders can be created and received
|
||||
- [ ] Incoming stock shows in inventory
|
||||
- [ ] Customer export to CSV works
|
||||
|
||||
### Business Tier Ready When:
|
||||
- [ ] Multi-vendor dashboard works
|
||||
- [ ] Accounting export works
|
||||
- [ ] API access documented
|
||||
734
docs/implementation/vat-invoice-feature.md
Normal file
734
docs/implementation/vat-invoice-feature.md
Normal file
@@ -0,0 +1,734 @@
|
||||
# VAT Invoice Feature - Technical Specification
|
||||
|
||||
## Overview
|
||||
|
||||
Generate compliant PDF invoices with correct VAT calculation based on destination country, handling EU cross-border VAT rules including OSS (One-Stop-Shop) regime.
|
||||
|
||||
---
|
||||
|
||||
## EU VAT Rules Summary
|
||||
|
||||
### Standard VAT Rates by Country (2024)
|
||||
|
||||
| Country | Code | Standard Rate | Reduced |
|
||||
|---------|------|---------------|---------|
|
||||
| Luxembourg | LU | 17% | 8%, 3% |
|
||||
| Germany | DE | 19% | 7% |
|
||||
| France | FR | 20% | 10%, 5.5% |
|
||||
| Belgium | BE | 21% | 12%, 6% |
|
||||
| Netherlands | NL | 21% | 9% |
|
||||
| Austria | AT | 20% | 13%, 10% |
|
||||
| Italy | IT | 22% | 10%, 5%, 4% |
|
||||
| Spain | ES | 21% | 10%, 4% |
|
||||
| Portugal | PT | 23% | 13%, 6% |
|
||||
| Ireland | IE | 23% | 13.5%, 9% |
|
||||
| Poland | PL | 23% | 8%, 5% |
|
||||
| Czech Republic | CZ | 21% | 15%, 10% |
|
||||
| ... | ... | ... | ... |
|
||||
|
||||
### When to Apply Which VAT
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ VAT DECISION TREE │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Is buyer a business with valid VAT number? │
|
||||
│ ├── YES → Reverse charge (0% VAT, buyer accounts for it) │
|
||||
│ └── NO → Continue... │
|
||||
│ │
|
||||
│ Is destination same country as seller? │
|
||||
│ ├── YES → Apply domestic VAT (Luxembourg = 17%) │
|
||||
│ └── NO → Continue... │
|
||||
│ │
|
||||
│ Is seller registered for OSS? │
|
||||
│ ├── YES → Apply destination country VAT rate │
|
||||
│ └── NO → Continue... │
|
||||
│ │
|
||||
│ Has seller exceeded €10,000 EU threshold? │
|
||||
│ ├── YES → Must register OSS, apply destination VAT │
|
||||
│ └── NO → Apply origin country VAT (Luxembourg = 17%) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Model
|
||||
|
||||
### New Tables
|
||||
|
||||
```sql
|
||||
-- VAT configuration per vendor
|
||||
CREATE TABLE vendor_vat_settings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
vendor_id UUID NOT NULL REFERENCES vendors(id),
|
||||
|
||||
-- Company details for invoices
|
||||
company_name VARCHAR(255) NOT NULL,
|
||||
company_address TEXT NOT NULL,
|
||||
company_city VARCHAR(100) NOT NULL,
|
||||
company_postal_code VARCHAR(20) NOT NULL,
|
||||
company_country VARCHAR(2) NOT NULL DEFAULT 'LU',
|
||||
vat_number VARCHAR(50), -- e.g., "LU12345678"
|
||||
|
||||
-- VAT regime
|
||||
is_vat_registered BOOLEAN DEFAULT TRUE,
|
||||
is_oss_registered BOOLEAN DEFAULT FALSE, -- One-Stop-Shop
|
||||
|
||||
-- Invoice numbering
|
||||
invoice_prefix VARCHAR(20) DEFAULT 'INV',
|
||||
invoice_next_number INTEGER DEFAULT 1,
|
||||
|
||||
-- Optional
|
||||
payment_terms TEXT, -- e.g., "Due upon receipt"
|
||||
bank_details TEXT, -- IBAN, etc.
|
||||
footer_text TEXT, -- Legal text, thank you message
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- EU VAT rates reference table
|
||||
CREATE TABLE eu_vat_rates (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
country_code VARCHAR(2) NOT NULL, -- ISO 3166-1 alpha-2
|
||||
country_name VARCHAR(100) NOT NULL,
|
||||
standard_rate DECIMAL(5,2) NOT NULL, -- e.g., 17.00
|
||||
reduced_rate_1 DECIMAL(5,2),
|
||||
reduced_rate_2 DECIMAL(5,2),
|
||||
super_reduced_rate DECIMAL(5,2),
|
||||
effective_from DATE NOT NULL,
|
||||
effective_until DATE, -- NULL = current
|
||||
|
||||
UNIQUE(country_code, effective_from)
|
||||
);
|
||||
|
||||
-- Generated invoices
|
||||
CREATE TABLE invoices (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
vendor_id UUID NOT NULL REFERENCES vendors(id),
|
||||
order_id UUID REFERENCES orders(id), -- Can be NULL for manual invoices
|
||||
|
||||
-- Invoice identity
|
||||
invoice_number VARCHAR(50) NOT NULL, -- e.g., "INV-2024-0042"
|
||||
invoice_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||
|
||||
-- Parties
|
||||
seller_details JSONB NOT NULL, -- Snapshot of vendor at invoice time
|
||||
buyer_details JSONB NOT NULL, -- Snapshot of customer at invoice time
|
||||
|
||||
-- VAT calculation details
|
||||
destination_country VARCHAR(2) NOT NULL,
|
||||
vat_regime VARCHAR(20) NOT NULL, -- 'domestic', 'oss', 'reverse_charge', 'origin'
|
||||
vat_rate DECIMAL(5,2) NOT NULL,
|
||||
|
||||
-- Amounts
|
||||
subtotal_net DECIMAL(12,2) NOT NULL, -- Before VAT
|
||||
vat_amount DECIMAL(12,2) NOT NULL,
|
||||
total_gross DECIMAL(12,2) NOT NULL, -- After VAT
|
||||
currency VARCHAR(3) DEFAULT 'EUR',
|
||||
|
||||
-- Line items snapshot
|
||||
line_items JSONB NOT NULL,
|
||||
|
||||
-- PDF storage
|
||||
pdf_path VARCHAR(500), -- Path to generated PDF
|
||||
pdf_generated_at TIMESTAMP,
|
||||
|
||||
-- Status
|
||||
status VARCHAR(20) DEFAULT 'draft', -- draft, issued, paid, cancelled
|
||||
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE(vendor_id, invoice_number)
|
||||
);
|
||||
```
|
||||
|
||||
### Line Items JSONB Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"description": "Product Name",
|
||||
"sku": "ABC123",
|
||||
"quantity": 2,
|
||||
"unit_price_net": 25.00,
|
||||
"vat_rate": 17.00,
|
||||
"vat_amount": 8.50,
|
||||
"line_total_net": 50.00,
|
||||
"line_total_gross": 58.50
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Layer
|
||||
|
||||
### VATService
|
||||
|
||||
```python
|
||||
# app/services/vat_service.py
|
||||
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
from typing import Optional
|
||||
|
||||
class VATService:
|
||||
"""Handles VAT calculation logic for EU cross-border sales."""
|
||||
|
||||
# Fallback rates if DB lookup fails
|
||||
DEFAULT_RATES = {
|
||||
'LU': Decimal('17.00'),
|
||||
'DE': Decimal('19.00'),
|
||||
'FR': Decimal('20.00'),
|
||||
'BE': Decimal('21.00'),
|
||||
'NL': Decimal('21.00'),
|
||||
'AT': Decimal('20.00'),
|
||||
'IT': Decimal('22.00'),
|
||||
'ES': Decimal('21.00'),
|
||||
# ... etc
|
||||
}
|
||||
|
||||
def __init__(self, db_session):
|
||||
self.db = db_session
|
||||
|
||||
def get_vat_rate(self, country_code: str, as_of: date = None) -> Decimal:
|
||||
"""Get current VAT rate for a country."""
|
||||
as_of = as_of or date.today()
|
||||
|
||||
# Try DB first
|
||||
rate = self.db.query(EUVATRate).filter(
|
||||
EUVATRate.country_code == country_code,
|
||||
EUVATRate.effective_from <= as_of,
|
||||
(EUVATRate.effective_until.is_(None) | (EUVATRate.effective_until >= as_of))
|
||||
).first()
|
||||
|
||||
if rate:
|
||||
return rate.standard_rate
|
||||
|
||||
# Fallback
|
||||
return self.DEFAULT_RATES.get(country_code, Decimal('0.00'))
|
||||
|
||||
def determine_vat_regime(
|
||||
self,
|
||||
seller_country: str,
|
||||
buyer_country: str,
|
||||
buyer_vat_number: Optional[str],
|
||||
seller_is_oss: bool,
|
||||
seller_exceeded_threshold: bool = False
|
||||
) -> tuple[str, Decimal]:
|
||||
"""
|
||||
Determine which VAT regime applies and the rate.
|
||||
|
||||
Returns: (regime_name, vat_rate)
|
||||
"""
|
||||
# B2B with valid VAT number = reverse charge
|
||||
if buyer_vat_number and self._validate_vat_number(buyer_vat_number):
|
||||
return ('reverse_charge', Decimal('0.00'))
|
||||
|
||||
# Domestic sale
|
||||
if seller_country == buyer_country:
|
||||
return ('domestic', self.get_vat_rate(seller_country))
|
||||
|
||||
# Cross-border B2C
|
||||
if seller_is_oss:
|
||||
# OSS: destination country VAT
|
||||
return ('oss', self.get_vat_rate(buyer_country))
|
||||
|
||||
if seller_exceeded_threshold:
|
||||
# Should be OSS but isn't - use destination anyway (compliance issue)
|
||||
return ('oss_required', self.get_vat_rate(buyer_country))
|
||||
|
||||
# Under threshold: origin country VAT
|
||||
return ('origin', self.get_vat_rate(seller_country))
|
||||
|
||||
def _validate_vat_number(self, vat_number: str) -> bool:
|
||||
"""
|
||||
Validate EU VAT number format.
|
||||
For production: integrate with VIES API.
|
||||
"""
|
||||
if not vat_number or len(vat_number) < 4:
|
||||
return False
|
||||
|
||||
# Basic format check: 2-letter country + numbers
|
||||
country = vat_number[:2].upper()
|
||||
return country in self.DEFAULT_RATES
|
||||
|
||||
def calculate_invoice_totals(
|
||||
self,
|
||||
line_items: list[dict],
|
||||
vat_rate: Decimal
|
||||
) -> dict:
|
||||
"""Calculate invoice totals with VAT."""
|
||||
subtotal_net = Decimal('0.00')
|
||||
|
||||
for item in line_items:
|
||||
quantity = Decimal(str(item['quantity']))
|
||||
unit_price = Decimal(str(item['unit_price_net']))
|
||||
line_net = quantity * unit_price
|
||||
|
||||
item['line_total_net'] = float(line_net)
|
||||
item['vat_rate'] = float(vat_rate)
|
||||
item['vat_amount'] = float(line_net * vat_rate / 100)
|
||||
item['line_total_gross'] = float(line_net + line_net * vat_rate / 100)
|
||||
|
||||
subtotal_net += line_net
|
||||
|
||||
vat_amount = subtotal_net * vat_rate / 100
|
||||
total_gross = subtotal_net + vat_amount
|
||||
|
||||
return {
|
||||
'subtotal_net': float(subtotal_net),
|
||||
'vat_rate': float(vat_rate),
|
||||
'vat_amount': float(vat_amount),
|
||||
'total_gross': float(total_gross),
|
||||
'line_items': line_items
|
||||
}
|
||||
```
|
||||
|
||||
### InvoiceService
|
||||
|
||||
```python
|
||||
# app/services/invoice_service.py
|
||||
|
||||
class InvoiceService:
|
||||
"""Generate and manage invoices."""
|
||||
|
||||
def __init__(self, db_session, vat_service: VATService):
|
||||
self.db = db_session
|
||||
self.vat = vat_service
|
||||
|
||||
def create_invoice_from_order(
|
||||
self,
|
||||
order_id: UUID,
|
||||
vendor_id: UUID
|
||||
) -> Invoice:
|
||||
"""Generate invoice from an existing order."""
|
||||
order = self.db.query(Order).get(order_id)
|
||||
vat_settings = self.db.query(VendorVATSettings).filter_by(
|
||||
vendor_id=vendor_id
|
||||
).first()
|
||||
|
||||
if not vat_settings:
|
||||
raise ValueError("Vendor VAT settings not configured")
|
||||
|
||||
# Determine VAT regime
|
||||
regime, rate = self.vat.determine_vat_regime(
|
||||
seller_country=vat_settings.company_country,
|
||||
buyer_country=order.shipping_country,
|
||||
buyer_vat_number=order.customer_vat_number,
|
||||
seller_is_oss=vat_settings.is_oss_registered
|
||||
)
|
||||
|
||||
# Prepare line items
|
||||
line_items = [
|
||||
{
|
||||
'description': item.product_name,
|
||||
'sku': item.sku,
|
||||
'quantity': item.quantity,
|
||||
'unit_price_net': float(item.unit_price)
|
||||
}
|
||||
for item in order.items
|
||||
]
|
||||
|
||||
# Calculate totals
|
||||
totals = self.vat.calculate_invoice_totals(line_items, rate)
|
||||
|
||||
# Generate invoice number
|
||||
invoice_number = self._generate_invoice_number(vat_settings)
|
||||
|
||||
# Create invoice
|
||||
invoice = Invoice(
|
||||
vendor_id=vendor_id,
|
||||
order_id=order_id,
|
||||
invoice_number=invoice_number,
|
||||
invoice_date=date.today(),
|
||||
seller_details=self._snapshot_seller(vat_settings),
|
||||
buyer_details=self._snapshot_buyer(order),
|
||||
destination_country=order.shipping_country,
|
||||
vat_regime=regime,
|
||||
vat_rate=rate,
|
||||
subtotal_net=totals['subtotal_net'],
|
||||
vat_amount=totals['vat_amount'],
|
||||
total_gross=totals['total_gross'],
|
||||
line_items={'items': totals['line_items']},
|
||||
status='issued'
|
||||
)
|
||||
|
||||
self.db.add(invoice)
|
||||
self.db.commit()
|
||||
|
||||
return invoice
|
||||
|
||||
def _generate_invoice_number(self, settings: VendorVATSettings) -> str:
|
||||
"""Generate next invoice number and increment counter."""
|
||||
year = date.today().year
|
||||
number = settings.invoice_next_number
|
||||
|
||||
invoice_number = f"{settings.invoice_prefix}-{year}-{number:04d}"
|
||||
|
||||
settings.invoice_next_number += 1
|
||||
self.db.commit()
|
||||
|
||||
return invoice_number
|
||||
|
||||
def _snapshot_seller(self, settings: VendorVATSettings) -> dict:
|
||||
"""Capture seller details at invoice time."""
|
||||
return {
|
||||
'company_name': settings.company_name,
|
||||
'address': settings.company_address,
|
||||
'city': settings.company_city,
|
||||
'postal_code': settings.company_postal_code,
|
||||
'country': settings.company_country,
|
||||
'vat_number': settings.vat_number
|
||||
}
|
||||
|
||||
def _snapshot_buyer(self, order: Order) -> dict:
|
||||
"""Capture buyer details at invoice time."""
|
||||
return {
|
||||
'name': f"{order.shipping_first_name} {order.shipping_last_name}",
|
||||
'company': order.shipping_company,
|
||||
'address': order.shipping_address,
|
||||
'city': order.shipping_city,
|
||||
'postal_code': order.shipping_postal_code,
|
||||
'country': order.shipping_country,
|
||||
'vat_number': order.customer_vat_number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PDF Generation
|
||||
|
||||
### Using WeasyPrint
|
||||
|
||||
```python
|
||||
# app/services/invoice_pdf_service.py
|
||||
|
||||
from weasyprint import HTML, CSS
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
class InvoicePDFService:
|
||||
"""Generate PDF invoices."""
|
||||
|
||||
def __init__(self, template_dir: str = 'app/templates/invoices'):
|
||||
self.env = Environment(loader=FileSystemLoader(template_dir))
|
||||
|
||||
def generate_pdf(self, invoice: Invoice) -> bytes:
|
||||
"""Generate PDF bytes from invoice."""
|
||||
template = self.env.get_template('invoice.html')
|
||||
|
||||
html_content = template.render(
|
||||
invoice=invoice,
|
||||
seller=invoice.seller_details,
|
||||
buyer=invoice.buyer_details,
|
||||
items=invoice.line_items['items'],
|
||||
vat_label=self._get_vat_label(invoice.vat_regime)
|
||||
)
|
||||
|
||||
pdf_bytes = HTML(string=html_content).write_pdf(
|
||||
stylesheets=[CSS(filename='app/static/css/invoice.css')]
|
||||
)
|
||||
|
||||
return pdf_bytes
|
||||
|
||||
def _get_vat_label(self, regime: str) -> str:
|
||||
"""Human-readable VAT regime label."""
|
||||
labels = {
|
||||
'domestic': 'TVA Luxembourg',
|
||||
'oss': 'TVA (OSS - pays de destination)',
|
||||
'reverse_charge': 'Autoliquidation (Reverse Charge)',
|
||||
'origin': 'TVA pays d\'origine'
|
||||
}
|
||||
return labels.get(regime, 'TVA')
|
||||
```
|
||||
|
||||
### Invoice HTML Template
|
||||
|
||||
```html
|
||||
<!-- app/templates/invoices/invoice.html -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; font-size: 11pt; }
|
||||
.header { display: flex; justify-content: space-between; margin-bottom: 30px; }
|
||||
.invoice-title { font-size: 24pt; color: #333; }
|
||||
.parties { display: flex; justify-content: space-between; margin-bottom: 30px; }
|
||||
.party-box { width: 45%; }
|
||||
.party-label { font-weight: bold; color: #666; margin-bottom: 5px; }
|
||||
table { width: 100%; border-collapse: collapse; margin-bottom: 30px; }
|
||||
th { background: #f5f5f5; padding: 10px; text-align: left; border-bottom: 2px solid #ddd; }
|
||||
td { padding: 10px; border-bottom: 1px solid #eee; }
|
||||
.amount { text-align: right; }
|
||||
.totals { width: 300px; margin-left: auto; }
|
||||
.totals td { padding: 5px 10px; }
|
||||
.totals .total-row { font-weight: bold; font-size: 14pt; border-top: 2px solid #333; }
|
||||
.footer { margin-top: 50px; font-size: 9pt; color: #666; }
|
||||
.vat-note { background: #f9f9f9; padding: 10px; margin-top: 20px; font-size: 9pt; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="invoice-title">FACTURE</div>
|
||||
<div>
|
||||
<strong>{{ invoice.invoice_number }}</strong><br>
|
||||
Date: {{ invoice.invoice_date.strftime('%d/%m/%Y') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="parties">
|
||||
<div class="party-box">
|
||||
<div class="party-label">De:</div>
|
||||
<strong>{{ seller.company_name }}</strong><br>
|
||||
{{ seller.address }}<br>
|
||||
{{ seller.postal_code }} {{ seller.city }}<br>
|
||||
{{ seller.country }}<br>
|
||||
{% if seller.vat_number %}TVA: {{ seller.vat_number }}{% endif %}
|
||||
</div>
|
||||
<div class="party-box">
|
||||
<div class="party-label">Facturé à:</div>
|
||||
<strong>{{ buyer.name }}</strong><br>
|
||||
{% if buyer.company %}{{ buyer.company }}<br>{% endif %}
|
||||
{{ buyer.address }}<br>
|
||||
{{ buyer.postal_code }} {{ buyer.city }}<br>
|
||||
{{ buyer.country }}<br>
|
||||
{% if buyer.vat_number %}TVA: {{ buyer.vat_number }}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if invoice.order_id %}
|
||||
<p><strong>Référence commande:</strong> {{ invoice.order_id }}</p>
|
||||
{% endif %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th>Qté</th>
|
||||
<th class="amount">Prix unit. HT</th>
|
||||
<th class="amount">Total HT</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in items %}
|
||||
<tr>
|
||||
<td>{{ item.description }}{% if item.sku %} <small>({{ item.sku }})</small>{% endif %}</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td class="amount">€{{ "%.2f"|format(item.unit_price_net) }}</td>
|
||||
<td class="amount">€{{ "%.2f"|format(item.line_total_net) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="totals">
|
||||
<tr>
|
||||
<td>Sous-total HT:</td>
|
||||
<td class="amount">€{{ "%.2f"|format(invoice.subtotal_net) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ vat_label }} ({{ invoice.vat_rate }}%):</td>
|
||||
<td class="amount">€{{ "%.2f"|format(invoice.vat_amount) }}</td>
|
||||
</tr>
|
||||
<tr class="total-row">
|
||||
<td>TOTAL TTC:</td>
|
||||
<td class="amount">€{{ "%.2f"|format(invoice.total_gross) }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{% if invoice.vat_regime == 'reverse_charge' %}
|
||||
<div class="vat-note">
|
||||
<strong>Autoliquidation de la TVA</strong><br>
|
||||
En application de l'article 196 de la directive 2006/112/CE, la TVA est due par le preneur.
|
||||
</div>
|
||||
{% elif invoice.vat_regime == 'oss' %}
|
||||
<div class="vat-note">
|
||||
<strong>Régime OSS (One-Stop-Shop)</strong><br>
|
||||
TVA calculée selon le taux du pays de destination ({{ invoice.destination_country }}).
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="footer">
|
||||
{% if seller.payment_terms %}{{ seller.payment_terms }}<br>{% endif %}
|
||||
{% if seller.bank_details %}{{ seller.bank_details }}<br>{% endif %}
|
||||
{% if seller.footer_text %}{{ seller.footer_text }}{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
```python
|
||||
# app/api/v1/vendor/invoices.py
|
||||
|
||||
@router.post("/orders/{order_id}/invoice")
|
||||
async def create_invoice_from_order(
|
||||
order_id: UUID,
|
||||
vendor: Vendor = Depends(get_current_vendor),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Generate invoice for an order."""
|
||||
service = InvoiceService(db, VATService(db))
|
||||
invoice = service.create_invoice_from_order(order_id, vendor.id)
|
||||
return InvoiceResponse.from_orm(invoice)
|
||||
|
||||
@router.get("/invoices/{invoice_id}/pdf")
|
||||
async def download_invoice_pdf(
|
||||
invoice_id: UUID,
|
||||
vendor: Vendor = Depends(get_current_vendor),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Download invoice as PDF."""
|
||||
invoice = db.query(Invoice).filter(
|
||||
Invoice.id == invoice_id,
|
||||
Invoice.vendor_id == vendor.id
|
||||
).first()
|
||||
|
||||
if not invoice:
|
||||
raise HTTPException(404, "Invoice not found")
|
||||
|
||||
pdf_service = InvoicePDFService()
|
||||
pdf_bytes = pdf_service.generate_pdf(invoice)
|
||||
|
||||
return Response(
|
||||
content=pdf_bytes,
|
||||
media_type="application/pdf",
|
||||
headers={
|
||||
"Content-Disposition": f"attachment; filename={invoice.invoice_number}.pdf"
|
||||
}
|
||||
)
|
||||
|
||||
@router.get("/invoices")
|
||||
async def list_invoices(
|
||||
vendor: Vendor = Depends(get_current_vendor),
|
||||
db: Session = Depends(get_db),
|
||||
skip: int = 0,
|
||||
limit: int = 50
|
||||
):
|
||||
"""List all invoices for vendor."""
|
||||
invoices = db.query(Invoice).filter(
|
||||
Invoice.vendor_id == vendor.id
|
||||
).order_by(Invoice.invoice_date.desc()).offset(skip).limit(limit).all()
|
||||
|
||||
return [InvoiceResponse.from_orm(inv) for inv in invoices]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UI Integration
|
||||
|
||||
### Order Detail - Invoice Button
|
||||
|
||||
```html
|
||||
<!-- In order detail view -->
|
||||
{% if not order.invoice %}
|
||||
<button
|
||||
@click="generateInvoice('{{ order.id }}')"
|
||||
class="btn btn-secondary">
|
||||
<i data-lucide="file-text"></i>
|
||||
Generate Invoice
|
||||
</button>
|
||||
{% else %}
|
||||
<a
|
||||
href="/api/v1/vendor/invoices/{{ order.invoice.id }}/pdf"
|
||||
class="btn btn-secondary"
|
||||
target="_blank">
|
||||
<i data-lucide="download"></i>
|
||||
Download Invoice ({{ order.invoice.invoice_number }})
|
||||
</a>
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
### Vendor Settings - VAT Configuration
|
||||
|
||||
```html
|
||||
<!-- New settings tab for VAT/Invoice configuration -->
|
||||
<div class="settings-section">
|
||||
<h3>Invoice Settings</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Company Name (for invoices)</label>
|
||||
<input type="text" x-model="settings.company_name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Company Address</label>
|
||||
<textarea x-model="settings.company_address" rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>Postal Code</label>
|
||||
<input type="text" x-model="settings.company_postal_code">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>City</label>
|
||||
<input type="text" x-model="settings.company_city">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>VAT Number</label>
|
||||
<input type="text" x-model="settings.vat_number" placeholder="LU12345678">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" x-model="settings.is_oss_registered">
|
||||
Registered for OSS (One-Stop-Shop)
|
||||
</label>
|
||||
<small>Check this if you're registered to report EU VAT through the OSS system</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Invoice Number Prefix</label>
|
||||
<input type="text" x-model="settings.invoice_prefix" placeholder="INV">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Payment Terms</label>
|
||||
<input type="text" x-model="settings.payment_terms" placeholder="Due upon receipt">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Bank Details (optional)</label>
|
||||
<textarea x-model="settings.bank_details" rows="2" placeholder="IBAN: LU..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Effort
|
||||
|
||||
| Component | Estimate |
|
||||
|-----------|----------|
|
||||
| Database migrations | 0.5 day |
|
||||
| VAT rates seed data | 0.5 day |
|
||||
| VATService | 1 day |
|
||||
| InvoiceService | 1 day |
|
||||
| PDF generation | 1.5 days |
|
||||
| API endpoints | 0.5 day |
|
||||
| UI (settings + order button) | 1 day |
|
||||
| Testing | 1 day |
|
||||
| **Total** | **~7 days** |
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **VIES VAT Validation** - Verify B2B VAT numbers via EU API
|
||||
2. **Credit Notes** - For returns/refunds
|
||||
3. **Batch Invoice Generation** - Generate for multiple orders
|
||||
4. **Email Delivery** - Send invoice PDF by email
|
||||
5. **Accounting Export** - CSV/XML for accounting software
|
||||
@@ -1,5 +1,13 @@
|
||||
# Pricing Strategy
|
||||
|
||||
## Product Positioning
|
||||
|
||||
**"Lightweight OMS for Letzshop Sellers"**
|
||||
|
||||
A focused Order Management System that works alongside Letzshop, not instead of it. Provides the operational tools Letzshop lacks: real inventory, correct invoicing, customer ownership.
|
||||
|
||||
---
|
||||
|
||||
## Market Context
|
||||
|
||||
### Luxembourg E-commerce Landscape
|
||||
@@ -11,151 +19,140 @@
|
||||
|
||||
### Competitor Reference
|
||||
- Letzshop charges vendors ~15% commission on sales
|
||||
- Enterprise solutions (Shopify Plus, etc.): EUR 300-2000+/month
|
||||
- Local agencies: EUR 500-3000 for custom integrations
|
||||
- Enterprise OMS (SAP, NetSuite): EUR 500-5000+/month
|
||||
- Local agencies for custom integrations: EUR 5,000-20,000
|
||||
- Spreadsheets: Free but error-prone and time-consuming
|
||||
|
||||
---
|
||||
|
||||
## Pricing Tiers
|
||||
|
||||
### Starter - EUR 49/month
|
||||
**Target:** Small vendors, 1-50 orders/month
|
||||
### Essential - EUR 49/month
|
||||
|
||||
| Included | Limit |
|
||||
|----------|-------|
|
||||
**Target:** Solo vendors, getting started, Letzshop-focused
|
||||
|
||||
| Feature | Limit |
|
||||
|---------|-------|
|
||||
| Letzshop Order Sync | Up to 100 orders/month |
|
||||
| Order Confirmation/Rejection | Unlimited |
|
||||
| Tracking Number Sync | Unlimited |
|
||||
| Product Export (CSV) | 3 exports/month |
|
||||
| Team Members | 2 users |
|
||||
| Email Support | 48h response |
|
||||
| Order Confirmation & Tracking | Included |
|
||||
| Inventory Management | Up to 200 products |
|
||||
| Basic Invoice (Luxembourg VAT) | Included |
|
||||
| Customer List | View only |
|
||||
| Team Members | 1 user |
|
||||
| Order History | 6 months |
|
||||
| Email Support | 72h response |
|
||||
|
||||
**Value Proposition:** "Stop copying orders manually. Save 5+ hours/month."
|
||||
**Value Proposition:** "Stop the spreadsheet chaos. Your orders, inventory, and invoices in one place."
|
||||
|
||||
**ROI Calculation:**
|
||||
- Time saved: 5 hours/month at EUR 25/hour = EUR 125 value
|
||||
- Price: EUR 49
|
||||
- **Net savings: EUR 76/month**
|
||||
**Upgrade Triggers:**
|
||||
- Exceeds 100 orders/month
|
||||
- Ships to other EU countries (needs VAT invoicing)
|
||||
- Needs team access
|
||||
- Has more than 200 products
|
||||
|
||||
---
|
||||
|
||||
### Professional - EUR 99/month
|
||||
**Target:** Active vendors, 50-200 orders/month
|
||||
|
||||
| Included | Limit |
|
||||
|----------|-------|
|
||||
| Everything in Starter | - |
|
||||
**Target:** Active multi-channel vendors, shipping EU-wide
|
||||
|
||||
| Feature | Limit |
|
||||
|---------|-------|
|
||||
| Letzshop Order Sync | Up to 500 orders/month |
|
||||
| Product Import (CSV) | Unlimited |
|
||||
| Product Export (CSV) | Unlimited |
|
||||
| Inventory Management | Full access |
|
||||
| Order Item Exceptions | Full resolution tools |
|
||||
| Team Members | 5 users |
|
||||
| Team Roles & Permissions | Full access |
|
||||
| Order Confirmation & Tracking | Included |
|
||||
| Inventory Management | Unlimited products |
|
||||
| **EU VAT Invoices** | Correct VAT for any EU country |
|
||||
| **Product Locations** | Warehouse/bin tracking |
|
||||
| **Incoming Stock / Purchase Orders** | Track what's on order |
|
||||
| **Customer Export** | CSV for Mailchimp, marketing |
|
||||
| Team Members | 3 users |
|
||||
| Order History | 24 months |
|
||||
| Priority Email Support | 24h response |
|
||||
|
||||
**Value Proposition:** "Complete Letzshop automation + team collaboration."
|
||||
**Value Proposition:** "Professional operations. Correct invoices. Know your customers."
|
||||
|
||||
**ROI Calculation:**
|
||||
- Time saved: 15 hours/month at EUR 25/hour = EUR 375 value
|
||||
- Prevented order errors: ~EUR 50/month
|
||||
- Time saved: 10+ hours/month at EUR 25/hour = EUR 250 value
|
||||
- Accountant VAT corrections avoided: EUR 50/month
|
||||
- Price: EUR 99
|
||||
- **Net savings: EUR 326/month**
|
||||
- **Net value: EUR 200+/month**
|
||||
|
||||
**Upgrade Triggers:**
|
||||
- Exceeds 500 orders/month
|
||||
- Multiple Letzshop vendor accounts
|
||||
- Needs API for integrations
|
||||
- Team grows beyond 3
|
||||
|
||||
---
|
||||
|
||||
### Business - EUR 199/month
|
||||
**Target:** High-volume vendors, 200+ orders/month
|
||||
|
||||
| Included | Limit |
|
||||
|----------|-------|
|
||||
| Everything in Professional | - |
|
||||
**Target:** High-volume vendors, teams, multiple operations
|
||||
|
||||
| Feature | Limit |
|
||||
|---------|-------|
|
||||
| Letzshop Order Sync | Unlimited orders |
|
||||
| Customer Messaging | Full inbox |
|
||||
| Analytics Dashboard | Advanced metrics |
|
||||
| Team Members | 15 users |
|
||||
| Everything in Professional | Included |
|
||||
| **Multi-Vendor Support** | Multiple Letzshop accounts |
|
||||
| **API Access** | For custom integrations |
|
||||
| **Accounting Export** | CSV/XML for accounting software |
|
||||
| Team Members | 10 users |
|
||||
| Team Roles & Permissions | Full access control |
|
||||
| Order History | Unlimited |
|
||||
| Phone Support | Available |
|
||||
| Dedicated Onboarding | Included |
|
||||
| Dedicated Onboarding | 2-hour session included |
|
||||
|
||||
**Value Proposition:** "Enterprise-grade automation at SMB pricing."
|
||||
**Value Proposition:** "Enterprise-grade OMS at SMB pricing."
|
||||
|
||||
---
|
||||
|
||||
### Enterprise - Custom Pricing
|
||||
**Target:** Multi-vendor companies, special requirements
|
||||
|
||||
| Included | Notes |
|
||||
|----------|-------|
|
||||
| Everything in Business | - |
|
||||
| Multiple Vendor Accounts | Consolidated billing |
|
||||
| Custom Integrations | API development |
|
||||
**Target:** Large operations, special requirements
|
||||
|
||||
| Feature | Notes |
|
||||
|---------|-------|
|
||||
| Everything in Business | Included |
|
||||
| Unlimited Team Members | As needed |
|
||||
| Custom Integrations | Built to spec |
|
||||
| SLA Guarantee | 99.9% uptime |
|
||||
| Dedicated Account Manager | Named contact |
|
||||
| Custom Reporting | Built to spec |
|
||||
| On-Premise Option | If required |
|
||||
|
||||
**Starting at EUR 499/month** - Contact for quote
|
||||
|
||||
---
|
||||
|
||||
## Add-On Services
|
||||
## Feature Comparison Matrix
|
||||
|
||||
### One-Time Services
|
||||
|
||||
| Service | Price | Description |
|
||||
|---------|-------|-------------|
|
||||
| Onboarding & Training | EUR 199 | 2-hour session + setup assistance |
|
||||
| Data Migration | EUR 299 | Import existing products/orders |
|
||||
| Custom CSV Mapping | EUR 149 | Map your specific CSV format |
|
||||
|
||||
### Monthly Add-Ons
|
||||
|
||||
| Add-On | Price | Description |
|
||||
|--------|-------|-------------|
|
||||
| Additional Marketplace | +EUR 29/mo | Per additional marketplace |
|
||||
| Extra Team Members | +EUR 5/user/mo | Beyond plan limit |
|
||||
| API Access | +EUR 49/mo | For custom integrations |
|
||||
|
||||
---
|
||||
|
||||
## For Vendors with Own Websites
|
||||
|
||||
### Scenario A: Keep Existing Website + Add Automation
|
||||
|
||||
For vendors who want to keep their WooCommerce/Shopify/custom site but need Letzshop integration.
|
||||
|
||||
**Connector Service - EUR 149/month**
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| Bidirectional Order Sync | Website <-> Letzshop |
|
||||
| Inventory Sync | Real-time stock levels |
|
||||
| Product Sync | Push products to Letzshop |
|
||||
| Unified Dashboard | See all orders in one place |
|
||||
|
||||
**One-Time Setup: EUR 499-999** (depending on platform complexity)
|
||||
|
||||
Supported Platforms:
|
||||
- WooCommerce (WordPress)
|
||||
- Shopify
|
||||
- PrestaShop
|
||||
- Magento (custom quote)
|
||||
- Custom PHP/API (custom quote)
|
||||
|
||||
### Scenario B: Migrate to Wizamart Platform
|
||||
|
||||
For vendors wanting a complete solution.
|
||||
|
||||
**Migration Package - EUR 799 one-time**
|
||||
|
||||
Includes:
|
||||
- Full product catalog migration
|
||||
- Customer data import
|
||||
- Order history import (last 12 months)
|
||||
- DNS/domain setup assistance
|
||||
- 2-week parallel running period
|
||||
- 3 months at Professional tier
|
||||
|
||||
**Then continues at chosen tier pricing.**
|
||||
| Feature | Essential | Professional | Business |
|
||||
|---------|:---------:|:------------:|:--------:|
|
||||
| **Orders** |
|
||||
| Letzshop Sync | 100/mo | 500/mo | Unlimited |
|
||||
| Order Confirmation | ✓ | ✓ | ✓ |
|
||||
| Tracking Sync | ✓ | ✓ | ✓ |
|
||||
| Order History | 6 months | 24 months | Unlimited |
|
||||
| **Inventory** |
|
||||
| Product Limit | 200 | Unlimited | Unlimited |
|
||||
| Stock Levels | ✓ | ✓ | ✓ |
|
||||
| Product Locations | - | ✓ | ✓ |
|
||||
| Incoming Stock / PO | - | ✓ | ✓ |
|
||||
| **Invoicing** |
|
||||
| Luxembourg Invoice | ✓ | ✓ | ✓ |
|
||||
| EU VAT Invoice | - | ✓ | ✓ |
|
||||
| Accounting Export | - | - | ✓ |
|
||||
| **Customers** |
|
||||
| Customer List | View | View + Export | View + Export |
|
||||
| **Team** |
|
||||
| Users | 1 | 3 | 10 |
|
||||
| Roles & Permissions | - | - | ✓ |
|
||||
| **Operations** |
|
||||
| Multi-Vendor | - | - | ✓ |
|
||||
| API Access | - | - | ✓ |
|
||||
| **Support** |
|
||||
| Email | 72h | 24h | 24h |
|
||||
| Phone | - | - | ✓ |
|
||||
| Onboarding | - | - | Included |
|
||||
|
||||
---
|
||||
|
||||
@@ -165,39 +162,111 @@ Includes:
|
||||
|
||||
| Offer | Details |
|
||||
|-------|---------|
|
||||
| 30-Day Free Trial | Full Professional features |
|
||||
| 14-Day Free Trial | Full Professional features |
|
||||
| 50% Off First 3 Months | Any tier |
|
||||
| Free Onboarding | With annual commitment |
|
||||
|
||||
### Annual Discount
|
||||
### Annual Discount (2 months free)
|
||||
|
||||
| Tier | Monthly | Annual (17% off) |
|
||||
|------|---------|------------------|
|
||||
| Starter | EUR 49/mo | EUR 490/year (EUR 41/mo) |
|
||||
| Tier | Monthly | Annual |
|
||||
|------|---------|--------|
|
||||
| Essential | EUR 49/mo | EUR 490/year (EUR 41/mo) |
|
||||
| Professional | EUR 99/mo | EUR 990/year (EUR 82/mo) |
|
||||
| Business | EUR 199/mo | EUR 1,990/year (EUR 166/mo) |
|
||||
|
||||
---
|
||||
|
||||
## Pricing Psychology Notes
|
||||
## Add-On Services
|
||||
|
||||
1. **Anchor on time saved** - Luxembourg has high labor costs. 5 hours/month at EUR 25/hour = EUR 125. Our EUR 49 plan is "obviously worth it."
|
||||
### One-Time Services
|
||||
|
||||
2. **Professional tier is the target** - Starter exists to make Professional look reasonable. Most vendors should land on Professional.
|
||||
| Service | Price | Description |
|
||||
|---------|-------|-------------|
|
||||
| Onboarding & Training | EUR 149 | 1-hour session + setup assistance |
|
||||
| Data Migration | EUR 299 | Import existing products/orders from spreadsheets |
|
||||
| Custom Invoice Template | EUR 99 | Branded invoice design |
|
||||
|
||||
3. **No per-order fees** - Unlike Letzshop's commission model, our flat fee means the more they sell, the better the value.
|
||||
### Monthly Add-Ons
|
||||
|
||||
4. **Annual commitment = lower churn** - 17% discount is significant enough to encourage annual.
|
||||
| Add-On | Price | Description |
|
||||
|--------|-------|-------------|
|
||||
| Additional Team Member | +EUR 9/user/mo | Beyond plan limit |
|
||||
| Additional Vendor Account | +EUR 29/mo | For Professional tier |
|
||||
| Extended History | +EUR 19/mo | Unlimited history for Essential |
|
||||
|
||||
5. **Free trial removes friction** - 30 days is enough to become dependent on the automation.
|
||||
---
|
||||
|
||||
## Pricing Psychology
|
||||
|
||||
### Why This Structure Works
|
||||
|
||||
1. **Essential (EUR 49) creates entry point**
|
||||
- Low enough to try without much deliberation
|
||||
- Genuinely useful for small operations
|
||||
- Natural limits trigger upgrades organically
|
||||
|
||||
2. **Professional (EUR 99) is the target tier**
|
||||
- EU VAT invoicing is the killer feature (compliance fear)
|
||||
- Most active vendors will need this
|
||||
- Price feels reasonable for operational software
|
||||
|
||||
3. **Business (EUR 199) provides anchor**
|
||||
- Makes Professional look affordable
|
||||
- Captures high-value customers
|
||||
- Multi-vendor is a clear enterprise need
|
||||
|
||||
4. **No per-order fees**
|
||||
- Unlike Letzshop's commission model
|
||||
- The more you sell, the better the value
|
||||
- Predictable costs for budgeting
|
||||
|
||||
5. **Annual = lower churn**
|
||||
- 17% discount is meaningful
|
||||
- 2 months free is easy to understand
|
||||
- Reduces monthly cancellation opportunity
|
||||
|
||||
---
|
||||
|
||||
## Competitive Positioning
|
||||
|
||||
| Competitor | Their Model | Our Advantage |
|
||||
|------------|-------------|---------------|
|
||||
| Letzshop Direct | 15% commission | Flat fee, scales better |
|
||||
| Manual Process | Free but time-consuming | Automation pays for itself |
|
||||
| Custom Development | EUR 5,000-20,000 | Ready-to-use, maintained |
|
||||
| Enterprise Solutions | EUR 300+/month | Luxembourg-focused, simpler |
|
||||
| Alternative | Their Model | Our Advantage |
|
||||
|-------------|-------------|---------------|
|
||||
| Just Letzshop | Free but limited | Real inventory, correct VAT, customer access |
|
||||
| Spreadsheets | Free but fragile | Automated, fewer errors, scales |
|
||||
| Enterprise OMS | EUR 500+/month | Right-sized, affordable, Letzshop-specific |
|
||||
| Custom Development | EUR 5,000-20,000 | Ready now, maintained, supported |
|
||||
| Accountant fixes VAT | EUR 50-100/month | Built-in, automatic, instant |
|
||||
|
||||
---
|
||||
|
||||
## Sales Guidance
|
||||
|
||||
### Qualifying Questions
|
||||
|
||||
1. "How many orders do you process per month?"
|
||||
- <100 → Essential
|
||||
- 100-500 → Professional
|
||||
- 500+ → Business
|
||||
|
||||
2. "Do you ship to other EU countries?"
|
||||
- Yes → Professional minimum (VAT invoicing)
|
||||
- No → Essential may suffice
|
||||
|
||||
3. "How many people handle orders?"
|
||||
- 1 → Essential
|
||||
- 2-3 → Professional
|
||||
- 4+ → Business
|
||||
|
||||
4. "Do you have multiple Letzshop accounts?"
|
||||
- Yes → Business
|
||||
|
||||
### Objection Handling
|
||||
|
||||
**"EUR 49 is too much for what I get"**
|
||||
> "How much time do you spend on manual order entry and spreadsheets each month? At EUR 25/hour, 2 hours of saved time pays for itself."
|
||||
|
||||
**"I can do this with spreadsheets"**
|
||||
> "You can, until you oversell because inventory wasn't updated, or your accountant flags incorrect VAT. How much does one of those mistakes cost?"
|
||||
|
||||
**"Why do I need Professional for EU invoices?"**
|
||||
> "EU VAT rules are complex - wrong rate, wrong country, wrong invoice = compliance issues. We handle this automatically so your accountant doesn't have to fix it."
|
||||
|
||||
303
docs/marketing/strategy/back-office-positioning.md
Normal file
303
docs/marketing/strategy/back-office-positioning.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# Strategic Positioning: Lightweight OMS for Letzshop Sellers
|
||||
|
||||
## The Core Insight
|
||||
|
||||
Letzshop vendors don't need another e-commerce platform. They need a **lightweight Order Management System** that works alongside Letzshop, not instead of it.
|
||||
|
||||
**Key realization:** Competing with Letzshop's native features is weak positioning. The value is in providing a proper **OMS layer** that Letzshop lacks - inventory truth, correct invoicing, operational tools.
|
||||
|
||||
## Product Category
|
||||
|
||||
**"Lightweight OMS for Letzshop Sellers"**
|
||||
|
||||
| What It Is | What It's Not |
|
||||
|------------|---------------|
|
||||
| Order Management System | E-commerce platform |
|
||||
| Back-office operations | Customer-facing storefront |
|
||||
| Works WITH Letzshop | Replaces Letzshop |
|
||||
| Right-sized for SMB | Enterprise complexity |
|
||||
|
||||
---
|
||||
|
||||
## Real Pain Points (From Vendor Experience)
|
||||
|
||||
| Pain Point | Current Workaround | Impact |
|
||||
|------------|-------------------|--------|
|
||||
| Inventory out of sync across channels | Manual updates, spreadsheets | Overselling, lost sales |
|
||||
| Need another app to find products | Separate warehouse app, memory | Slow picking, errors |
|
||||
| Stock not linked to incoming purchases | Mental notes, spreadsheets | False "out of stock" |
|
||||
| VAT wrong for cross-border EU shipping | Accountant fixes, or ignore | Compliance risk, costs |
|
||||
| Can't retarget/contact past customers | Letzshop owns the relationship | Lost repeat business |
|
||||
|
||||
---
|
||||
|
||||
## The Positioning
|
||||
|
||||
### What We Are NOT
|
||||
- Not a Letzshop replacement
|
||||
- Not a full e-commerce platform
|
||||
- Not an enterprise ERP system
|
||||
|
||||
### What We ARE
|
||||
> **"Lightweight OMS for Letzshop Sellers"**
|
||||
>
|
||||
> Letzshop is where you sell. Wizamart is where you manage operations.
|
||||
|
||||
A focused Order Management System for vendors who:
|
||||
- Sell on Letzshop + other channels (own website, markets, B2B)
|
||||
- Need professional invoicing with correct VAT
|
||||
- Want to own their customer relationships
|
||||
- Need real inventory management, not just Letzshop's view
|
||||
|
||||
---
|
||||
|
||||
## Target Customer
|
||||
|
||||
**Primary:** Multi-channel Letzshop vendors
|
||||
- Sell on Letzshop + at least one other channel
|
||||
- 50-500 orders/month total
|
||||
- Frustrated with manual sync and spreadsheets
|
||||
- May have accountant who complains about VAT
|
||||
|
||||
**Secondary:** Growing Letzshop-only vendors
|
||||
- Planning to expand to other channels
|
||||
- Want professional operations before they scale
|
||||
- Need correct invoicing for EU customers
|
||||
|
||||
**NOT targeting:** Pure Letzshop vendors happy with manual processes
|
||||
|
||||
---
|
||||
|
||||
## Core Feature Set
|
||||
|
||||
### 1. Inventory Truth (Central Stock Management)
|
||||
**Problem:** Letzshop shows its own stock count, but vendor sells elsewhere too.
|
||||
|
||||
**Solution:**
|
||||
- Single source of truth for all inventory
|
||||
- One-way push to Letzshop (keeps it in sync)
|
||||
- Vendor updates here when selling on other channels
|
||||
- No complex connectors needed - vendor is the sync
|
||||
|
||||
**Value:** Never oversell. Always know real stock.
|
||||
|
||||
### 2. Product Locations
|
||||
**Problem:** Vendor has to open another app to find where products are stored.
|
||||
|
||||
**Solution:**
|
||||
- Location/bin field on each product
|
||||
- Shows in order picking view
|
||||
- Print pick lists with locations
|
||||
|
||||
**Value:** Faster fulfillment, fewer errors.
|
||||
|
||||
### 3. Incoming Stock / Purchase Orders
|
||||
**Problem:** Stock levels don't reflect what's on order from suppliers.
|
||||
|
||||
**Solution:**
|
||||
```
|
||||
In stock: 5 units
|
||||
Reserved: 2 units
|
||||
Available: 3 units
|
||||
On order: 50 units (arriving Jan 15)
|
||||
───────────────────────
|
||||
Available to promise: 53 units
|
||||
```
|
||||
|
||||
**Value:** Don't mark products unavailable when restock is days away.
|
||||
|
||||
### 4. Smart VAT Invoicing (Differentiator)
|
||||
**Problem:** EU VAT depends on destination country. Letzshop invoices don't handle this.
|
||||
|
||||
**Solution:**
|
||||
- Automatic VAT calculation based on ship-to country
|
||||
- Handles OSS (One-Stop-Shop) rules
|
||||
- Generates compliant PDF invoices
|
||||
- Proper VAT breakdown per rate
|
||||
|
||||
**Value:** Compliance without accountant. Professional documents.
|
||||
|
||||
### 5. Customer Ownership
|
||||
**Problem:** Letzshop owns the customer relationship. Vendor can't retarget or build loyalty.
|
||||
|
||||
**Solution:**
|
||||
- All customers in your database
|
||||
- Order history and lifetime value
|
||||
- Export for email marketing (Mailchimp, etc.)
|
||||
- Tagging and segmentation
|
||||
|
||||
**Value:** Build repeat business. Own your customers.
|
||||
|
||||
---
|
||||
|
||||
## Why This Wins
|
||||
|
||||
### Low Support Overhead
|
||||
| Feature | External Dependencies | Support Risk |
|
||||
|---------|----------------------|--------------|
|
||||
| Inventory management | None | Low |
|
||||
| Product locations | None | Very Low |
|
||||
| Purchase orders | None | Low |
|
||||
| VAT invoicing | None (just rules) | Low |
|
||||
| Customer export | None | Low |
|
||||
|
||||
No connectors to WooCommerce/Shopify = No "why isn't it syncing?" tickets.
|
||||
|
||||
### High Perceived Value
|
||||
| Feature | Why It Feels Valuable |
|
||||
|---------|----------------------|
|
||||
| Inventory truth | "Finally, one place for everything" |
|
||||
| VAT invoicing | "My accountant will love this" / fear of compliance |
|
||||
| Customer ownership | "I can finally email my customers" |
|
||||
|
||||
### Defensible Position
|
||||
Letzshop is unlikely to build:
|
||||
- Multi-channel inventory (they want you Letzshop-only)
|
||||
- Correct cross-border VAT (complex, not their core)
|
||||
- Customer export (they benefit from owning relationships)
|
||||
|
||||
---
|
||||
|
||||
## Pricing Tiers
|
||||
|
||||
### Tier Logic: What Drives Upgrades?
|
||||
|
||||
The goal is natural upgrade pressure based on **growth**, not artificial limits.
|
||||
|
||||
| Growth Signal | Triggers Upgrade To |
|
||||
|---------------|---------------------|
|
||||
| More orders | Higher tier (volume) |
|
||||
| Shipping to EU | Pro (VAT invoicing) |
|
||||
| Team grows | Pro/Business (users) |
|
||||
| More products | Pro (locations, PO) |
|
||||
| Multiple shops | Business (multi-vendor) |
|
||||
|
||||
---
|
||||
|
||||
### Essential - EUR 49/month
|
||||
|
||||
**Target:** Solo vendors, getting started, Letzshop + 1 channel
|
||||
|
||||
| Feature | Limit |
|
||||
|---------|-------|
|
||||
| Letzshop Order Sync | Up to 100 orders/month |
|
||||
| Inventory Management | Up to 200 products |
|
||||
| Basic Invoices (Luxembourg) | Included |
|
||||
| Team Members | 1 user |
|
||||
| Order History | 6 months |
|
||||
| Email Support | 72h response |
|
||||
|
||||
**Why they upgrade:** Hit order limit, need EU VAT invoices, need team access.
|
||||
|
||||
---
|
||||
|
||||
### Professional - EUR 99/month
|
||||
|
||||
**Target:** Active vendors, multi-channel, shipping EU-wide
|
||||
|
||||
| Feature | Limit |
|
||||
|---------|-------|
|
||||
| Letzshop Order Sync | Up to 500 orders/month |
|
||||
| Inventory Management | Unlimited products |
|
||||
| **EU VAT Invoices** | All EU countries |
|
||||
| **Product Locations** | Warehouse/bin tracking |
|
||||
| **Incoming Stock / PO** | Track supplier orders |
|
||||
| **Customer Export** | CSV for marketing |
|
||||
| Team Members | 3 users |
|
||||
| Order History | 24 months |
|
||||
| Priority Email Support | 24h response |
|
||||
|
||||
**Why they upgrade:** Multiple team members, multiple Letzshop accounts, need API.
|
||||
|
||||
---
|
||||
|
||||
### Business - EUR 199/month
|
||||
|
||||
**Target:** Teams, high volume, multiple vendor accounts
|
||||
|
||||
| Feature | Limit |
|
||||
|---------|-------|
|
||||
| Letzshop Order Sync | Unlimited orders |
|
||||
| Everything in Professional | Included |
|
||||
| **Multi-Vendor Support** | Multiple Letzshop accounts |
|
||||
| **API Access** | For custom integrations |
|
||||
| **Accounting Export** | CSV/XML for accountants |
|
||||
| Team Members | 10 users |
|
||||
| Team Roles & Permissions | Full RBAC |
|
||||
| Order History | Unlimited |
|
||||
| Phone Support | Available |
|
||||
| Dedicated Onboarding | Included |
|
||||
|
||||
---
|
||||
|
||||
### Feature Access by Tier
|
||||
|
||||
| Feature | Essential | Professional | Business |
|
||||
|---------|:---------:|:------------:|:--------:|
|
||||
| Letzshop Order Sync | 100/mo | 500/mo | Unlimited |
|
||||
| Inventory Management | 200 SKU | Unlimited | Unlimited |
|
||||
| Product Locations | - | ✓ | ✓ |
|
||||
| Incoming Stock / PO | - | ✓ | ✓ |
|
||||
| Basic Invoice (LU) | ✓ | ✓ | ✓ |
|
||||
| EU VAT Invoice | - | ✓ | ✓ |
|
||||
| Customer List | View | + Export | + Export |
|
||||
| Team Members | 1 | 3 | 10 |
|
||||
| Multi-Vendor | - | - | ✓ |
|
||||
| API Access | - | - | ✓ |
|
||||
| Order History | 6 mo | 24 mo | Unlimited |
|
||||
|
||||
---
|
||||
|
||||
### Why This Structure Works
|
||||
|
||||
1. **Essential (EUR 49)** is genuinely useful but has natural limits
|
||||
- 100 orders/month is ~3/day - fine for small sellers
|
||||
- Luxembourg-only invoices work if you don't ship EU
|
||||
- 1 user is fine for solo operation
|
||||
|
||||
2. **Professional (EUR 99)** unlocks the "serious" features
|
||||
- EU VAT invoicing is the killer upgrade trigger
|
||||
- Product locations + PO = operational maturity
|
||||
- 3 users = small team
|
||||
|
||||
3. **Business (EUR 199)** is for scale
|
||||
- Multi-vendor = manages multiple Letzshop shops
|
||||
- API = integrates with other systems
|
||||
- 10 users = real team
|
||||
|
||||
**Price anchoring:** EUR 99 is the target tier. EUR 49 exists to capture price-sensitive leads. EUR 199 exists to make EUR 99 look reasonable.
|
||||
|
||||
---
|
||||
|
||||
## Competitive Positioning
|
||||
|
||||
| Alternative | Their Limitation | Our Advantage |
|
||||
|-------------|------------------|---------------|
|
||||
| Just use Letzshop | No multi-channel inventory, wrong VAT, no customer access | Complete back-office |
|
||||
| Spreadsheets | Error-prone, no automation, time-consuming | Professional, synced |
|
||||
| Full ERP (SAP, Odoo) | Overkill, expensive, complex | Right-sized, affordable |
|
||||
| Accountant fixes VAT | EUR 50-100/month for corrections | Built-in, automatic |
|
||||
|
||||
---
|
||||
|
||||
## Go-to-Market
|
||||
|
||||
### Message Hierarchy
|
||||
|
||||
**Primary:** "The back-office Letzshop doesn't give you"
|
||||
|
||||
**Supporting:**
|
||||
1. "One inventory for all your channels"
|
||||
2. "Invoices with correct VAT, any EU country"
|
||||
3. "Your customers, your data"
|
||||
|
||||
### Initial Outreach Target
|
||||
Vendors who:
|
||||
- Have their own website AND Letzshop presence
|
||||
- Ship to multiple EU countries
|
||||
- Have complained about Letzshop limitations
|
||||
|
||||
### Proof Points to Gather
|
||||
- Time saved per week on manual sync
|
||||
- VAT corrections avoided
|
||||
- Overselling incidents prevented
|
||||
272
docs/marketing/strategy/customer-marketing-positioning.md
Normal file
272
docs/marketing/strategy/customer-marketing-positioning.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# Customer Ownership & Marketing Positioning
|
||||
|
||||
## The Problem
|
||||
|
||||
Letzshop owns the customer relationship. Vendors:
|
||||
- Can't export customer emails easily
|
||||
- Can't send marketing campaigns
|
||||
- Can't retarget past buyers
|
||||
- Lose repeat business to marketplace algorithm
|
||||
|
||||
**Result:** Vendors acquire customers through Letzshop but can't turn them into loyal, direct customers.
|
||||
|
||||
---
|
||||
|
||||
## What "Customer Ownership" Could Look Like
|
||||
|
||||
### Level 1: Data Export (Simple)
|
||||
|
||||
**What it is:** Export customer list with order history to CSV.
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Wizamart Dashboard │
|
||||
│ ┌──────────────────────────────────────┐ │
|
||||
│ │ Customers (142) [Export CSV] │ │
|
||||
│ ├──────────────────────────────────────┤ │
|
||||
│ │ Marie Dupont 3 orders €245 │ │
|
||||
│ │ Jean Martin 1 order €89 │ │
|
||||
│ │ Sophie Weber 5 orders €512 │ │
|
||||
│ └──────────────────────────────────────┘ │
|
||||
└────────────────────────────────────────────┘
|
||||
│
|
||||
▼ Export
|
||||
┌────────────────────────────────────────────┐
|
||||
│ email,name,orders,total_spent,last_order │
|
||||
│ marie@...,Marie Dupont,3,245,2024-12-01 │
|
||||
│ jean@...,Jean Martin,1,89,2024-11-15 │
|
||||
└────────────────────────────────────────────┘
|
||||
│
|
||||
▼ Import manually
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Mailchimp / Brevo / etc. │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Effort:** ~2 days (you already have customer data from orders)
|
||||
**Support overhead:** Very low
|
||||
**Value:** Medium - manual but functional
|
||||
|
||||
---
|
||||
|
||||
### Level 2: Smart Segmentation (Medium)
|
||||
|
||||
**What it is:** Tag customers, filter by behavior, export segments.
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Customer Segments │
|
||||
│ ┌──────────────────────────────────────┐ │
|
||||
│ │ 🏆 VIP (5+ orders) 23 │ │
|
||||
│ │ 😴 Dormant (no order 90d) 45 │ │
|
||||
│ │ 🆕 New (first order) 12 │ │
|
||||
│ │ 🇩🇪 Germany shipping 34 │ │
|
||||
│ │ 🎁 Holiday buyers 2023 28 │ │
|
||||
│ └──────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [Export Segment to CSV] │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Auto-tagging based on behavior (VIP, dormant, new)
|
||||
- Manual tagging (wholesale, problem customer)
|
||||
- Filter by: country, order count, total spent, last order date
|
||||
- Export filtered lists
|
||||
|
||||
**Effort:** ~1 week
|
||||
**Support overhead:** Low
|
||||
**Value:** High - actionable data
|
||||
|
||||
---
|
||||
|
||||
### Level 3: Mailchimp Integration (Complex)
|
||||
|
||||
**What it is:** Direct sync with Mailchimp - customers auto-sync, segments sync, tags sync.
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐
|
||||
│ Wizamart │ ──────► │ Mailchimp │
|
||||
│ │ Sync │ │
|
||||
│ Customers │ ◄────── │ Audiences │
|
||||
│ Orders │ │ Tags │
|
||||
│ Segments │ │ Campaigns │
|
||||
└─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
**API Integration Required:**
|
||||
- Mailchimp Marketing API v3
|
||||
- OAuth 2.0 for account connection
|
||||
- Webhook for unsubscribes (GDPR)
|
||||
- Audience sync (create/update members)
|
||||
- Tag sync (apply tags from segments)
|
||||
|
||||
**Effort:** ~2-3 weeks
|
||||
**Support overhead:** MEDIUM-HIGH
|
||||
- "Why aren't my contacts syncing?"
|
||||
- "My tags aren't showing up"
|
||||
- Mailchimp API changes / deprecations
|
||||
- GDPR compliance (unsubscribe sync)
|
||||
|
||||
**Value:** High - but is it 2-3 weeks of value?
|
||||
|
||||
---
|
||||
|
||||
### Level 4: Built-in Email Marketing (Very Complex)
|
||||
|
||||
**What it is:** Send emails directly from Wizamart.
|
||||
|
||||
**Required:**
|
||||
- Email template builder
|
||||
- Email sending infrastructure (SendGrid, SES, Postmark)
|
||||
- Deliverability management (SPF, DKIM, DMARC setup)
|
||||
- Bounce/complaint handling
|
||||
- Unsubscribe management
|
||||
- Open/click tracking
|
||||
- A/B testing
|
||||
- Scheduling
|
||||
- Campaign analytics
|
||||
|
||||
**Effort:** 2-3 months (to do it well)
|
||||
**Support overhead:** VERY HIGH
|
||||
- "My emails go to spam"
|
||||
- "Why didn't my campaign send?"
|
||||
- Deliverability issues
|
||||
- GDPR compliance
|
||||
|
||||
**Value:** Very high - but you're building Mailchimp
|
||||
|
||||
**Verdict:** Don't do this. Use existing tools.
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Back-Office vs Marketing Positioning
|
||||
|
||||
### Option A: Back-Office Focus (Invoicing, Inventory, Operations)
|
||||
|
||||
| Aspect | Assessment |
|
||||
|--------|------------|
|
||||
| **Core message** | "Run your business better" |
|
||||
| **Primary features** | VAT invoicing, inventory truth, locations, incoming stock |
|
||||
| **Target emotion** | Fear (compliance), relief (organization) |
|
||||
| **Competitive moat** | VAT expertise, Letzshop-specific |
|
||||
| **Support overhead** | Low (self-contained systems) |
|
||||
| **Development effort** | ~2-3 weeks for MVP |
|
||||
| **Revenue model** | Subscription (necessary tool) |
|
||||
|
||||
**Customer type:** Operations-focused, compliance-worried
|
||||
|
||||
### Option B: Marketing Focus (Customer Ownership, Retargeting)
|
||||
|
||||
| Aspect | Assessment |
|
||||
|--------|------------|
|
||||
| **Core message** | "Grow your business" |
|
||||
| **Primary features** | Customer CRM, segmentation, Mailchimp sync |
|
||||
| **Target emotion** | Ambition (growth), frustration (Letzshop limits) |
|
||||
| **Competitive moat** | Weak (many CRM tools exist) |
|
||||
| **Support overhead** | Medium-High (external integrations) |
|
||||
| **Development effort** | ~3-4 weeks for meaningful features |
|
||||
| **Revenue model** | Subscription (growth tool) |
|
||||
|
||||
**Customer type:** Growth-focused, marketing-savvy
|
||||
|
||||
---
|
||||
|
||||
## The Strategic Question
|
||||
|
||||
### Who is easier to sell to?
|
||||
|
||||
| Customer Type | Buys Because | Objection |
|
||||
|---------------|--------------|-----------|
|
||||
| **Operations person** | "I need this to not mess up" | "Is it really necessary?" |
|
||||
| **Growth person** | "This will make me money" | "Will it actually work?" |
|
||||
|
||||
### Which has stickier retention?
|
||||
|
||||
| Tool Type | Stickiness | Why |
|
||||
|-----------|------------|-----|
|
||||
| **Back-office** | HIGH | Your invoices, inventory data - hard to migrate |
|
||||
| **Marketing** | MEDIUM | Customer list is portable, can switch tools |
|
||||
|
||||
### Which is simpler to support?
|
||||
|
||||
| Tool Type | External Dependencies | Support Risk |
|
||||
|-----------|----------------------|--------------|
|
||||
| **Back-office** | None | LOW |
|
||||
| **Marketing** | Mailchimp API, email delivery | MEDIUM-HIGH |
|
||||
|
||||
---
|
||||
|
||||
## My Recommendation
|
||||
|
||||
### Start with Back-Office, Add Customer Export
|
||||
|
||||
**Phase 1 (Now):** Back-office tools
|
||||
- VAT invoicing (differentiator, compliance fear)
|
||||
- Inventory management (already built)
|
||||
- Product locations (simple, useful)
|
||||
- Incoming stock/PO (nice to have)
|
||||
- **Customer export to CSV** (satisfies marketing need without complexity)
|
||||
|
||||
**Phase 2 (Later, if demand):** Marketing enhancement
|
||||
- Smart segmentation
|
||||
- Mailchimp sync (only if customers ask for it specifically)
|
||||
|
||||
### Why This Order?
|
||||
|
||||
1. **Back-office is a "must-have"** - vendors need correct invoices
|
||||
2. **Marketing is a "nice-to-have"** - they can use Mailchimp directly with CSV export
|
||||
3. **Lower risk** - no external API dependencies to start
|
||||
4. **Faster to market** - VAT invoicing is ~1 week, Mailchimp is ~3 weeks
|
||||
5. **Clearer positioning** - "The back-office Letzshop doesn't give you"
|
||||
|
||||
### The Hybrid Pitch
|
||||
|
||||
> "Wizamart gives you the tools Letzshop doesn't:
|
||||
>
|
||||
> - **Correct invoices** with proper VAT for any EU country
|
||||
> - **Real inventory** across all your channels
|
||||
> - **Your customers** - export anytime for your marketing
|
||||
>
|
||||
> EUR 49/month. You focus on selling, we handle the back-office."
|
||||
|
||||
The customer export feature satisfies the marketing need without building a marketing platform.
|
||||
|
||||
---
|
||||
|
||||
## If You Want Marketing Focus Instead
|
||||
|
||||
If you strongly feel marketing is the right angle:
|
||||
|
||||
### Minimum Viable Marketing Product
|
||||
|
||||
1. Customer list with order history ✓ (you have this)
|
||||
2. Basic tagging (manual + auto VIP/dormant)
|
||||
3. Segment filtering
|
||||
4. CSV export with segments
|
||||
5. **Mailchimp sync** (this is the "magic" feature)
|
||||
|
||||
**Skip:** Built-in email sending, campaign builder, analytics
|
||||
|
||||
**Effort:** ~3 weeks total
|
||||
|
||||
**The pitch becomes:**
|
||||
> "Own your Letzshop customers. Sync them to Mailchimp automatically.
|
||||
> Build repeat business without copy-pasting spreadsheets."
|
||||
|
||||
But: This competes with many existing tools. Back-office is more defensible.
|
||||
|
||||
---
|
||||
|
||||
## Final Comparison Table
|
||||
|
||||
| Factor | Back-Office (Invoicing) | Marketing (Customer CRM) |
|
||||
|--------|------------------------|--------------------------|
|
||||
| Uniqueness | HIGH (VAT expertise) | LOW (many CRM tools) |
|
||||
| Development time | ~2 weeks | ~3-4 weeks |
|
||||
| Support overhead | LOW | MEDIUM-HIGH |
|
||||
| External dependencies | NONE | Mailchimp API |
|
||||
| Stickiness | HIGH | MEDIUM |
|
||||
| Emotional driver | Fear (compliance) | Ambition (growth) |
|
||||
| Price sensitivity | LOW (necessary) | HIGH (nice-to-have) |
|
||||
| **Recommendation** | **START HERE** | Add later if demanded |
|
||||
@@ -147,6 +147,8 @@ nav:
|
||||
- Order Item Exceptions: implementation/order-item-exceptions.md
|
||||
- Product Suppliers Table: implementation/product-suppliers-table.md
|
||||
- Unified Order View: implementation/unified-order-view.md
|
||||
- VAT Invoice Feature: implementation/vat-invoice-feature.md
|
||||
- OMS Feature Plan: implementation/oms-feature-plan.md
|
||||
- Seed Scripts Audit: development/seed-scripts-audit.md
|
||||
- Database Seeder:
|
||||
- Documentation: development/database-seeder/database-seeder-documentation.md
|
||||
@@ -222,6 +224,9 @@ nav:
|
||||
- Overview: marketing/index.md
|
||||
- Feature List & Roadmap: marketing/features.md
|
||||
- Pricing Strategy: marketing/pricing.md
|
||||
- Strategy:
|
||||
- Back-Office Positioning: marketing/strategy/back-office-positioning.md
|
||||
- Customer & Marketing: marketing/strategy/customer-marketing-positioning.md
|
||||
- Outreach Templates:
|
||||
- Letzshop Automation: marketing/outreach/letzshop-automation.md
|
||||
- Website Vendors: marketing/outreach/website-vendors.md
|
||||
|
||||
Reference in New Issue
Block a user