project initialization
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

This commit is contained in:
2025-10-05 02:37:33 +08:00
parent 2cbb6d5fa1
commit b3fff546e9
226 changed files with 97805 additions and 35 deletions

View File

@@ -0,0 +1,579 @@
"""
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