Files
multitenetsaas/backend/tests/integration/test_retail_operations.py
AHMET YILMAZ b3fff546e9
Some checks failed
System Monitoring / Health Checks (push) Has been cancelled
System Monitoring / Performance Monitoring (push) Has been cancelled
System Monitoring / Database Monitoring (push) Has been cancelled
System Monitoring / Cache Monitoring (push) Has been cancelled
System Monitoring / Log Monitoring (push) Has been cancelled
System Monitoring / Resource Monitoring (push) Has been cancelled
System Monitoring / Uptime Monitoring (push) Has been cancelled
System Monitoring / Backup Monitoring (push) Has been cancelled
System Monitoring / Security Monitoring (push) Has been cancelled
System Monitoring / Monitoring Dashboard (push) Has been cancelled
System Monitoring / Alerting (push) Has been cancelled
Security Scanning / Dependency Scanning (push) Has been cancelled
Security Scanning / Code Security Scanning (push) Has been cancelled
Security Scanning / Secrets Scanning (push) Has been cancelled
Security Scanning / Container Security Scanning (push) Has been cancelled
Security Scanning / Compliance Checking (push) Has been cancelled
Security Scanning / Security Dashboard (push) Has been cancelled
Security Scanning / Security Remediation (push) Has been cancelled
project initialization
2025-10-05 02:37:33 +08:00

579 lines
19 KiB
Python

"""
Integration test for retail module operations.
This test MUST fail before implementation.
"""
import pytest
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APIClient
from rest_framework import status
import json
from datetime import datetime, timedelta
class RetailOperationsIntegrationTest(TestCase):
def setUp(self):
self.client = APIClient()
# Tenant authentication header
self.tenant_auth = {'HTTP_AUTHORIZATION': 'Bearer tenant_token'}
# Test product data
self.product_data = {
'sku': 'LPT-PRO-001',
'name': 'Professional Laptop 15"',
'description': 'High-performance laptop for business use',
'category': 'ELECTRONICS',
'price': 3499.99,
'cost': 2800.00,
'stock_quantity': 25,
'barcode': '1234567890123',
'brand': 'TechBrand',
'model': 'PRO-15-2024',
'tax_rate': 6.0
}
# Test customer data
self.customer_data = {
'name': 'John Customer',
'email': 'john.customer@example.com',
'phone': '+60123456789',
'address': {
'street': '123 Customer Street',
'city': 'Kuala Lumpur',
'state': 'Wilayah Persekutuan',
'postal_code': '50000',
'country': 'Malaysia'
}
}
def test_complete_retail_workflow(self):
"""Test complete retail workflow from product creation to sales reporting."""
# Step 1: Create product (should fail before implementation)
product_response = self.client.post(
'/api/v1/retail/products/',
data=json.dumps(self.product_data),
content_type='application/json',
**self.tenant_auth
)
assert product_response.status_code == status.HTTP_201_CREATED
product_data = product_response.json()
# Verify product structure
assert 'id' in product_data
assert product_data['sku'] == self.product_data['sku']
assert product_data['stock_quantity'] == self.product_data['stock_quantity']
assert product_data['status'] == 'ACTIVE'
# Step 2: Create additional products for inventory testing
additional_products = [
{
'sku': 'MOU-WRL-001',
'name': 'Wireless Mouse',
'category': 'ELECTRONICS',
'price': 89.99,
'cost': 45.00,
'stock_quantity': 50
},
{
'sku': 'KEY-MEC-001',
'name': 'Mechanical Keyboard',
'category': 'ELECTRONICS',
'price': 299.99,
'cost': 180.00,
'stock_quantity': 30
}
]
created_products = []
for prod_data in additional_products:
prod_response = self.client.post(
'/api/v1/retail/products/',
data=json.dumps(prod_data),
content_type='application/json',
**self.tenant_auth
)
assert prod_response.status_code == status.HTTP_201_CREATED
created_products.append(prod_response.json())
# Step 3: Process multiple sales transactions
sales_transactions = [
{
'customer': self.customer_data,
'items': [
{
'product_id': product_data['id'],
'sku': product_data['sku'],
'quantity': 2,
'unit_price': product_data['price']
},
{
'product_id': created_products[0]['id'],
'sku': created_products[0]['sku'],
'quantity': 1,
'unit_price': created_products[0]['price']
}
],
'payment': {
'method': 'CARD',
'amount_paid': 7290.00,
'reference_number': 'CARD-001'
}
},
{
'customer': {
'name': 'Jane Buyer',
'email': 'jane@example.com',
'phone': '+60198765432'
},
'items': [
{
'product_id': created_products[1]['id'],
'sku': created_products[1]['sku'],
'quantity': 3,
'unit_price': created_products[1]['price']
}
],
'payment': {
'method': 'CASH',
'amount_paid': 900.00,
'reference_number': 'CASH-001'
}
}
]
created_sales = []
for sale_data in sales_transactions:
sale_response = self.client.post(
'/api/v1/retail/sales/',
data=json.dumps(sale_data),
content_type='application/json',
**self.tenant_auth
)
assert sale_response.status_code == status.HTTP_201_CREATED
created_sales.append(sale_response.json())
# Step 4: Verify inventory updates after sales
inventory_check_response = self.client.get(
f'/api/v1/retail/products/{product_data["id"]}/',
**self.tenant_auth
)
assert inventory_check_response.status_code == status.HTTP_200_OK
updated_product = inventory_check_response.json()
# Stock should be reduced by sold quantity
expected_stock = self.product_data['stock_quantity'] - 2 # 2 laptops sold
assert updated_product['stock_quantity'] == expected_stock
# Step 5: Test sales reporting
sales_report_response = self.client.get(
'/api/v1/retail/reports/sales/',
data={
'start_date': (datetime.now() - timedelta(days=7)).isoformat(),
'end_date': datetime.now().isoformat()
},
**self.tenant_auth
)
assert sales_report_response.status_code == status.HTTP_200_OK
sales_report = sales_report_response.json()
assert 'total_sales' in sales_report
assert 'total_revenue' in sales_report
assert 'transactions_count' in sales_report
assert 'top_products' in sales_report
# Verify report data
assert sales_report['transactions_count'] == len(created_sales)
assert sales_report['total_revenue'] > 0
# Step 6: Test inventory reporting
inventory_report_response = self.client.get(
'/api/v1/retail/reports/inventory/',
**self.tenant_auth
)
assert inventory_report_response.status_code == status.HTTP_200_OK
inventory_report = inventory_report_response.json()
assert 'total_products' in inventory_report
assert 'low_stock_items' in inventory_report
assert 'total_value' in inventory_report
# Step 7: Test product search and filtering
search_response = self.client.get(
'/api/v1/retail/products/',
data={'search': 'laptop', 'category': 'ELECTRONICS'},
**self.tenant_auth
)
assert search_response.status_code == status.HTTP_200_OK
search_results = search_response.json()['products']
# Should find the laptop product
assert len(search_results) > 0
assert any(product['id'] == product_data['id'] for product in search_results)
def test_inventory_management_operations(self):
"""Test inventory management operations."""
# Create product first
product_response = self.client.post(
'/api/v1/retail/products/',
data=json.dumps(self.product_data),
content_type='application/json',
**self.tenant_auth
)
assert product_response.status_code == status.HTTP_201_CREATED
product_data = product_response.json()
# Step 1: Stock adjustment
adjustment_data = {
'type': 'ADDITION',
'quantity': 10,
'reason': 'New stock received',
'reference': 'PO-2024-001',
'unit_cost': 2750.00
}
adjustment_response = self.client.post(
f'/api/v1/retail/products/{product_data["id"]}/inventory/',
data=json.dumps(adjustment_data),
content_type='application/json',
**self.tenant_auth
)
assert adjustment_response.status_code == status.HTTP_200_OK
# Verify stock was updated
updated_product_response = self.client.get(
f'/api/v1/retail/products/{product_data["id"]}/',
**self.tenant_auth
)
assert updated_product_response.status_code == status.HTTP_200_OK
updated_product = updated_product_response.json()
expected_stock = self.product_data['stock_quantity'] + 10
assert updated_product['stock_quantity'] == expected_stock
# Step 2: Stock transfer
transfer_data = {
'quantity': 5,
'from_location': 'Warehouse A',
'to_location': 'Store Front',
'reason': 'Restocking store'
}
transfer_response = self.client.post(
f'/api/v1/retail/products/{product_data["id"]}/transfer/',
data=json.dumps(transfer_data),
content_type='application/json',
**self.tenant_auth
)
assert transfer_response.status_code == status.HTTP_200_OK
# Step 3: Low stock alerts
# Create product with low stock
low_stock_product = self.product_data.copy()
low_stock_product['sku'] = 'LOW-STOCK-001'
low_stock_product['stock_quantity'] = 2
low_stock_response = self.client.post(
'/api/v1/retail/products/',
data=json.dumps(low_stock_product),
content_type='application/json',
**self.tenant_auth
)
assert low_stock_response.status_code == status.HTTP_201_CREATED
# Check low stock report
low_stock_report_response = self.client.get(
'/api/v1/retail/reports/low-stock/',
**self.tenant_auth
)
assert low_stock_report_response.status_code == status.HTTP_200_OK
low_stock_report = low_stock_report_response.json()
assert 'low_stock_items' in low_stock_report
assert len(low_stock_report['low_stock_items']) > 0
def test_product_variant_management(self):
"""Test product variant management."""
# Create parent product with variants
parent_product = self.product_data.copy()
parent_product['variants'] = [
{
'sku': 'LPT-PRO-001-BLK',
'name': 'Professional Laptop 15" - Black',
'attributes': {'color': 'Black', 'storage': '512GB SSD'},
'price_adjustment': 0,
'stock_quantity': 10
},
{
'sku': 'LPT-PRO-001-SLV',
'name': 'Professional Laptop 15" - Silver',
'attributes': {'color': 'Silver', 'storage': '1TB SSD'},
'price_adjustment': 200,
'stock_quantity': 8
}
]
product_response = self.client.post(
'/api/v1/retail/products/',
data=json.dumps(parent_product),
content_type='application/json',
**self.tenant_auth
)
assert product_response.status_code == status.HTTP_201_CREATED
created_product = product_response.json()
# Verify variants were created
assert 'variants' in created_product
assert len(created_product['variants']) == 2
# Test variant operations
variant = created_product['variants'][0]
# Update variant stock
variant_stock_update = {
'stock_quantity': 15,
'reason': 'New stock received'
}
variant_update_response = self.client.put(
f'/api/v1/retail/products/{created_product["id"]}/variants/{variant["sku"]}/',
data=json.dumps(variant_stock_update),
content_type='application/json',
**self.tenant_auth
)
assert variant_update_response.status_code == status.HTTP_200_OK
def test_customer_management(self):
"""Test customer management operations."""
# Create customer
customer_response = self.client.post(
'/api/v1/retail/customers/',
data=json.dumps(self.customer_data),
content_type='application/json',
**self.tenant_auth
)
assert customer_response.status_code == status.HTTP_201_CREATED
customer_data = customer_response.json()
# Step 1: Customer purchase history
# Create a sale for this customer
sale_data = {
'customer_id': customer_data['id'],
'items': [
{
'product_id': 'product-001',
'sku': 'TEST-001',
'quantity': 1,
'unit_price': 99.99
}
],
'payment': {
'method': 'CASH',
'amount_paid': 99.99
}
}
sale_response = self.client.post(
'/api/v1/retail/sales/',
data=json.dumps(sale_data),
content_type='application/json',
**self.tenant_auth
)
assert sale_response.status_code == status.HTTP_201_CREATED
# Get customer purchase history
history_response = self.client.get(
f'/api/v1/retail/customers/{customer_data["id"]}/history/',
**self.tenant_auth
)
assert history_response.status_code == status.HTTP_200_OK
history_data = history_response.json()
assert 'purchases' in history_data
assert 'total_spent' in history_data
assert 'loyalty_points' in history_data
# Step 2: Customer loyalty program
loyalty_data = {
'points_earned': 100,
'notes': 'Purchase bonus'
}
loyalty_response = self.client.post(
f'/api/v1/retail/customers/{customer_data["id"]}/loyalty/',
data=json.dumps(loyalty_data),
content_type='application/json',
**self.tenant_auth
)
assert loyalty_response.status_code == status.HTTP_200_OK
def test_discount_and_promotion_management(self):
"""Test discount and promotion management."""
# Create promotion
promotion_data = {
'name': 'New Year Sale',
'type': 'PERCENTAGE',
'value': 20,
'start_date': (datetime.now() - timedelta(days=1)).isoformat(),
'end_date': (datetime.now() + timedelta(days=30)).isoformat(),
'applicable_products': ['product-001', 'product-002'],
'minimum_purchase': 100,
'usage_limit': 100
}
promotion_response = self.client.post(
'/api/v1/retail/promotions/',
data=json.dumps(promotion_data),
content_type='application/json',
**self.tenant_auth
)
assert promotion_response.status_code == status.HTTP_201_CREATED
created_promotion = promotion_response.json()
# Test promotion application in sale
sale_with_promotion = {
'customer': self.customer_data,
'items': [
{
'product_id': 'product-001',
'sku': 'TEST-001',
'quantity': 2,
'unit_price': 100.00
}
],
'promotion_code': created_promotion['code'],
'payment': {
'method': 'CARD',
'amount_paid': 160.00 # 20% discount on 200
}
}
sale_response = self.client.post(
'/api/v1/retail/sales/',
data=json.dumps(sale_with_promotion),
content_type='application/json',
**self.tenant_auth
)
assert sale_response.status_code == status.HTTP_201_CREATED
sale_data = sale_response.json()
# Verify discount was applied
assert 'discount_amount' in sale_data['totals']
assert sale_data['totals']['discount_amount'] == 40.00
def test_return_and_refund_operations(self):
"""Test return and refund operations."""
# Create a sale first
sale_data = {
'customer': self.customer_data,
'items': [
{
'product_id': 'product-001',
'sku': 'TEST-001',
'quantity': 2,
'unit_price': 100.00
}
],
'payment': {
'method': 'CARD',
'amount_paid': 200.00
}
}
sale_response = self.client.post(
'/api/v1/retail/sales/',
data=json.dumps(sale_data),
content_type='application/json',
**self.tenant_auth
)
assert sale_response.status_code == status.HTTP_201_CREATED
created_sale = sale_response.json()
# Process return
return_data = {
'sale_id': created_sale['id'],
'items': [
{
'product_id': 'product-001',
'quantity': 1,
'reason': 'Defective product',
'condition': 'DAMAGED'
}
],
'refund_method': 'ORIGINAL',
'notes': 'Customer reported defective item'
}
return_response = self.client.post(
'/api/v1/retail/returns/',
data=json.dumps(return_data),
content_type='application/json',
**self.tenant_auth
)
assert return_response.status_code == status.HTTP_201_CREATED
return_data = return_response.json()
# Verify inventory was updated (returned to stock)
# Verify refund was processed
assert 'refund_amount' in return_data
assert return_data['refund_amount'] == 100.00
def test_retail_analytics_and_reporting(self):
"""Test retail analytics and reporting."""
# Generate some test data first
# This would involve creating multiple products and sales
# Test sales analytics
analytics_response = self.client.get(
'/api/v1/retail/analytics/',
data={
'period': 'monthly',
'year': 2024,
'month': 1
},
**self.tenant_auth
)
assert analytics_response.status_code == status.HTTP_200_OK
analytics_data = analytics_response.json()
assert 'revenue' in analytics_data
assert 'profit' in analytics_data
assert 'top_products' in analytics_data
assert 'customer_metrics' in analytics_data
# Test product performance
performance_response = self.client.get(
'/api/v1/retail/reports/product-performance/',
**self.tenant_auth
)
assert performance_response.status_code == status.HTTP_200_OK
performance_data = performance_response.json()
assert 'products' in performance_data
assert 'best_sellers' in performance_data
assert 'low_performers' in performance_data