feat: integer cents money handling, order page fixes, and vendor filter persistence

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>
This commit is contained in:
2025-12-20 20:33:48 +01:00
parent 7f0d32c18d
commit a19c84ea4e
56 changed files with 6155 additions and 447 deletions

View File

@@ -581,7 +581,7 @@ class TestLetzshopOrderService:
"id": "order_123",
"number": "R123456",
"email": "test@example.com",
"total": 29.99,
"total": "29.99 EUR",
"locale": "fr",
"shipAddress": {
"firstName": "Jean",
@@ -598,8 +598,8 @@ class TestLetzshopOrderService:
order = service.create_order(test_vendor.id, shipment_data)
assert order.customer_locale == "fr"
assert order.shipping_country_iso == "LU"
assert order.billing_country_iso == "FR"
assert order.ship_country_iso == "LU" # Correct attribute name
assert order.bill_country_iso == "FR" # Correct attribute name
def test_create_order_extracts_ean(self, db, test_vendor):
"""Test that create_order extracts EAN from tradeId."""
@@ -640,14 +640,15 @@ class TestLetzshopOrderService:
order = service.create_order(test_vendor.id, shipment_data)
assert len(order.inventory_units) == 1
unit = order.inventory_units[0]
assert unit["ean"] == "0889698273022"
assert unit["ean_type"] == "gtin13"
assert unit["sku"] == "SKU123"
assert unit["mpn"] == "MPN456"
assert unit["product_name"] == "Test Product"
assert unit["price"] == 19.99
# Check order items (unified model uses items relationship)
assert len(order.items) == 1
item = order.items[0]
assert item.gtin == "0889698273022"
assert item.gtin_type == "gtin13"
assert item.product_sku == "SKU123"
assert item.product_name == "Test Product"
# Price is stored in cents (19.99 EUR = 1999 cents)
assert item.unit_price_cents == 1999
def test_import_historical_shipments_deduplication(self, db, test_vendor):
"""Test that historical import deduplicates existing orders."""