- Add invoice exceptions module with proper exception hierarchy
- Replace HTTPException with service-layer exceptions in invoice API
- Add InvoicePDFGeneratedResponse and InvoiceStatsResponse Pydantic models
- Replace db.commit() with db.flush() in services for proper transaction control
- Update invoice service to use exceptions from app/exceptions/invoice.py
All 14 errors and 14 warnings are now resolved. Validation passes with
only INFO-level findings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 1 OMS implementation:
Invoicing:
- Add Invoice and VendorInvoiceSettings database models
- Full EU VAT support (27 countries, OSS, B2B reverse charge)
- Invoice PDF generation with WeasyPrint + Jinja2 templates
- Vendor invoice API endpoints for settings, creation, PDF download
Subscription Tiers:
- Add VendorSubscription model with 4 tiers (Essential/Professional/Business/Enterprise)
- Tier limit enforcement for orders, products, team members
- Feature gating based on subscription tier
- Automatic trial subscription creation for new vendors
- Integrate limit checks into order creation (direct and Letzshop sync)
Marketing:
- Update pricing documentation with 4-tier structure
- Revise back-office positioning strategy
- Update homepage with Veeqo-inspired Letzshop-focused messaging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change message exceptions (MessageAttachmentException,
InvalidConversationTypeException, InvalidRecipientTypeException)
to extend BusinessLogicException instead of ValidationException
which doesn't accept error_code parameter
- Update vendor letzshop API endpoints:
- Change sync_status query param to status in list_orders()
- Fix response mapping to use unified Order model properties
(external_order_id, external_shipment_id, status, etc.)
- Fix confirm_order() to get inventory unit IDs from order items
- Fix set_tracking() to use external_shipment_id
- Add order_date to test fixtures (required NOT NULL field)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment out links to pages not yet implemented:
- notifications-settings
- profile
- api-keys
These were causing 404 errors when clicked.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- messages.js: Add missing `error` property required by error_state macro
- platform-homepage.html: Use `<template x-if>` instead of `x-show` to
prevent Alpine from evaluating `page.template` when `page` is null
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The TPL-008 rule was only in the single-file validation path,
not in the full project validation. Added it to _validate_templates().
Fixed invalid block names:
- customers.html: page_scripts → extra_scripts
- notifications.html: page_scripts → extra_scripts
- test-vendors-users-migration.html: scripts → extra_scripts
- test-auth-flow.html: scripts → extra_scripts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix messages.html: change {% block page_scripts %} to {% block extra_scripts %}
(page_scripts doesn't exist in admin/base.html, causing JS not to load)
- Add TPL-008 architecture rule to catch invalid template block names
This prevents silent failures where content in undefined blocks is ignored
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Nested {# ... #} comments inside the docstring were breaking
the outer comment block, causing 'dropdown' is undefined error
when rendering the components page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create action_dropdown macro in dropdowns.html supporting:
- Loading/disabled state via loading_var parameter
- Custom loading label
- Icon support
- Primary/secondary variants
- Update code quality dashboard to use new macro
- Add Dropdowns section to components page with examples:
- Basic dropdown
- Action dropdown with loading state
- Context menu (3-dot)
- Variant showcase (primary, secondary, ghost)
Architecture validation now passes with 0 errors and 0 warnings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move database operations from API to service layer:
- Add create_pending_scan() method to code_quality_service
- Add get_running_scans() method to code_quality_service
- Update API to use service methods instead of direct db queries
- Replace inline SVG spinner with $icon('spinner', ...) helper
- Add comment documenting custom dropdown exception
Validation now passes with 0 errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Minor improvements to admin notification service
- Add unit tests for admin notification service
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Refactor messaging API endpoints for admin, shop, and vendor
- Add message-specific exceptions (ConversationNotFoundException, etc.)
- Enhance messaging service with additional helper methods
- Add comprehensive test fixtures for messaging
- Add integration tests for admin and vendor messaging APIs
- Add unit tests for messaging and attachment services
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create reusable pagination macro in shared/macros/pagination.html
- Update customers template to use shared pagination macro
- Reduces code duplication across admin templates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The page_header macro doesn't accept a 'buttons' parameter.
Changed to page_header_flex with caller block for custom button.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add validator_type field to scans and violations (architecture,
security, performance)
- Create security validator with SEC-xxx rules
- Create performance validator with PERF-xxx rules
- Add base validator class for shared functionality
- Add validate_all.py script to run all validators
- Update code quality service with validator type filtering
- Add validator type tabs to dashboard UI
- Add validator type filter to violations list
- Update stats response with per-validator breakdown
- Add security and performance rules documentation
- Add chat-bubble icons to icon library
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add status fields to ArchitectureScan model (status, started_at,
completed_at, error_message, progress_message)
- Create database migration for new status fields
- Create background task function execute_code_quality_scan()
- Update API to return 202 with job IDs and support polling
- Add code quality scans to unified BackgroundTasksService
- Integrate scans into background tasks API and page
- Implement frontend polling with 3-second interval
- Add progress banner showing scan status
- Users can navigate away while scans run in background
- Document the implementation in architecture docs
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add job cancellation and retry functionality
- Improve jobs table with better status display
- Add background task improvements
- Update Letzshop order service
- Update documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add admin customers API endpoints
- Add AdminCustomerService for customer operations
- Enhance customers.html template with management features
- Add customers.js Alpine component
- Add customer list schemas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace browser alert with proper modal for job details view
- Show job info, status, records, timestamps in modal
- Display export file details (languages, file sizes) for export jobs
- Include error_details in API response for export and order_sync jobs
- Add selectedJobDetails state and showJobDetailsModal flag
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously export jobs showed "3/23" (languages/products) which was confusing.
Now shows "3/3" (files succeeded / files processed) for consistency.
- Updated log_export to track files_processed/succeeded/failed
- Products count stored in error_details for reference
- Updated documentation to explain records column meaning per job type
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Export operations now create LetzshopSyncLog entries with type 'product_export'
- Added log_export method to LetzshopExportService (follows architecture rules)
- Updated list_letzshop_jobs to include export jobs
- Added export filter option back to jobs dropdown
- Export jobs display with blue badge and cloud-upload icon
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1. Products tab now shows Letzshop marketplace products instead of vendor products
- Uses /admin/products endpoint with marketplace=Letzshop filter
- Fixed field names (image_link, price_numeric, sku vs vendor_sku)
- Search now works with title, GTIN, SKU, brand
2. Jobs section moved to a separate tab
- New "Jobs" tab between Exceptions and Settings
- Tab watcher reloads data when switching tabs
- Updated filter dropdown (removed export, added historical_import)
3. Product stats endpoint now accepts marketplace and vendor_name filters
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add API-002 architecture rule preventing Pydantic imports in API endpoints
- Move inline Pydantic models from vendor_products.py to models/schema/vendor_product.py
- Update vendor_products.py to import schemas from proper location
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Follows architecture rule: Pydantic schemas belong in models/schema/
- Moved LetzshopExportRequest to models/schema/vendor.py
- Added LetzshopExportFileInfo and LetzshopExportResponse schemas
- Updated API endpoint to use proper response_model
- Removed inline BaseModel import from API file
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Products Tab Changes:
- Converted to product listing page similar to /admin/marketplace-products
- Added Import/Export buttons in header
- Added product stats cards (total, active, inactive, last sync)
- Added search and filter functionality
- Added product table with pagination
- Import modal for single URL or all languages
Settings Tab Changes:
- Moved batch size setting from products tab
- Moved include inactive checkbox from products tab
- Added export behavior info box
Export Changes:
- New POST endpoint exports all languages (FR, DE, EN)
- CSV files written to exports/letzshop/{vendor_code}/ for scheduler pickup
- Letzshop scheduler can fetch files from this location
API Changes:
- Added vendor_id filter to /admin/vendor-products/stats endpoint
- Added POST /admin/vendors/{id}/export/letzshop for folder export
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Renamed supplier_cost to cost in VendorProductDetail schema
- Added tax_rate_percent, net_price, vat_amount, profit, profit_margin_percent
- Updated vendor_product_service to use new property names
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Money Handling Architecture:
- Store all monetary values as integer cents (€105.91 = 10591)
- Add app/utils/money.py with Money class and conversion helpers
- Add static/shared/js/money.js for frontend formatting
- Update all database models to use _cents columns (Product, Order, etc.)
- Update CSV processor to convert prices to cents on import
- Add Alembic migration for Float to Integer conversion
- Create .architecture-rules/money.yaml with 7 validation rules
- Add docs/architecture/money-handling.md documentation
Order Details Page Fixes:
- Fix customer name showing 'undefined undefined' - use flat field names
- Fix vendor info empty - add vendor_name/vendor_code to OrderDetailResponse
- Fix shipping address using wrong nested object structure
- Enrich order detail API response with vendor info
Vendor Filter Persistence Fixes:
- Fix orders.js: restoreSavedVendor now sets selectedVendor and filters
- Fix orders.js: init() only loads orders if no saved vendor to restore
- Fix marketplace-letzshop.js: restoreSavedVendor calls selectVendor()
- Fix marketplace-letzshop.js: clearVendorSelection clears TomSelect dropdown
- Align vendor selector placeholder text between pages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds a new "Exceptions" tab to the Letzshop marketplace page for managing
unmatched product exceptions from order imports.
Features:
- Exception list with search and status filtering
- Stats cards showing pending/resolved/ignored counts
- Resolve modal with product search
- Bulk resolve option for same GTIN
- Ignore functionality
Files:
- New: letzshop-exceptions-tab.html partial template
- Updated: marketplace-letzshop.html (tab button, panel, resolve modal)
- Updated: marketplace-letzshop.js (exception state, methods)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Items like vouchers may have no GTIN at all. Previously, the placeholder
product was only created when there were missing GTINs, causing a NOT NULL
constraint violation for items with gtin=None.
Now we also check for items without GTIN and create a placeholder for them.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Orders were being flushed but only committed every 10 orders via the
progress callback. With slow imports (~1.5 min/order), no commits
happened before the first 10 orders, causing data loss if the import
failed or was interrupted.
Changes:
- Add db.commit() after each successful order creation
- Add db.rollback() on order creation failure to prevent corrupt state
- Add db.commit() after order updates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
func.case() is not valid SQLAlchemy - case() must be imported directly
from sqlalchemy. This was causing TypeError on /api/v1/admin/background-tasks/tasks/stats.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Historical import jobs were not appearing in the recent jobs list because
list_letzshop_jobs() only queried marketplace_import_jobs and letzshop_sync_logs.
Changes:
- Add LetzshopHistoricalImportJob query to list_letzshop_jobs()
- Add current_phase and error_message fields to LetzshopJobItem schema
- Fixed stuck job 8 (marked as failed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces the "fail on missing product" behavior with graceful handling:
- Orders import even when products aren't found by GTIN
- Unmatched items link to a per-vendor placeholder product
- Exceptions tracked in order_item_exceptions table for QC resolution
- Order confirmation blocked until exceptions are resolved
- Auto-matching when products are imported via catalog sync
New files:
- OrderItemException model and migration
- OrderItemExceptionService with CRUD and resolution logic
- Admin and vendor API endpoints for exception management
- Domain exceptions for error handling
Modified:
- OrderItem: added needs_product_match flag and exception relationship
- OrderService: graceful handling with placeholder products
- MarketplaceProductService: auto-match on product import
- Letzshop confirm endpoints: blocking check for unresolved exceptions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Restructured create_letzshop_order to follow the "validate first, then write"
architecture pattern:
Phase 1 (Read-only validation):
- Check if order already exists
- Parse all inventory units and collect GTINs
- Batch query all products by GTIN (single query instead of N queries)
- Validate all products exist - raise ValidationException BEFORE any writes
Phase 2 (Database writes):
- Only after all validation passes, create customer, order, and items
This ensures if validation fails, no database modifications happen, so the
endpoint/task simply doesn't commit - no rollback needed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When create_letzshop_order raises an exception (e.g., product not found by GTIN)
after flushing the order to the database, the session is left in an inconsistent
state. Without rollback, subsequent database operations fail or hang, causing
the import to get stuck at "0 processed...".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the missing method to OrderService that was being called
from the admin orders API endpoint.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update all frontend templates and JavaScript to use new unified Order model:
- Orders tab: use status field, processing/cancelled values, items array
- Order detail: use snapshot fields, items array, tracking_provider
- JavaScript: update API params (status vs sync_status), orderStats fields
- Tracking modal: use tracking_provider instead of tracking_carrier
- Order items modal: use items array with item_state field
All status mappings:
- pending → pending (unconfirmed)
- processing → confirmed (at least one item available)
- cancelled → declined (all items unavailable)
- shipped → shipped (with tracking)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update API endpoints and schemas to use the unified Order model:
- Update Letzshop order schemas with OrderItem support
- Update API responses to use new field names (external_*, status, etc.)
- Update confirm/reject endpoints to use OrderItem.external_item_id
- Update Letzshop order service for unified Order model queries
- Update documentation to reflect completed implementation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update implementation guide with unified order approach
- Add mkdocs navigation entry
- Add background task for order sync
- Add debug script for historical imports
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Letzshop order detail page template
- Update orders list template
- Update Letzshop orders tab with improved UI
- Add JavaScript for order confirmation flow
Note: Frontend needs alignment with new unified order schema.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>