# 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