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:
@@ -18,6 +18,7 @@ import requests
|
||||
from sqlalchemy import literal
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.utils.money import euros_to_cents
|
||||
from models.database.marketplace_import_job import MarketplaceImportError
|
||||
from models.database.marketplace_product import MarketplaceProduct
|
||||
from models.database.marketplace_product_translation import (
|
||||
@@ -154,8 +155,18 @@ class CSVProcessor:
|
||||
logger.info(f"Normalized columns: {list(df.columns)}")
|
||||
return df
|
||||
|
||||
def _parse_price_to_numeric(self, price_str: str | None) -> float | None:
|
||||
"""Parse price string like '19.99 EUR' to float."""
|
||||
def _parse_price_to_cents(self, price_str: str | None) -> int | None:
|
||||
"""Parse price string like '19.99 EUR' to integer cents.
|
||||
|
||||
Uses the money utility for precise conversion.
|
||||
Example: '19.99 EUR' -> 1999
|
||||
|
||||
Args:
|
||||
price_str: Price string with optional currency
|
||||
|
||||
Returns:
|
||||
Price in integer cents, or None if parsing fails
|
||||
"""
|
||||
if not price_str:
|
||||
return None
|
||||
|
||||
@@ -164,8 +175,9 @@ class CSVProcessor:
|
||||
if numbers:
|
||||
num_str = numbers[0].replace(",", ".")
|
||||
try:
|
||||
return float(num_str)
|
||||
except ValueError:
|
||||
# Convert euros to cents using money utility
|
||||
return euros_to_cents(num_str)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
return None
|
||||
|
||||
@@ -185,10 +197,10 @@ class CSVProcessor:
|
||||
parsed_price, currency = self.price_processor.parse_price_currency(
|
||||
processed_data["price"]
|
||||
)
|
||||
# Store both raw price string and numeric value
|
||||
# Store both raw price string and numeric value in cents
|
||||
raw_price = processed_data["price"]
|
||||
processed_data["price"] = parsed_price
|
||||
processed_data["price_numeric"] = self._parse_price_to_numeric(raw_price)
|
||||
processed_data["price_cents"] = self._parse_price_to_cents(raw_price)
|
||||
processed_data["currency"] = currency
|
||||
|
||||
# Process sale_price
|
||||
@@ -198,7 +210,7 @@ class CSVProcessor:
|
||||
processed_data["sale_price"]
|
||||
)
|
||||
processed_data["sale_price"] = parsed_sale_price
|
||||
processed_data["sale_price_numeric"] = self._parse_price_to_numeric(
|
||||
processed_data["sale_price_cents"] = self._parse_price_to_cents(
|
||||
raw_sale_price
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user