Files
orion/app/modules/orders/docs/oms-features.md
Samir Boulahtit f141cc4e6a docs: migrate module documentation to single source of truth
Move 39 documentation files from top-level docs/ into each module's
docs/ folder, accessible via symlinks from docs/modules/. Create
data-model.md files for 10 modules with full schema documentation.
Replace originals with redirect stubs. Remove empty guide stubs.

Modules migrated: tenancy, billing, loyalty, marketplace, orders,
messaging, cms, catalog, inventory, hosting, prospecting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:38:37 +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