# tests/unit/models/database/test_order.py """Unit tests for Order and OrderItem database models.""" from datetime import datetime, timezone import pytest from sqlalchemy.exc import IntegrityError from models.database.order import Order, OrderItem def create_order_with_snapshots( db, vendor, customer, customer_address, order_number, status="pending", subtotal=99.99, total_amount=99.99, **kwargs ): """Helper to create Order with required address snapshots.""" # Remove channel from kwargs if present (we set it explicitly) channel = kwargs.pop("channel", "direct") order = Order( vendor_id=vendor.id, customer_id=customer.id, order_number=order_number, status=status, channel=channel, subtotal=subtotal, total_amount=total_amount, currency="EUR", order_date=datetime.now(timezone.utc), # Customer snapshot customer_first_name=customer.first_name, customer_last_name=customer.last_name, customer_email=customer.email, # Shipping address snapshot ship_first_name=customer_address.first_name, ship_last_name=customer_address.last_name, ship_address_line_1=customer_address.address_line_1, ship_city=customer_address.city, ship_postal_code=customer_address.postal_code, ship_country_iso="LU", # Billing address snapshot bill_first_name=customer_address.first_name, bill_last_name=customer_address.last_name, bill_address_line_1=customer_address.address_line_1, bill_city=customer_address.city, bill_postal_code=customer_address.postal_code, bill_country_iso="LU", **kwargs ) db.add(order) db.commit() db.refresh(order) return order @pytest.mark.unit @pytest.mark.database class TestOrderModel: """Test Order model.""" def test_order_creation( self, db, test_vendor, test_customer, test_customer_address ): """Test Order model with customer relationship.""" order = create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number="ORD-001", ) assert order.id is not None assert order.vendor_id == test_vendor.id assert order.customer_id == test_customer.id assert order.order_number == "ORD-001" assert order.status == "pending" assert float(order.total_amount) == 99.99 # Verify snapshots assert order.customer_first_name == test_customer.first_name assert order.ship_city == test_customer_address.city assert order.ship_country_iso == "LU" def test_order_number_uniqueness( self, db, test_vendor, test_customer, test_customer_address ): """Test order_number unique constraint.""" create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number="UNIQUE-ORD-001", ) # Duplicate order number should fail with pytest.raises(IntegrityError): create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number="UNIQUE-ORD-001", ) def test_order_status_values( self, db, test_vendor, test_customer, test_customer_address ): """Test Order with different status values.""" statuses = [ "pending", "processing", "shipped", "delivered", "cancelled", "refunded", ] for i, status in enumerate(statuses): order = create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number=f"STATUS-ORD-{i:03d}", status=status, ) assert order.status == status def test_order_amounts(self, db, test_vendor, test_customer, test_customer_address): """Test Order amount fields.""" order = create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number="AMOUNTS-ORD-001", subtotal=100.00, tax_amount=20.00, shipping_amount=10.00, discount_amount=5.00, total_amount=125.00, ) assert float(order.subtotal) == 100.00 assert float(order.tax_amount) == 20.00 assert float(order.shipping_amount) == 10.00 assert float(order.discount_amount) == 5.00 assert float(order.total_amount) == 125.00 def test_order_relationships( self, db, test_vendor, test_customer, test_customer_address ): """Test Order relationships.""" order = create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number="REL-ORD-001", ) assert order.vendor is not None assert order.customer is not None assert order.vendor.id == test_vendor.id assert order.customer.id == test_customer.id def test_order_channel_field( self, db, test_vendor, test_customer, test_customer_address ): """Test Order channel field for marketplace support.""" order = create_order_with_snapshots( db, test_vendor, test_customer, test_customer_address, order_number="CHANNEL-ORD-001", channel="letzshop", external_order_id="LS-12345", external_shipment_id="SHIP-67890", ) assert order.channel == "letzshop" assert order.external_order_id == "LS-12345" assert order.external_shipment_id == "SHIP-67890" @pytest.mark.unit @pytest.mark.database class TestOrderItemModel: """Test OrderItem model.""" def test_order_item_creation(self, db, test_order, test_product): """Test OrderItem model.""" # Get title from translation product_title = test_product.marketplace_product.get_title("en") order_item = OrderItem( order_id=test_order.id, product_id=test_product.id, product_name=product_title, product_sku=test_product.vendor_sku or "SKU001", quantity=2, unit_price=49.99, total_price=99.98, ) db.add(order_item) db.commit() db.refresh(order_item) assert order_item.id is not None assert order_item.order_id == test_order.id assert order_item.product_id == test_product.id assert order_item.quantity == 2 assert float(order_item.unit_price) == 49.99 assert float(order_item.total_price) == 99.98 def test_order_item_stores_product_snapshot(self, db, test_order, test_product): """Test OrderItem stores product name and SKU as snapshot.""" order_item = OrderItem( order_id=test_order.id, product_id=test_product.id, product_name="Snapshot Product Name", product_sku="SNAPSHOT-SKU-001", quantity=1, unit_price=25.00, total_price=25.00, ) db.add(order_item) db.commit() db.refresh(order_item) assert order_item.id is not None assert order_item.product_name == "Snapshot Product Name" assert order_item.product_sku == "SNAPSHOT-SKU-001" def test_order_item_relationships(self, db, test_order, test_product): """Test OrderItem relationships.""" order_item = OrderItem( order_id=test_order.id, product_id=test_product.id, product_name="Test Product", product_sku="SKU001", quantity=1, unit_price=50.00, total_price=50.00, ) db.add(order_item) db.commit() db.refresh(order_item) assert order_item.order is not None assert order_item.order.id == test_order.id def test_multiple_items_per_order(self, db, test_order, test_product): """Test multiple OrderItems can belong to same Order.""" # Create two order items for the same product (different quantities) item1 = OrderItem( order_id=test_order.id, product_id=test_product.id, product_name="Product - Size M", product_sku="SKU001-M", quantity=1, unit_price=25.00, total_price=25.00, ) item2 = OrderItem( order_id=test_order.id, product_id=test_product.id, product_name="Product - Size L", product_sku="SKU001-L", quantity=2, unit_price=30.00, total_price=60.00, ) db.add_all([item1, item2]) db.commit() assert item1.order_id == item2.order_id assert item1.id != item2.id assert item1.product_id == item2.product_id # Same product, different items def test_order_item_needs_product_match(self, db, test_order, test_product): """Test OrderItem needs_product_match flag for exceptions.""" order_item = OrderItem( order_id=test_order.id, product_id=test_product.id, product_name="Unmatched Product", product_sku="UNMATCHED-001", quantity=1, unit_price=50.00, total_price=50.00, needs_product_match=True, ) db.add(order_item) db.commit() db.refresh(order_item) assert order_item.needs_product_match is True # Resolve the match order_item.needs_product_match = False db.commit() db.refresh(order_item) assert order_item.needs_product_match is False