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

17 KiB

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