Files
orion/docs/implementation/oms-feature-plan.md
Samir Boulahtit e9253fbd84 refactor: rename Wizamart to Orion across entire codebase
Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart
with Orion/orion/ORION across 184 files. This includes database
identifiers, email addresses, domain references, R2 bucket names,
DNS prefixes, encryption salt, Celery app name, config defaults,
Docker configs, CI configs, documentation, seed data, and templates.

Renames homepage-wizamart.html template to homepage-orion.html.
Fixes duplicate file_pattern key in api.yaml architecture rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:46:56 +01:00

663 lines
17 KiB
Markdown

# OMS Feature Implementation Plan
## Overview
Transform Orion 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 (Merchant → Store 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 |
| Store VAT Settings | Professional | P1 |
| EU VAT Invoice | Professional | P1 |
| Incoming Stock / PO | Professional | P1 |
| Customer CSV Export | Professional | P1 |
| Multi-store 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: Store Invoice Settings (1 day)
**Create model for store billing details:**
```
models/database/store_invoice_settings.py
```
Fields:
- `store_id` (FK, unique - one-to-one)
- `merchant_name` (legal name for invoices)
- `merchant_address`, `merchant_city`, `merchant_postal_code`, `merchant_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` (StoreLetzshopCredentials)
**Files to create/modify:**
- `models/database/store_invoice_settings.py` (new)
- `models/database/__init__.py` (add import)
- `models/database/store.py` (add relationship)
- `models/schema/invoice.py` (new - Pydantic schemas)
- `alembic/versions/xxx_add_store_invoice_settings.py` (migration)
---
### Step 1.2: Basic Invoice Model (0.5 day)
**Create invoice storage:**
```
models/database/invoice.py
```
Fields:
- `id`, `store_id` (FK)
- `order_id` (FK, nullable - for manual invoices later)
- `invoice_number` (unique per store)
- `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, store_id)` - Generate invoice from order
- `get_invoice(invoice_id, store_id)` - Retrieve invoice
- `list_invoices(store_id, skip, limit)` - List store invoices
- `_generate_invoice_number(settings)` - Auto-increment number
- `_snapshot_seller(settings)` - Capture store 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 store invoice endpoints:**
```
app/api/v1/store/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/store/invoices.py` (new)
- `app/api/v1/store/__init__.py` (add router)
---
### Step 1.6: Invoice Settings UI (0.5 day)
**Add invoice settings to store settings page:**
Modify existing store settings template to add "Invoice Settings" section:
- Merchant name, address fields
- VAT number
- Invoice prefix
- Payment terms
- Bank details
**Files to modify:**
- `app/templates/store/settings.html` (add section)
- `static/store/js/settings.js` (add handlers)
- `app/api/v1/store/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/store/order-detail.html` (add button)
- `static/store/js/order-detail.js` (add handler)
---
### Step 1.8: Tier Limits Enforcement (1 day)
**Create tier/subscription model:**
```
models/database/store_subscription.py
```
Fields:
- `store_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(store_id)` - Returns (allowed: bool, remaining: int)
- `increment_order_count(store_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/store_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 Store VAT Settings (0.5 day)
**Add OSS fields to StoreInvoiceSettings:**
- `is_oss_registered` (boolean)
- `oss_registration_country` (if different from merchant country)
**Files to modify:**
- `models/database/store_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`, `store_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(store_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(store_id)` - Summary of pending stock
- `list_purchase_orders(store_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/store/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/store/purchase-orders.html` (new)
- `static/store/js/purchase-orders.js` (new)
- `app/api/v1/store/purchase_orders.py` (new endpoints)
- `app/routes/store_pages.py` (add route)
- `app/templates/store/partials/sidebar.html` (add menu item)
- `app/templates/store/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(store_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/store/customers/export?format=csv
```
**Add export button to customers page:**
- "Export to CSV" button
- Downloads file directly
**Files to modify:**
- `app/api/v1/store/customers.py` (add export endpoint)
- `app/templates/store/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-Store Consolidated View (2 days)
**For merchants with multiple Letzshop accounts:**
**New page:**
```
app/templates/store/multi-store-dashboard.html
```
Features:
- See all store accounts under same merchant
- Consolidated order count, revenue
- Switch between store contexts
- Unified reporting
**Requires:** Merchant-level authentication context (already exists via Merchant → Store relationship)
**Files to create/modify:**
- `app/templates/store/multi-store-dashboard.html` (new)
- `app/services/multi_store_service.py` (new)
- `app/api/v1/store/multi_store.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(store_id, date_from, date_to)` - Simple CSV
- `export_invoices_xml(store_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/store/accounting.py` (new endpoints)
---
### Step 3.3: API Access Documentation (1 day)
**If not already documented, create API documentation page:**
- Document existing store API endpoints
- Add rate limiting for API tier
- Generate API keys for stores
**Files to create/modify:**
- `docs/api/store-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 | Store 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-store 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/store_invoice_settings.py`
- `models/database/invoice.py`
- `models/database/eu_vat_rates.py`
- `models/database/store_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/store/purchase-orders.html`
### Existing Files to Modify
- `models/database/__init__.py`
- `models/database/store.py`
- `app/services/order_service.py`
- `app/templates/store/settings.html`
- `app/templates/store/order-detail.html`
- `app/templates/store/inventory.html`
- `app/templates/store/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/store/test_invoices.py`
- `tests/integration/api/v1/store/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-store dashboard works
- [ ] Accounting export works
- [ ] API access documented