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>
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