Files
multitenetsaas/backend/tests/unit/models/test_retail_models.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

350 lines
12 KiB
Python

"""
Unit tests for Retail Models
Tests for retail module models:
- Product
- Sale
Author: Claude
"""
import pytest
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.utils import timezone
from decimal import Decimal
from datetime import date
from backend.src.core.models.tenant import Tenant
from backend.src.core.models.user import User
from backend.src.modules.retail.models.product import Product
from backend.src.modules.retail.models.sale import Sale, SaleItem
User = get_user_model()
class ProductModelTest(TestCase):
"""Test cases for Product model"""
def setUp(self):
self.tenant = Tenant.objects.create(
name='Test Business Sdn Bhd',
schema_name='test_business',
domain='testbusiness.com',
business_type='retail'
)
self.user = User.objects.create_user(
username='testuser',
email='user@test.com',
password='test123',
tenant=self.tenant
)
self.product_data = {
'tenant': self.tenant,
'sku': 'PRD-001',
'name': 'Test Product',
'description': 'A test product for unit testing',
'category': 'electronics',
'brand': 'Test Brand',
'barcode': '1234567890123',
'unit': 'piece',
'current_stock': 100,
'minimum_stock': 10,
'maximum_stock': 500,
'reorder_point': 15,
'purchase_price': Decimal('50.00'),
'selling_price': Decimal('100.00'),
'wholesale_price': Decimal('80.00'),
'tax_rate': 10.0,
'is_taxable': True,
'is_active': True,
'requires_prescription': False,
'is_halal': True,
'msme_certified': True,
'created_by': self.user
}
def test_create_product(self):
"""Test creating a new product"""
product = Product.objects.create(**self.product_data)
self.assertEqual(product.tenant, self.tenant)
self.assertEqual(product.sku, self.product_data['sku'])
self.assertEqual(product.name, self.product_data['name'])
self.assertEqual(product.current_stock, self.product_data['current_stock'])
self.assertEqual(product.purchase_price, self.product_data['purchase_price'])
self.assertEqual(product.selling_price, self.product_data['selling_price'])
self.assertTrue(product.is_active)
self.assertTrue(product.is_halal)
def test_product_string_representation(self):
"""Test product string representation"""
product = Product.objects.create(**self.product_data)
self.assertEqual(str(product), f"{product.name} ({product.sku})")
def test_product_is_low_stock(self):
"""Test product low stock detection"""
product = Product.objects.create(**self.product_data)
# Normal stock level
self.assertFalse(product.is_low_stock)
# Low stock level
product.current_stock = 5
product.save()
self.assertTrue(product.is_low_stock)
def test_product_profit_margin(self):
"""Test product profit margin calculation"""
product = Product.objects.create(**self.product_data)
expected_margin = ((product.selling_price - product.purchase_price) / product.selling_price) * 100
self.assertAlmostEqual(product.profit_margin, expected_margin)
def test_product_category_choices(self):
"""Test product category validation"""
invalid_data = self.product_data.copy()
invalid_data['category'] = 'invalid_category'
with self.assertRaises(Exception):
Product.objects.create(**invalid_data)
def test_product_unit_choices(self):
"""Test product unit validation"""
invalid_data = self.product_data.copy()
invalid_data['unit'] = 'invalid_unit'
with self.assertRaises(Exception):
Product.objects.create(**invalid_data)
def test_product_barcode_validation(self):
"""Test product barcode validation"""
# Valid barcode
product = Product.objects.create(**self.product_data)
self.assertEqual(product.barcode, self.product_data['barcode'])
# Invalid barcode (too long)
invalid_data = self.product_data.copy()
invalid_data['barcode'] = '1' * 14
with self.assertRaises(Exception):
Product.objects.create(**invalid_data)
def test_product_stock_validation(self):
"""Test product stock validation"""
invalid_data = self.product_data.copy()
invalid_data['current_stock'] = -1
with self.assertRaises(Exception):
Product.objects.create(**invalid_data)
invalid_data['current_stock'] = 0
invalid_data['minimum_stock'] = -5
with self.assertRaises(Exception):
Product.objects.create(**invalid_data)
class SaleModelTest(TestCase):
"""Test cases for Sale and SaleItem models"""
def setUp(self):
self.tenant = Tenant.objects.create(
name='Test Business Sdn Bhd',
schema_name='test_business',
domain='testbusiness.com',
business_type='retail'
)
self.user = User.objects.create_user(
username='testuser',
email='user@test.com',
password='test123',
tenant=self.tenant
)
self.product1 = Product.objects.create(
tenant=self.tenant,
sku='PRD-001',
name='Product 1',
category='electronics',
unit='piece',
current_stock=100,
minimum_stock=10,
purchase_price=Decimal('50.00'),
selling_price=Decimal('100.00'),
tax_rate=10.0,
created_by=self.user
)
self.product2 = Product.objects.create(
tenant=self.tenant,
sku='PRD-002',
name='Product 2',
category='electronics',
unit='piece',
current_stock=50,
minimum_stock=5,
purchase_price=Decimal('30.00'),
selling_price=Decimal('60.00'),
tax_rate=10.0,
created_by=self.user
)
self.sale_data = {
'tenant': self.tenant,
'invoice_number': 'INV-2024010001',
'customer_name': 'Test Customer',
'customer_email': 'customer@test.com',
'customer_phone': '+60123456789',
'customer_ic': '000101-01-0001',
'sale_date': timezone.now(),
'status': 'completed',
'payment_method': 'cash',
'payment_status': 'paid',
'sales_person': self.user,
'notes': 'Test sale for unit testing'
}
def test_create_sale(self):
"""Test creating a new sale"""
sale = Sale.objects.create(**self.sale_data)
self.assertEqual(sale.tenant, self.tenant)
self.assertEqual(sale.invoice_number, self.sale_data['invoice_number'])
self.assertEqual(sale.customer_name, self.sale_data['customer_name'])
self.assertEqual(sale.status, self.sale_data['status'])
self.assertEqual(sale.payment_status, self.sale_data['payment_status'])
self.assertEqual(sale.sales_person, self.user)
def test_sale_string_representation(self):
"""Test sale string representation"""
sale = Sale.objects.create(**self.sale_data)
self.assertEqual(str(sale), f"Invoice #{sale.invoice_number} - {sale.customer_name}")
def test_create_sale_item(self):
"""Test creating a sale item"""
sale = Sale.objects.create(**self.sale_data)
sale_item_data = {
'sale': sale,
'product': self.product1,
'quantity': 2,
'unit_price': Decimal('100.00'),
'discount_percentage': 0.0,
'tax_rate': 10.0,
'notes': 'Test sale item'
}
sale_item = SaleItem.objects.create(**sale_item_data)
self.assertEqual(sale_item.sale, sale)
self.assertEqual(sale_item.product, self.product1)
self.assertEqual(sale_item.quantity, 2)
self.assertEqual(sale_item.unit_price, Decimal('100.00'))
def test_sale_item_subtotal(self):
"""Test sale item subtotal calculation"""
sale = Sale.objects.create(**self.sale_data)
sale_item = SaleItem.objects.create(
sale=sale,
product=self.product1,
quantity=2,
unit_price=Decimal('100.00'),
tax_rate=10.0
)
expected_subtotal = Decimal('200.00') # 2 * 100.00
self.assertEqual(sale_item.subtotal, expected_subtotal)
def test_sale_item_tax_amount(self):
"""Test sale item tax amount calculation"""
sale = Sale.objects.create(**self.sale_data)
sale_item = SaleItem.objects.create(
sale=sale,
product=self.product1,
quantity=2,
unit_price=Decimal('100.00'),
tax_rate=10.0
)
expected_tax = Decimal('20.00') # 200.00 * 0.10
self.assertEqual(sale_item.tax_amount, expected_tax)
def test_sale_item_total_amount(self):
"""Test sale item total amount calculation"""
sale = Sale.objects.create(**self.sale_data)
sale_item = SaleItem.objects.create(
sale=sale,
product=self.product1,
quantity=2,
unit_price=Decimal('100.00'),
tax_rate=10.0
)
expected_total = Decimal('220.00') # 200.00 + 20.00
self.assertEqual(sale_item.total_amount, expected_total)
def test_sale_calculate_totals(self):
"""Test sale total calculations"""
sale = Sale.objects.create(**self.sale_data)
# Create multiple sale items
SaleItem.objects.create(
sale=sale,
product=self.product1,
quantity=2,
unit_price=Decimal('100.00'),
tax_rate=10.0
)
SaleItem.objects.create(
sale=sale,
product=self.product2,
quantity=1,
unit_price=Decimal('60.00'),
tax_rate=10.0
)
# Test the calculate_totals method
sale.calculate_totals()
expected_subtotal = Decimal('260.00') # 200.00 + 60.00
expected_tax = Decimal('26.00') # 20.00 + 6.00
expected_total = Decimal('286.00') # 260.00 + 26.00
self.assertEqual(sale.subtotal_amount, expected_subtotal)
self.assertEqual(sale.tax_amount, expected_tax)
self.assertEqual(sale.total_amount, expected_total)
def test_sale_status_choices(self):
"""Test sale status validation"""
invalid_data = self.sale_data.copy()
invalid_data['status'] = 'invalid_status'
with self.assertRaises(Exception):
Sale.objects.create(**invalid_data)
def test_sale_payment_method_choices(self):
"""Test sale payment method validation"""
invalid_data = self.sale_data.copy()
invalid_data['payment_method'] = 'invalid_method'
with self.assertRaises(Exception):
Sale.objects.create(**invalid_data)
def test_malaysian_customer_validation(self):
"""Test Malaysian customer validation"""
# Valid Malaysian IC
sale = Sale.objects.create(**self.sale_data)
self.assertEqual(sale.customer_ic, self.sale_data['customer_ic'])
# Valid Malaysian phone
self.assertEqual(sale.customer_phone, self.sale_data['customer_phone'])
# Invalid phone number
invalid_data = self.sale_data.copy()
invalid_data['customer_phone'] = '12345'
with self.assertRaises(Exception):
Sale.objects.create(**invalid_data)