vendor refactoring

This commit is contained in:
2025-10-05 19:49:03 +02:00
parent 0114b6c46e
commit f569995883
17 changed files with 121 additions and 121 deletions

View File

@@ -206,7 +206,7 @@ class AdminService:
raise AdminOperationException( raise AdminOperationException(
operation="toggle_vendor_status", operation="toggle_vendor_status",
reason="Database update failed", reason="Database update failed",
target_type="vendor ", target_type="vendor",
target_id=str(vendor_id) target_id=str(vendor_id)
) )

View File

@@ -15,15 +15,15 @@ class Product(Base, TimestampMixin):
vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False) vendor_id = Column(Integer, ForeignKey("vendors.id"), nullable=False)
marketplace_product_id = Column(Integer, ForeignKey("marketplace_products.id"), nullable=False) marketplace_product_id = Column(Integer, ForeignKey("marketplace_products.id"), nullable=False)
# Shop-specific overrides (can override the main product data) # Vendor-specific overrides (can override the main product data)
product_id = Column(String) # Shop's internal product ID product_id = Column(String) # Vendor's internal product ID
price = Column(Float) # Override main product price price = Column(Float) # Override main product price
sale_price = Column(Float) sale_price = Column(Float)
currency = Column(String) currency = Column(String)
availability = Column(String) # Override availability availability = Column(String) # Override availability
condition = Column(String) condition = Column(String)
# Shop-specific metadata # Vendor-specific metadata
is_featured = Column(Boolean, default=False) is_featured = Column(Boolean, default=False)
is_active = Column(Boolean, default=True) is_active = Column(Boolean, default=True)
display_order = Column(Integer, default=0) display_order = Column(Integer, default=0)

View File

@@ -21,7 +21,7 @@ class Stock(Base, TimestampMixin):
vendor_id = Column(Integer, ForeignKey("vendors.id")) # Optional: vendor -specific stock vendor_id = Column(Integer, ForeignKey("vendors.id")) # Optional: vendor -specific stock
# Relationships # Relationships
vendor = relationship("Shop") vendor = relationship("Vendor")
# Composite unique constraint to prevent duplicate GTIN-location combinations # Composite unique constraint to prevent duplicate GTIN-location combinations
__table_args__ = ( __table_args__ = (

View File

@@ -9,7 +9,7 @@ def test_marketplace_import_job(db, test_vendor, test_user):
"""Create a test marketplace import job""" """Create a test marketplace import job"""
job = MarketplaceImportJob( job = MarketplaceImportJob(
marketplace="amazon", marketplace="amazon",
vendor_name="Test Import Shop", vendor_name="Test Import Vendor",
status="completed", status="completed",
source_url="https://test-marketplace.example.com/import", source_url="https://test-marketplace.example.com/import",
vendor_id=test_vendor.id, vendor_id=test_vendor.id,
@@ -30,7 +30,7 @@ def create_test_marketplace_import_job(db, vendor_id, user_id, **kwargs):
"""Helper function to create MarketplaceImportJob with defaults""" """Helper function to create MarketplaceImportJob with defaults"""
defaults = { defaults = {
"marketplace": "test", "marketplace": "test",
"vendor_name": "Test Shop", "vendor_name": "Test Vendor",
"status": "pending", "status": "pending",
"source_url": "https://test.example.com/import", "source_url": "https://test.example.com/import",
"vendor_id": vendor_id, "vendor_id": vendor_id,

View File

@@ -41,7 +41,7 @@ def unique_product(db):
gtin=f"123456789{unique_id[:4]}", gtin=f"123456789{unique_id[:4]}",
availability="in stock", availability="in stock",
marketplace="Letzshop", marketplace="Letzshop",
vendor_name=f"UniqueShop_{unique_id}", vendor_name=f"UniqueVendor_{unique_id}",
google_product_category=f"UniqueCategory_{unique_id}", google_product_category=f"UniqueCategory_{unique_id}",
) )
db.add(marketplace_product) db.add(marketplace_product)
@@ -65,7 +65,7 @@ def multiple_products(db):
currency="EUR", currency="EUR",
brand=f"MultiBrand_{i % 3}", # Create 3 different brands brand=f"MultiBrand_{i % 3}", # Create 3 different brands
marketplace=f"MultiMarket_{i % 2}", # Create 2 different marketplaces marketplace=f"MultiMarket_{i % 2}", # Create 2 different marketplaces
vendor_name=f"MultiShop_{i}", vendor_name=f"MultiVendor_{i}",
google_product_category=f"MultiCategory_{i % 2}", # Create 2 different categories google_product_category=f"MultiCategory_{i % 2}", # Create 2 different categories
gtin=f"1234567890{i}{unique_id[:2]}", gtin=f"1234567890{i}{unique_id[:2]}",
) )

View File

@@ -344,7 +344,7 @@ class TestMarketplaceImportJobAPI:
import_data = { import_data = {
"url": "https://example.com/products.csv", "url": "https://example.com/products.csv",
"marketplace": "TestMarket", "marketplace": "TestMarket",
"vendor_code": "TEST_SHOP", "vendor_code": "TEST_VENDOR",
} }
response = client.post("/api/v1/marketplace/import-product", json=import_data) response = client.post("/api/v1/marketplace/import-product", json=import_data)

View File

@@ -70,13 +70,13 @@ class TestExportFunctionality:
unique_suffix = str(uuid.uuid4())[:8] unique_suffix = str(uuid.uuid4())[:8]
products = [ products = [
MarketplaceProduct( MarketplaceProduct(
marketplace_product_id=f"SHOP1_{unique_suffix}", marketplace_product_id=f"VENDOR1_{unique_suffix}",
title=f"Shop1 MarketplaceProduct {unique_suffix}", title=f"Vendor1 MarketplaceProduct {unique_suffix}",
vendor_name="TestVendor1" vendor_name="TestVendor1"
), ),
MarketplaceProduct( MarketplaceProduct(
marketplace_product_id=f"SHOP2_{unique_suffix}", marketplace_product_id=f"VENDOR2_{unique_suffix}",
title=f"Shop2 MarketplaceProduct {unique_suffix}", title=f"Vendor2 MarketplaceProduct {unique_suffix}",
vendor_name="TestVendor2" vendor_name="TestVendor2"
), ),
] ]
@@ -90,8 +90,8 @@ class TestExportFunctionality:
assert response.status_code == 200 assert response.status_code == 200
csv_content = response.content.decode("utf-8") csv_content = response.content.decode("utf-8")
assert f"SHOP1_{unique_suffix}" in csv_content assert f"VENDOR1_{unique_suffix}" in csv_content
assert f"SHOP2_{unique_suffix}" not in csv_content # Should be filtered out assert f"VENDOR2_{unique_suffix}" not in csv_content # Should be filtered out
def test_csv_export_with_combined_filters_success(self, client, auth_headers, db): def test_csv_export_with_combined_filters_success(self, client, auth_headers, db):
"""Test CSV export with combined marketplace and vendor filters successfully""" """Test CSV export with combined marketplace and vendor filters successfully"""
@@ -113,7 +113,7 @@ class TestExportFunctionality:
marketplace_product_id=f"COMBO3_{unique_suffix}", marketplace_product_id=f"COMBO3_{unique_suffix}",
title=f"Combo MarketplaceProduct 3 {unique_suffix}", title=f"Combo MarketplaceProduct 3 {unique_suffix}",
marketplace="Amazon", marketplace="Amazon",
vendor_name="OtherShop" vendor_name="OtherVendor"
), ),
] ]

View File

@@ -191,7 +191,7 @@ class TestPagination:
vendors =[] vendors =[]
for i in range(15): for i in range(15):
vendor = Vendor( vendor = Vendor(
vendor_code=f"PAGESHOP{i:03d}_{unique_suffix}", vendor_code=f"PAGEVENDOR{i:03d}_{unique_suffix}",
vendor_name=f"Pagination Vendor {i}", vendor_name=f"Pagination Vendor {i}",
owner_id=test_user.id, owner_id=test_user.id,
is_active=True, is_active=True,
@@ -203,7 +203,7 @@ class TestPagination:
# Test first page (assuming admin endpoint exists) # Test first page (assuming admin endpoint exists)
response = client.get( response = client.get(
"/api/v1/vendor ?limit=5&skip=0", headers=admin_headers "/api/v1/vendor?limit=5&skip=0", headers=admin_headers
) )
assert response.status_code == 200 assert response.status_code == 200
data = response.json() data = response.json()

View File

@@ -15,7 +15,7 @@ class TestVendorsAPI:
"description": "A new test vendor ", "description": "A new test vendor ",
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
assert response.status_code == 200 assert response.status_code == 200
data = response.json() data = response.json()
@@ -31,7 +31,7 @@ class TestVendorsAPI:
"description": "Different description", "description": "Different description",
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
assert response.status_code == 409 assert response.status_code == 409
data = response.json() data = response.json()
@@ -47,7 +47,7 @@ class TestVendorsAPI:
"description": "Missing vendor code", "description": "Missing vendor code",
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
assert response.status_code == 422 assert response.status_code == 422
data = response.json() data = response.json()
@@ -64,7 +64,7 @@ class TestVendorsAPI:
"description": "Vendor with empty name", "description": "Vendor with empty name",
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
assert response.status_code == 422 assert response.status_code == 422
data = response.json() data = response.json()
@@ -87,7 +87,7 @@ class TestVendorsAPI:
def test_get_vendors_success(self, client, auth_headers, test_vendor): def test_get_vendors_success(self, client, auth_headers, test_vendor):
"""Test getting vendors list successfully""" """Test getting vendors list successfully"""
response = client.get("/api/v1/vendor ", headers=auth_headers) response = client.get("/api/v1/vendor", headers=auth_headers)
assert response.status_code == 200 assert response.status_code == 200
data = response.json() data = response.json()
@@ -101,21 +101,21 @@ class TestVendorsAPI:
def test_get_vendors_with_filters(self, client, auth_headers, test_vendor): def test_get_vendors_with_filters(self, client, auth_headers, test_vendor):
"""Test getting vendors with filtering options""" """Test getting vendors with filtering options"""
# Test active_only filter # Test active_only filter
response = client.get("/api/v1/vendor ?active_only=true", headers=auth_headers) response = client.get("/api/v1/vendor?active_only=true", headers=auth_headers)
assert response.status_code == 200 assert response.status_code == 200
data = response.json() data = response.json()
for vendor in data["vendors"]: for vendor in data["vendors"]:
assert vendor ["is_active"] is True assert vendor ["is_active"] is True
# Test verified_only filter # Test verified_only filter
response = client.get("/api/v1/vendor ?verified_only=true", headers=auth_headers) response = client.get("/api/v1/vendor?verified_only=true", headers=auth_headers)
assert response.status_code == 200 assert response.status_code == 200
# Response should only contain verified vendors # Response should only contain verified vendors
def test_get_vendor_by_code_success(self, client, auth_headers, test_vendor): def test_get_vendor_by_code_success(self, client, auth_headers, test_vendor):
"""Test getting specific vendor successfully""" """Test getting specific vendor successfully"""
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}", headers=auth_headers f"/api/v1/vendor/{test_vendor.vendor_code}", headers=auth_headers
) )
assert response.status_code == 200 assert response.status_code == 200
@@ -125,7 +125,7 @@ class TestVendorsAPI:
def test_get_vendor_by_code_not_found(self, client, auth_headers): def test_get_vendor_by_code_not_found(self, client, auth_headers):
"""Test getting nonexistent vendor returns VendorNotFoundException""" """Test getting nonexistent vendor returns VendorNotFoundException"""
response = client.get("/api/v1/vendor /NONEXISTENT", headers=auth_headers) response = client.get("/api/v1/vendor/NONEXISTENT", headers=auth_headers)
assert response.status_code == 404 assert response.status_code == 404
data = response.json() data = response.json()
@@ -144,7 +144,7 @@ class TestVendorsAPI:
db.commit() db.commit()
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}", headers=auth_headers f"/api/v1/vendor/{test_vendor.vendor_code}", headers=auth_headers
) )
assert response.status_code == 403 assert response.status_code == 403
@@ -158,7 +158,7 @@ class TestVendorsAPI:
"""Test accessing inactive vendor owned by another user returns UnauthorizedVendorAccessException""" """Test accessing inactive vendor owned by another user returns UnauthorizedVendorAccessException"""
# inactive_vendor fixture already creates an unverified, inactive vendor owned by other_user # inactive_vendor fixture already creates an unverified, inactive vendor owned by other_user
response = client.get( response = client.get(
f"/api/v1/vendor /{inactive_vendor.vendor_code}", headers=auth_headers f"/api/v1/vendor/{inactive_vendor.vendor_code}", headers=auth_headers
) )
assert response.status_code == 403 assert response.status_code == 403
@@ -173,7 +173,7 @@ class TestVendorsAPI:
# verified_vendor fixture creates a verified, active vendor owned by other_user # verified_vendor fixture creates a verified, active vendor owned by other_user
# This should allow public access per your business logic # This should allow public access per your business logic
response = client.get( response = client.get(
f"/api/v1/vendor /{verified_vendor.vendor_code}", headers=auth_headers f"/api/v1/vendor/{verified_vendor.vendor_code}", headers=auth_headers
) )
assert response.status_code == 200 assert response.status_code == 200
@@ -191,7 +191,7 @@ class TestVendorsAPI:
} }
response = client.post( response = client.post(
f"/api/v1/vendor /{test_vendor.vendor_code}/products", f"/api/v1/vendor/{test_vendor.vendor_code}/products",
headers=auth_headers, headers=auth_headers,
json=product_data json=product_data
) )
@@ -221,7 +221,7 @@ class TestVendorsAPI:
} }
response = client.post( response = client.post(
f"/api/v1/vendor /{test_vendor.vendor_code}/products", f"/api/v1/vendor/{test_vendor.vendor_code}/products",
headers=auth_headers, headers=auth_headers,
json=product_data json=product_data
) )
@@ -241,7 +241,7 @@ class TestVendorsAPI:
} }
response = client.post( response = client.post(
f"/api/v1/vendor /{test_vendor.vendor_code}/products", f"/api/v1/vendor/{test_vendor.vendor_code}/products",
headers=auth_headers, headers=auth_headers,
json=product_data json=product_data
) )
@@ -255,7 +255,7 @@ class TestVendorsAPI:
def test_get_products_success(self, client, auth_headers, test_vendor, test_product): def test_get_products_success(self, client, auth_headers, test_vendor, test_product):
"""Test getting vendor products successfully""" """Test getting vendor products successfully"""
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}/products", f"/api/v1/vendor/{test_vendor.vendor_code}/products",
headers=auth_headers headers=auth_headers
) )
@@ -263,21 +263,21 @@ class TestVendorsAPI:
data = response.json() data = response.json()
assert data["total"] >= 1 assert data["total"] >= 1
assert len(data["products"]) >= 1 assert len(data["products"]) >= 1
assert "vendor " in data assert "vendor" in data
assert data["vendor "]["vendor_code"] == test_vendor.vendor_code assert data["vendor"]["vendor_code"] == test_vendor.vendor_code
def test_get_products_with_filters(self, client, auth_headers, test_vendor): def test_get_products_with_filters(self, client, auth_headers, test_vendor):
"""Test getting vendor products with filtering""" """Test getting vendor products with filtering"""
# Test active_only filter # Test active_only filter
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}/products?active_only=true", f"/api/v1/vendor/{test_vendor.vendor_code}/products?active_only=true",
headers=auth_headers headers=auth_headers
) )
assert response.status_code == 200 assert response.status_code == 200
# Test featured_only filter # Test featured_only filter
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}/products?featured_only=true", f"/api/v1/vendor/{test_vendor.vendor_code}/products?featured_only=true",
headers=auth_headers headers=auth_headers
) )
assert response.status_code == 200 assert response.status_code == 200
@@ -285,7 +285,7 @@ class TestVendorsAPI:
def test_get_products_from_nonexistent_vendor_not_found(self, client, auth_headers): def test_get_products_from_nonexistent_vendor_not_found(self, client, auth_headers):
"""Test getting products from nonexistent vendor returns VendorNotFoundException""" """Test getting products from nonexistent vendor returns VendorNotFoundException"""
response = client.get( response = client.get(
"/api/v1/vendor /NONEXISTENT/products", "/api/v1/vendor/NONEXISTENT/products",
headers=auth_headers headers=auth_headers
) )
@@ -303,7 +303,7 @@ class TestVendorsAPI:
# Depending on your business logic, this might return an error # Depending on your business logic, this might return an error
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}", headers=auth_headers f"/api/v1/vendor/{test_vendor.vendor_code}", headers=auth_headers
) )
# If your service enforces active vendor requirement # If your service enforces active vendor requirement
@@ -326,7 +326,7 @@ class TestVendorsAPI:
} }
response = client.post( response = client.post(
f"/api/v1/vendor /{test_vendor.vendor_code}/products", f"/api/v1/vendor/{test_vendor.vendor_code}/products",
headers=auth_headers, headers=auth_headers,
json=product_data json=product_data
) )
@@ -340,7 +340,7 @@ class TestVendorsAPI:
def test_get_vendor_without_auth_returns_invalid_token(self, client): def test_get_vendor_without_auth_returns_invalid_token(self, client):
"""Test that vendor endpoints require authentication returns InvalidTokenException""" """Test that vendor endpoints require authentication returns InvalidTokenException"""
response = client.get("/api/v1/vendor ") response = client.get("/api/v1/vendor")
assert response.status_code == 401 assert response.status_code == 401
data = response.json() data = response.json()
@@ -350,19 +350,19 @@ class TestVendorsAPI:
def test_pagination_validation_errors(self, client, auth_headers): def test_pagination_validation_errors(self, client, auth_headers):
"""Test pagination parameter validation""" """Test pagination parameter validation"""
# Test negative skip # Test negative skip
response = client.get("/api/v1/vendor ?skip=-1", headers=auth_headers) response = client.get("/api/v1/vendor?skip=-1", headers=auth_headers)
assert response.status_code == 422 assert response.status_code == 422
data = response.json() data = response.json()
assert data["error_code"] == "VALIDATION_ERROR" assert data["error_code"] == "VALIDATION_ERROR"
# Test zero limit # Test zero limit
response = client.get("/api/v1/vendor ?limit=0", headers=auth_headers) response = client.get("/api/v1/vendor?limit=0", headers=auth_headers)
assert response.status_code == 422 assert response.status_code == 422
data = response.json() data = response.json()
assert data["error_code"] == "VALIDATION_ERROR" assert data["error_code"] == "VALIDATION_ERROR"
# Test excessive limit # Test excessive limit
response = client.get("/api/v1/vendor ?limit=10000", headers=auth_headers) response = client.get("/api/v1/vendor?limit=10000", headers=auth_headers)
assert response.status_code == 422 assert response.status_code == 422
data = response.json() data = response.json()
assert data["error_code"] == "VALIDATION_ERROR" assert data["error_code"] == "VALIDATION_ERROR"
@@ -370,7 +370,7 @@ class TestVendorsAPI:
def test_exception_structure_consistency(self, client, auth_headers): def test_exception_structure_consistency(self, client, auth_headers):
"""Test that all vendor exceptions follow the consistent LetzShopException structure""" """Test that all vendor exceptions follow the consistent LetzShopException structure"""
# Test with a known error case # Test with a known error case
response = client.get("/api/v1/vendor /NONEXISTENT", headers=auth_headers) response = client.get("/api/v1/vendor/NONEXISTENT", headers=auth_headers)
assert response.status_code == 404 assert response.status_code == 404
data = response.json() data = response.json()

View File

@@ -13,7 +13,7 @@ class TestAuthentication:
"/api/v1/admin/vendors", "/api/v1/admin/vendors",
"/api/v1/marketplace/import-jobs", "/api/v1/marketplace/import-jobs",
"/api/v1/marketplace/product", "/api/v1/marketplace/product",
"/api/v1/vendor ", "/api/v1/vendor",
"/api/v1/stats", "/api/v1/stats",
"/api/v1/stock", "/api/v1/stock",
] ]

View File

@@ -42,7 +42,7 @@ class TestAuthorization:
"""Test that users can only access their own vendors""" """Test that users can only access their own vendors"""
# Test accessing own vendor (should work) # Test accessing own vendor (should work)
response = client.get( response = client.get(
f"/api/v1/vendor /{test_vendor.vendor_code}", headers=auth_headers f"/api/v1/vendor/{test_vendor.vendor_code}", headers=auth_headers
) )
# Response depends on your implementation - could be 200 or 404 if vendor doesn't belong to user # Response depends on your implementation - could be 200 or 404 if vendor doesn't belong to user

View File

@@ -19,7 +19,7 @@ class TestBackgroundTasks:
job = MarketplaceImportJob( job = MarketplaceImportJob(
status="pending", status="pending",
source_url="http://example.com/test.csv", source_url="http://example.com/test.csv",
vendor_name="TESTSHOP", vendor_name="TESTVENDOR",
marketplace="TestMarket", marketplace="TestMarket",
vendor_id=test_vendor.id, vendor_id=test_vendor.id,
user_id=test_user.id, user_id=test_user.id,
@@ -47,7 +47,7 @@ class TestBackgroundTasks:
# Run background task # Run background task
await process_marketplace_import( await process_marketplace_import(
job_id, "http://example.com/test.csv", "TestMarket", "TESTSHOP", 1000 job_id, "http://example.com/test.csv", "TestMarket", "TESTVENDOR", 1000
) )
# Re-query the job using the stored ID # Re-query the job using the stored ID
@@ -73,7 +73,7 @@ class TestBackgroundTasks:
job = MarketplaceImportJob( job = MarketplaceImportJob(
status="pending", status="pending",
source_url="http://example.com/test.csv", source_url="http://example.com/test.csv",
vendor_name="TESTSHOP", vendor_name="TESTVENDOR",
marketplace="TestMarket", marketplace="TestMarket",
vendor_id=test_vendor.id, vendor_id=test_vendor.id,
user_id=test_user.id, user_id=test_user.id,
@@ -102,7 +102,7 @@ class TestBackgroundTasks:
job_id, job_id,
"http://example.com/test.csv", "http://example.com/test.csv",
"TestMarket", "TestMarket",
"TESTSHOP", "TESTVENDOR",
1000, 1000,
) )
except Exception: except Exception:
@@ -142,7 +142,7 @@ class TestBackgroundTasks:
999, # Non-existent job ID 999, # Non-existent job ID
"http://example.com/test.csv", "http://example.com/test.csv",
"TestMarket", "TestMarket",
"TESTSHOP", "TESTVENDOR",
1000, 1000,
) )
@@ -157,7 +157,7 @@ class TestBackgroundTasks:
job = MarketplaceImportJob( job = MarketplaceImportJob(
status="pending", status="pending",
source_url="http://example.com/test.csv", source_url="http://example.com/test.csv",
vendor_name="TESTSHOP", vendor_name="TESTVENDOR",
marketplace="TestMarket", marketplace="TestMarket",
vendor_id=test_vendor.id, vendor_id=test_vendor.id,
user_id=test_user.id, user_id=test_user.id,
@@ -185,7 +185,7 @@ class TestBackgroundTasks:
# Run background task # Run background task
await process_marketplace_import( await process_marketplace_import(
job_id, "http://example.com/test.csv", "TestMarket", "TESTSHOP", 1000 job_id, "http://example.com/test.csv", "TestMarket", "TESTVENDOR", 1000
) )
# Re-query the job using the stored ID # Re-query the job using the stored ID

View File

@@ -64,21 +64,21 @@ class TestIntegrationFlows:
"""Test vendor creation and product management workflow""" """Test vendor creation and product management workflow"""
# 1. Create a vendor # 1. Create a vendor
vendor_data = { vendor_data = {
"vendor_code": "FLOWSHOP", "vendor_code": "FLOWVENDOR",
"vendor_name": "Integration Flow Shop", "vendor_name": "Integration Flow Vendor",
"description": "Test vendor for integration", "description": "Test vendor for integration",
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
assert response.status_code == 200 assert response.status_code == 200
vendor = response.json() vendor = response.json()
# 2. Create a product # 2. Create a product
product_data = { product_data = {
"marketplace_product_id": "SHOPFLOW001", "marketplace_product_id": "VENDORFLOW001",
"title": "Vendor Flow MarketplaceProduct", "title": "Vendor Flow MarketplaceProduct",
"price": "15.99", "price": "15.99",
"marketplace": "ShopFlow", "marketplace": "VendorFlow",
} }
response = client.post( response = client.post(
@@ -91,7 +91,7 @@ class TestIntegrationFlows:
# This would test the vendor -product association # This would test the vendor -product association
# 4. Get vendor details # 4. Get vendor details
response = client.get(f"/api/v1/vendor /{vendor ['vendor_code']}", headers=auth_headers) response = client.get(f"/api/v1/vendor/{vendor ['vendor_code']}", headers=auth_headers)
assert response.status_code == 200 assert response.status_code == 200
def test_stock_operations_workflow(self, client, auth_headers): def test_stock_operations_workflow(self, client, auth_headers):

View File

@@ -16,7 +16,7 @@ class TestErrorHandling:
def test_invalid_json_request(self, client, auth_headers): def test_invalid_json_request(self, client, auth_headers):
"""Test handling of malformed JSON requests""" """Test handling of malformed JSON requests"""
response = client.post( response = client.post(
"/api/v1/vendor ", "/api/v1/vendor",
headers=auth_headers, headers=auth_headers,
content="{ invalid json syntax" content="{ invalid json syntax"
) )
@@ -31,9 +31,9 @@ class TestErrorHandling:
"""Test validation errors for missing required fields""" """Test validation errors for missing required fields"""
# Missing vendor_name # Missing vendor_name
response = client.post( response = client.post(
"/api/v1/vendor ", "/api/v1/vendor",
headers=auth_headers, headers=auth_headers,
json={"vendor_code": "TESTSHOP"} json={"vendor_code": "TESTVENDOR"}
) )
assert response.status_code == 422 assert response.status_code == 422
@@ -46,11 +46,11 @@ class TestErrorHandling:
"""Test validation errors for invalid field formats""" """Test validation errors for invalid field formats"""
# Invalid vendor_code format (contains special characters) # Invalid vendor_code format (contains special characters)
response = client.post( response = client.post(
"/api/v1/vendor ", "/api/v1/vendor",
headers=auth_headers, headers=auth_headers,
json={ json={
"vendor_code": "INVALID@SHOP!", "vendor_code": "INVALID@VENDOR!",
"vendor_name": "Test Shop" "vendor_name": "Test Vendor"
} }
) )
@@ -63,7 +63,7 @@ class TestErrorHandling:
def test_missing_authentication_token(self, client): def test_missing_authentication_token(self, client):
"""Test authentication required endpoints without token""" """Test authentication required endpoints without token"""
response = client.get("/api/v1/vendor ") response = client.get("/api/v1/vendor")
assert response.status_code == 401 assert response.status_code == 401
data = response.json() data = response.json()
@@ -73,7 +73,7 @@ class TestErrorHandling:
def test_invalid_authentication_token(self, client): def test_invalid_authentication_token(self, client):
"""Test endpoints with invalid JWT token""" """Test endpoints with invalid JWT token"""
headers = {"Authorization": "Bearer invalid_token_here"} headers = {"Authorization": "Bearer invalid_token_here"}
response = client.get("/api/v1/vendor ", headers=headers) response = client.get("/api/v1/vendor", headers=headers)
assert response.status_code == 401 assert response.status_code == 401
data = response.json() data = response.json()
@@ -85,7 +85,7 @@ class TestErrorHandling:
# This would require creating an expired token for testing # This would require creating an expired token for testing
expired_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.expired.token" expired_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.expired.token"
headers = {"Authorization": f"Bearer {expired_token}"} headers = {"Authorization": f"Bearer {expired_token}"}
response = client.get("/api/v1/vendor ", headers=headers) response = client.get("/api/v1/vendor", headers=headers)
assert response.status_code == 401 assert response.status_code == 401
data = response.json() data = response.json()
@@ -93,13 +93,13 @@ class TestErrorHandling:
def test_vendor_not_found(self, client, auth_headers): def test_vendor_not_found(self, client, auth_headers):
"""Test accessing non-existent vendor """ """Test accessing non-existent vendor """
response = client.get("/api/v1/vendor /NONEXISTENT", headers=auth_headers) response = client.get("/api/v1/vendor/NONEXISTENT", headers=auth_headers)
assert response.status_code == 404 assert response.status_code == 404
data = response.json() data = response.json()
assert data["error_code"] == "VENDOR_NOT_FOUND" assert data["error_code"] == "VENDOR_NOT_FOUND"
assert data["status_code"] == 404 assert data["status_code"] == 404
assert data["details"]["resource_type"] == "Shop" assert data["details"]["resource_type"] == "Vendor"
assert data["details"]["identifier"] == "NONEXISTENT" assert data["details"]["identifier"] == "NONEXISTENT"
def test_product_not_found(self, client, auth_headers): def test_product_not_found(self, client, auth_headers):
@@ -117,10 +117,10 @@ class TestErrorHandling:
"""Test creating vendor with duplicate vendor code""" """Test creating vendor with duplicate vendor code"""
vendor_data = { vendor_data = {
"vendor_code": test_vendor.vendor_code, "vendor_code": test_vendor.vendor_code,
"vendor_name": "Duplicate Shop" "vendor_name": "Duplicate Vendor"
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
assert response.status_code == 409 assert response.status_code == 409
data = response.json() data = response.json()
@@ -146,7 +146,7 @@ class TestErrorHandling:
def test_unauthorized_vendor_access(self, client, auth_headers, inactive_vendor): def test_unauthorized_vendor_access(self, client, auth_headers, inactive_vendor):
"""Test accessing vendor without proper permissions""" """Test accessing vendor without proper permissions"""
response = client.get(f"/api/v1/vendor /{inactive_vendor.vendor_code}", headers=auth_headers) response = client.get(f"/api/v1/vendor/{inactive_vendor.vendor_code}", headers=auth_headers)
assert response.status_code == 403 assert response.status_code == 403
data = response.json() data = response.json()
@@ -171,10 +171,10 @@ class TestErrorHandling:
vendors_created = [] vendors_created = []
for i in range(6): # Assume limit is 5 for i in range(6): # Assume limit is 5
vendor_data = { vendor_data = {
"vendor_code": f"SHOP{i:03d}", "vendor_code": f"VENDOR{i:03d}",
"vendor_name": f"Test Vendor {i}" "vendor_name": f"Test Vendor {i}"
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
vendors_created.append(response) vendors_created.append(response)
# At least one should succeed, and if limit is enforced, later ones should fail # At least one should succeed, and if limit is enforced, later ones should fail
@@ -246,7 +246,7 @@ class TestErrorHandling:
def test_method_not_allowed(self, client, auth_headers): def test_method_not_allowed(self, client, auth_headers):
"""Test 405 for wrong HTTP method on existing endpoints""" """Test 405 for wrong HTTP method on existing endpoints"""
# Try DELETE on an endpoint that only supports GET # Try DELETE on an endpoint that only supports GET
response = client.delete("/api/v1/vendor ", headers=auth_headers) response = client.delete("/api/v1/vendor", headers=auth_headers)
assert response.status_code == 405 assert response.status_code == 405
# FastAPI automatically handles 405 errors # FastAPI automatically handles 405 errors
@@ -255,7 +255,7 @@ class TestErrorHandling:
"""Test handling of unsupported content types""" """Test handling of unsupported content types"""
headers = {**auth_headers, "Content-Type": "application/xml"} headers = {**auth_headers, "Content-Type": "application/xml"}
response = client.post( response = client.post(
"/api/v1/vendor ", "/api/v1/vendor",
headers=headers, headers=headers,
content="<vendor ><code>TEST</code></vendor >" content="<vendor ><code>TEST</code></vendor >"
) )
@@ -266,12 +266,12 @@ class TestErrorHandling:
"""Test handling of unusually large payloads""" """Test handling of unusually large payloads"""
large_description = "x" * 100000 # Very long description large_description = "x" * 100000 # Very long description
vendor_data = { vendor_data = {
"vendor_code": "LARGESHOP", "vendor_code": "LARGEVENDOR",
"vendor_name": "Large Shop", "vendor_name": "Large Vendor",
"description": large_description "description": large_description
} }
response = client.post("/api/v1/vendor ", headers=auth_headers, json=vendor_data) response = client.post("/api/v1/vendor", headers=auth_headers, json=vendor_data)
# Should either accept it or reject with appropriate error # Should either accept it or reject with appropriate error
assert response.status_code in [200, 201, 413, 422] assert response.status_code in [200, 201, 413, 422]
@@ -285,7 +285,7 @@ class TestErrorHandling:
# Make rapid requests to potentially trigger rate limiting # Make rapid requests to potentially trigger rate limiting
responses = [] responses = []
for _ in range(50): # Aggressive request count for _ in range(50): # Aggressive request count
response = client.get("/api/v1/vendor ", headers=auth_headers) response = client.get("/api/v1/vendor", headers=auth_headers)
responses.append(response) responses.append(response)
# Check if any rate limiting occurred and verify error structure # Check if any rate limiting occurred and verify error structure
@@ -344,7 +344,7 @@ class TestErrorHandling:
def test_error_response_consistency(self, client, auth_headers): def test_error_response_consistency(self, client, auth_headers):
"""Test that all error responses follow consistent structure""" """Test that all error responses follow consistent structure"""
test_cases = [ test_cases = [
("/api/v1/vendor /NONEXISTENT", 404), ("/api/v1/vendor/NONEXISTENT", 404),
("/api/v1/marketplace/product/NONEXISTENT", 404), ("/api/v1/marketplace/product/NONEXISTENT", 404),
] ]
@@ -365,7 +365,7 @@ class TestErrorHandling:
def test_cors_error_handling(self, client): def test_cors_error_handling(self, client):
"""Test CORS errors are handled properly""" """Test CORS errors are handled properly"""
# Test preflight request # Test preflight request
response = client.options("/api/v1/vendor ") response = client.options("/api/v1/vendor")
# Should either succeed or be handled gracefully # Should either succeed or be handled gracefully
assert response.status_code in [200, 204, 405] assert response.status_code in [200, 204, 405]
@@ -373,7 +373,7 @@ class TestErrorHandling:
def test_authentication_error_details(self, client): def test_authentication_error_details(self, client):
"""Test authentication error provides helpful details""" """Test authentication error provides helpful details"""
# Test missing Authorization header # Test missing Authorization header
response = client.get("/api/v1/vendor ") response = client.get("/api/v1/vendor")
assert response.status_code == 401 assert response.status_code == 401
data = response.json() data = response.json()
@@ -406,7 +406,7 @@ class TestErrorRecovery:
assert health_response.status_code == 200 assert health_response.status_code == 200
# API endpoints may or may not work depending on system state # API endpoints may or may not work depending on system state
api_response = client.get("/api/v1/vendor ", headers=auth_headers) api_response = client.get("/api/v1/vendor", headers=auth_headers)
# Should get either data or a proper error, not a crash # Should get either data or a proper error, not a crash
assert api_response.status_code in [200, 401, 403, 500, 503] assert api_response.status_code in [200, 401, 403, 500, 503]
@@ -416,7 +416,7 @@ class TestErrorRecovery:
with caplog.at_level(logging.ERROR): with caplog.at_level(logging.ERROR):
# Trigger an error # Trigger an error
client.get("/api/v1/vendor /NONEXISTENT", headers=auth_headers) client.get("/api/v1/vendor/NONEXISTENT", headers=auth_headers)
# Check that error was logged (if your app logs 404s as errors) # Check that error was logged (if your app logs 404s as errors)
# Adjust based on your logging configuration # Adjust based on your logging configuration

View File

@@ -97,7 +97,7 @@ class TestMarketplaceService:
request = MarketplaceImportJobRequest( request = MarketplaceImportJobRequest(
url="https://example.com/products.csv", url="https://example.com/products.csv",
marketplace="Amazon", marketplace="Amazon",
vendor_code="INVALID_SHOP", vendor_code="INVALID_VENDOR",
batch_size=1000, batch_size=1000,
) )
@@ -106,7 +106,7 @@ class TestMarketplaceService:
exception = exc_info.value exception = exc_info.value
assert exception.error_code == "VENDOR_NOT_FOUND" assert exception.error_code == "VENDOR_NOT_FOUND"
assert "INVALID_SHOP" in exception.message assert "INVALID_VENDOR" in exception.message
def test_create_import_job_unauthorized_access(self, db, test_vendor, test_user, other_user): def test_create_import_job_unauthorized_access(self, db, test_vendor, test_user, other_user):
"""Test import job creation with unauthorized vendor access""" """Test import job creation with unauthorized vendor access"""
@@ -452,7 +452,7 @@ class TestMarketplaceService:
request = MarketplaceImportJobRequest( request = MarketplaceImportJobRequest(
url="https://example.com/products.csv", url="https://example.com/products.csv",
marketplace="Amazon", marketplace="Amazon",
vendor_code="TEST_SHOP", vendor_code="TEST_VENDOR",
batch_size=1000, batch_size=1000,
) )

View File

@@ -41,7 +41,7 @@ class TestStatsService:
brand="DifferentBrand", brand="DifferentBrand",
google_product_category="Different Category", google_product_category="Different Category",
marketplace="Amazon", marketplace="Amazon",
vendor_name="AmazonShop", vendor_name="AmazonVendor",
price="15.99", price="15.99",
currency="EUR", currency="EUR",
), ),
@@ -51,7 +51,7 @@ class TestStatsService:
brand="ThirdBrand", brand="ThirdBrand",
google_product_category="Third Category", google_product_category="Third Category",
marketplace="eBay", marketplace="eBay",
vendor_name="eBayShop", vendor_name="eBayVendor",
price="25.99", price="25.99",
currency="USD", currency="USD",
), ),
@@ -61,7 +61,7 @@ class TestStatsService:
brand="TestBrand", # Same as test_marketplace_product brand="TestBrand", # Same as test_marketplace_product
google_product_category="Different Category", google_product_category="Different Category",
marketplace="Letzshop", # Same as test_marketplace_product marketplace="Letzshop", # Same as test_marketplace_product
vendor_name="DifferentShop", vendor_name="DifferentVendor",
price="35.99", price="35.99",
currency="EUR", currency="EUR",
), ),
@@ -143,7 +143,7 @@ class TestStatsService:
title="Amazon MarketplaceProduct 1", title="Amazon MarketplaceProduct 1",
brand="AmazonBrand1", brand="AmazonBrand1",
marketplace="Amazon", marketplace="Amazon",
vendor_name="AmazonShop1", vendor_name="AmazonVendor1",
price="20.00", price="20.00",
currency="EUR", currency="EUR",
), ),
@@ -152,7 +152,7 @@ class TestStatsService:
title="Amazon MarketplaceProduct 2", title="Amazon MarketplaceProduct 2",
brand="AmazonBrand2", brand="AmazonBrand2",
marketplace="Amazon", marketplace="Amazon",
vendor_name="AmazonShop2", vendor_name="AmazonVendor2",
price="25.00", price="25.00",
currency="EUR", currency="EUR",
), ),
@@ -161,7 +161,7 @@ class TestStatsService:
title="eBay MarketplaceProduct", title="eBay MarketplaceProduct",
brand="eBayBrand", brand="eBayBrand",
marketplace="eBay", marketplace="eBay",
vendor_name="eBayShop", vendor_name="eBayVendor",
price="30.00", price="30.00",
currency="USD", currency="USD",
), ),
@@ -196,7 +196,7 @@ class TestStatsService:
marketplace_product_id="NULLMARKET001", marketplace_product_id="NULLMARKET001",
title="MarketplaceProduct without marketplace", title="MarketplaceProduct without marketplace",
marketplace=None, marketplace=None,
vendor_name="SomeShop", vendor_name="SomeVendor",
brand="SomeBrand", brand="SomeBrand",
price="10.00", price="10.00",
currency="EUR", currency="EUR",
@@ -291,7 +291,7 @@ class TestStatsService:
marketplace_product_id="MARKET001", marketplace_product_id="MARKET001",
title="Marketplace MarketplaceProduct 1", title="Marketplace MarketplaceProduct 1",
marketplace="Amazon", marketplace="Amazon",
vendor_name="AmazonShop", vendor_name="AmazonVendor",
price="10.00", price="10.00",
currency="EUR", currency="EUR",
), ),
@@ -299,7 +299,7 @@ class TestStatsService:
marketplace_product_id="MARKET002", marketplace_product_id="MARKET002",
title="Marketplace MarketplaceProduct 2", title="Marketplace MarketplaceProduct 2",
marketplace="eBay", marketplace="eBay",
vendor_name="eBayShop", vendor_name="eBayVendor",
price="15.00", price="15.00",
currency="EUR", currency="EUR",
), ),
@@ -317,18 +317,18 @@ class TestStatsService:
# Add products with different vendor names # Add products with different vendor names
products = [ products = [
MarketplaceProduct( MarketplaceProduct(
marketplace_product_id="SHOP001", marketplace_product_id="PRODUCT001",
title="Vendor MarketplaceProduct 1", title="Vendor MarketplaceProduct 1",
marketplace="Test", marketplace="Test",
vendor_name="ShopA", vendor_name="VendorA",
price="10.00", price="10.00",
currency="EUR", currency="EUR",
), ),
MarketplaceProduct( MarketplaceProduct(
marketplace_product_id="SHOP002", marketplace_product_id="PRODUCT002",
title="Vendor MarketplaceProduct 2", title="Vendor MarketplaceProduct 2",
marketplace="Test", marketplace="Test",
vendor_name="ShopB", vendor_name="VendorB",
price="15.00", price="15.00",
currency="EUR", currency="EUR",
), ),
@@ -338,7 +338,7 @@ class TestStatsService:
count = self.service._get_unique_vendors_count(db) count = self.service._get_unique_vendors_count(db)
assert count >= 2 # At least ShopA and ShopB, plus test_marketplace_product vendor assert count >= 2 # At least VendorA and VendorB, plus test_marketplace_product vendor
assert isinstance(count, int) assert isinstance(count, int)
def test_get_stock_statistics(self, db, test_stock): def test_get_stock_statistics(self, db, test_stock):
@@ -379,7 +379,7 @@ class TestStatsService:
title="Specific MarketplaceProduct 1", title="Specific MarketplaceProduct 1",
brand="SpecificBrand1", brand="SpecificBrand1",
marketplace="SpecificMarket", marketplace="SpecificMarket",
vendor_name="SpecificShop1", vendor_name="SpecificVendor1",
price="10.00", price="10.00",
currency="EUR", currency="EUR",
), ),
@@ -388,7 +388,7 @@ class TestStatsService:
title="Specific MarketplaceProduct 2", title="Specific MarketplaceProduct 2",
brand="SpecificBrand2", brand="SpecificBrand2",
marketplace="SpecificMarket", marketplace="SpecificMarket",
vendor_name="SpecificShop2", vendor_name="SpecificVendor2",
price="15.00", price="15.00",
currency="EUR", currency="EUR",
), ),
@@ -397,7 +397,7 @@ class TestStatsService:
title="Other MarketplaceProduct", title="Other MarketplaceProduct",
brand="OtherBrand", brand="OtherBrand",
marketplace="OtherMarket", marketplace="OtherMarket",
vendor_name="OtherShop", vendor_name="OtherVendor",
price="20.00", price="20.00",
currency="EUR", currency="EUR",
), ),
@@ -417,7 +417,7 @@ class TestStatsService:
# Create products for specific marketplace # Create products for specific marketplace
marketplace_products = [ marketplace_products = [
MarketplaceProduct( MarketplaceProduct(
marketplace_product_id="SHOPTEST001", marketplace_product_id="MARKETTEST001",
title="Vendor Test MarketplaceProduct 1", title="Vendor Test MarketplaceProduct 1",
brand="TestBrand", brand="TestBrand",
marketplace="TestMarketplace", marketplace="TestMarketplace",
@@ -426,7 +426,7 @@ class TestStatsService:
currency="EUR", currency="EUR",
), ),
MarketplaceProduct( MarketplaceProduct(
marketplace_product_id="SHOPTEST002", marketplace_product_id="MARKETTEST002",
title="Vendor Test MarketplaceProduct 2", title="Vendor Test MarketplaceProduct 2",
brand="TestBrand", brand="TestBrand",
marketplace="TestMarketplace", marketplace="TestMarketplace",
@@ -452,7 +452,7 @@ class TestStatsService:
marketplace_product_id="COUNT001", marketplace_product_id="COUNT001",
title="Count MarketplaceProduct 1", title="Count MarketplaceProduct 1",
marketplace="CountMarketplace", marketplace="CountMarketplace",
vendor_name="CountShop", vendor_name="CountVendor",
price="10.00", price="10.00",
currency="EUR", currency="EUR",
), ),
@@ -460,7 +460,7 @@ class TestStatsService:
marketplace_product_id="COUNT002", marketplace_product_id="COUNT002",
title="Count MarketplaceProduct 2", title="Count MarketplaceProduct 2",
marketplace="CountMarketplace", marketplace="CountMarketplace",
vendor_name="CountShop", vendor_name="CountVendor",
price="15.00", price="15.00",
currency="EUR", currency="EUR",
), ),
@@ -468,7 +468,7 @@ class TestStatsService:
marketplace_product_id="COUNT003", marketplace_product_id="COUNT003",
title="Count MarketplaceProduct 3", title="Count MarketplaceProduct 3",
marketplace="CountMarketplace", marketplace="CountMarketplace",
vendor_name="CountShop", vendor_name="CountVendor",
price="20.00", price="20.00",
currency="EUR", currency="EUR",
), ),

View File

@@ -19,7 +19,7 @@ from models.schemas.product import ProductCreate
@pytest.mark.unit @pytest.mark.unit
@pytest.mark.vendors @pytest.mark.vendors
class TestVendorService: class TestVendorService:
"""Test suite for ShopService following the application's exception patterns""" """Test suite for VendorService following the application's exception patterns"""
def setup_method(self): def setup_method(self):
"""Setup method following the same pattern as admin service tests""" """Setup method following the same pattern as admin service tests"""
@@ -29,7 +29,7 @@ class TestVendorService:
"""Test successful vendor creation""" """Test successful vendor creation"""
vendor_data = VendorCreate( vendor_data = VendorCreate(
vendor_code="NEWVENDOR", vendor_code="NEWVENDOR",
vendor_name="New Test Shop", vendor_name="New Test Vendor",
description="A new test vendor ", description="A new test vendor ",
) )
@@ -42,7 +42,7 @@ class TestVendorService:
def test_create_vendor_admin_auto_verify(self, db, test_admin, vendor_factory): def test_create_vendor_admin_auto_verify(self, db, test_admin, vendor_factory):
"""Test admin creates verified vendor automatically""" """Test admin creates verified vendor automatically"""
vendor_data = VendorCreate(vendor_code="ADMINSHOP", vendor_name="Admin Test Shop") vendor_data = VendorCreate(vendor_code="ADMINVENDOR", vendor_name="Admin Test Vendor")
vendor = self.service.create_vendor(db, vendor_data, test_admin) vendor = self.service.create_vendor(db, vendor_data, test_admin)
@@ -65,7 +65,7 @@ class TestVendorService:
def test_create_vendor_invalid_data_empty_code(self, db, test_user): def test_create_vendor_invalid_data_empty_code(self, db, test_user):
"""Test vendor creation fails with empty vendor code""" """Test vendor creation fails with empty vendor code"""
vendor_data = VendorCreate(vendor_code="", vendor_name="Test Shop") vendor_data = VendorCreate(vendor_code="", vendor_name="Test Vendor")
with pytest.raises(InvalidVendorDataException) as exc_info: with pytest.raises(InvalidVendorDataException) as exc_info:
self.service.create_vendor(db, vendor_data, test_user) self.service.create_vendor(db, vendor_data, test_user)
@@ -88,7 +88,7 @@ class TestVendorService:
def test_create_vendor_invalid_code_format(self, db, test_user): def test_create_vendor_invalid_code_format(self, db, test_user):
"""Test vendor creation fails with invalid vendor code format""" """Test vendor creation fails with invalid vendor code format"""
vendor_data = VendorCreate(vendor_code="INVALID@CODE!", vendor_name="Test Shop") vendor_data = VendorCreate(vendor_code="INVALID@CODE!", vendor_name="Test Vendor")
with pytest.raises(InvalidVendorDataException) as exc_info: with pytest.raises(InvalidVendorDataException) as exc_info:
self.service.create_vendor(db, vendor_data, test_user) self.service.create_vendor(db, vendor_data, test_user)
@@ -163,7 +163,7 @@ class TestVendorService:
exception = exc_info.value exception = exc_info.value
assert exception.status_code == 404 assert exception.status_code == 404
assert exception.error_code == "VENDOR_NOT_FOUND" assert exception.error_code == "VENDOR_NOT_FOUND"
assert exception.details["resource_type"] == "Shop" assert exception.details["resource_type"] == "Vendor"
assert exception.details["identifier"] == "NONEXISTENT" assert exception.details["identifier"] == "NONEXISTENT"
def test_get_vendor_by_code_access_denied(self, db, test_user, inactive_vendor): def test_get_vendor_by_code_access_denied(self, db, test_user, inactive_vendor):
@@ -266,7 +266,7 @@ class TestVendorService:
monkeypatch.setattr(db, "commit", mock_commit) monkeypatch.setattr(db, "commit", mock_commit)
vendor_data = VendorCreate(vendor_code="NEWVENDOR", vendor_name="Test Shop") vendor_data = VendorCreate(vendor_code="NEWVENDOR", vendor_name="Test Vendor")
with pytest.raises(ValidationException) as exc_info: with pytest.raises(ValidationException) as exc_info:
self.service.create_vendor(db, vendor_data, test_user) self.service.create_vendor(db, vendor_data, test_user)