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>
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_countryvat_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_dateseller_details(JSONB snapshot)buyer_details(JSONB snapshot)line_items(JSONB snapshot)subtotal_cents,vat_rate,vat_amount_cents,total_centscurrency(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 orderget_invoice(invoice_id, store_id)- Retrieve invoicelist_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 orderGET /invoices- List invoicesGET /invoices/{invoice_id}- Get invoice detailsGET /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_endis_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 syncedget_tier_limits(tier)- Returns limit configreset_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_namestandard_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 ratedetermine_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:
- B2B with valid VAT number → Reverse charge (0%)
- Domestic sale → Domestic VAT
- Cross-border + OSS registered → Destination VAT
- 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_regimefield to invoice (domestic, oss, reverse_charge, origin) - Add
destination_countryfield - 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_datenotes
PurchaseOrderItem:
purchase_order_id(FK)product_id(FK)quantity_orderedquantity_receivedunit_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 POadd_item(po_id, product_id, quantity)- Add line itemreceive_items(po_id, items)- Mark items received, update inventoryget_incoming_stock(store_id)- Summary of pending stocklist_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 CSVexport_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.pymodels/database/invoice.pymodels/database/eu_vat_rates.pymodels/database/store_subscription.pymodels/database/purchase_order.py
Services to Create
app/services/invoice_service.pyapp/services/invoice_pdf_service.pyapp/services/vat_service.pyapp/services/tier_limits_service.pyapp/services/purchase_order_service.pyapp/services/customer_export_service.pyapp/services/accounting_export_service.py
Templates to Create
app/templates/invoices/invoice.htmlapp/templates/store/purchase-orders.html
Existing Files to Modify
models/database/__init__.pymodels/database/store.pyapp/services/order_service.pyapp/templates/store/settings.htmlapp/templates/store/order-detail.htmlapp/templates/store/inventory.htmlapp/templates/store/customers.htmlrequirements.txt
Dependencies to Add
# requirements.txt
weasyprint>=60.0
Note: WeasyPrint requires system dependencies:
libpango-1.0-0libpangocairo-1.0-0libgdk-pixbuf2.0-0
Add to Dockerfile if deploying via Docker.
Testing Strategy
Unit Tests
tests/unit/services/test_invoice_service.pytests/unit/services/test_vat_service.pytests/unit/services/test_tier_limits_service.pytests/unit/services/test_purchase_order_service.py
Integration Tests
tests/integration/api/v1/store/test_invoices.pytests/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