Files
TimeTracker/tests/test_extra_good_model.py
Dries Peeters 90dde470da style: standardize code formatting and normalize line endings
- Normalize line endings from CRLF to LF across all files to match .editorconfig
- Standardize quote style from single quotes to double quotes
- Normalize whitespace and formatting throughout codebase
- Apply consistent code style across 372 files including:
  * Application code (models, routes, services, utils)
  * Test files
  * Configuration files
  * CI/CD workflows

This ensures consistency with the project's .editorconfig settings and
improves code maintainability.
2025-11-28 20:05:37 +01:00

263 lines
8.8 KiB
Python

"""
Tests for ExtraGood model
"""
import pytest
from decimal import Decimal
from datetime import datetime
from app.models import ExtraGood, Project, User, Client, Invoice
from factories import InvoiceFactory
class TestExtraGoodModel:
"""Test cases for ExtraGood model"""
def test_create_extra_good_for_project(self, app, db_session):
"""Test creating an extra good for a project"""
# Create test data
client = Client(name="Test Client")
db_session.add(client)
db_session.commit()
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
project = Project(name="Test Project", client_id=client.id)
db_session.add(project)
db_session.commit()
# Create extra good
good = ExtraGood(
name="Test Product",
unit_price=100.00,
quantity=5,
created_by=user.id,
project_id=project.id,
description="Test description",
category="product",
sku="TEST-001",
)
db_session.add(good)
db_session.commit()
# Verify
assert good.id is not None
assert good.name == "Test Product"
assert good.quantity == Decimal("5")
assert good.unit_price == Decimal("100.00")
assert good.total_amount == Decimal("500.00")
assert good.project_id == project.id
assert good.created_by == user.id
assert good.category == "product"
assert good.sku == "TEST-001"
def test_create_extra_good_for_invoice(self, app, db_session):
"""Test creating an extra good for an invoice"""
# Create test data
client = Client(name="Test Client")
db_session.add(client)
db_session.commit()
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
project = Project(name="Test Project", client_id=client.id)
db_session.add(project)
db_session.commit()
invoice = InvoiceFactory(
invoice_number="INV-001",
project_id=project.id,
client_name="Test Client",
due_date=datetime.utcnow().date(),
created_by=user.id,
client_id=client.id,
status="draft",
)
# Create extra good
good = ExtraGood(
name="License Fee",
unit_price=500.00,
quantity=1,
created_by=user.id,
invoice_id=invoice.id,
category="license",
)
db_session.add(good)
db_session.commit()
# Verify
assert good.id is not None
assert good.invoice_id == invoice.id
assert good.total_amount == Decimal("500.00")
def test_update_total(self, app, db_session):
"""Test updating total when quantity or price changes"""
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
good = ExtraGood(name="Test Good", unit_price=10.00, quantity=2, created_by=user.id)
db_session.add(good)
db_session.commit()
# Change quantity and update total
good.quantity = Decimal("5")
good.update_total()
assert good.total_amount == Decimal("50.00")
# Change unit price and update total
good.unit_price = Decimal("15.00")
good.update_total()
assert good.total_amount == Decimal("75.00")
def test_to_dict(self, app, db_session):
"""Test converting extra good to dictionary"""
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
good = ExtraGood(
name="Test Product",
unit_price=100.00,
quantity=2,
created_by=user.id,
description="Test desc",
category="product",
sku="SKU-123",
)
db_session.add(good)
db_session.commit()
data = good.to_dict()
assert data["name"] == "Test Product"
assert data["quantity"] == 2.0
assert data["unit_price"] == 100.0
assert data["total_amount"] == 200.0
assert data["category"] == "product"
assert data["sku"] == "SKU-123"
assert data["creator"] == "testuser"
def test_get_project_goods(self, app, db_session):
"""Test getting goods for a project"""
client = Client(name="Test Client")
db_session.add(client)
db_session.commit()
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
project = Project(name="Test Project", client_id=client.id)
db_session.add(project)
db_session.commit()
# Create multiple goods
good1 = ExtraGood(
name="Good 1", unit_price=10, quantity=1, created_by=user.id, project_id=project.id, billable=True
)
good2 = ExtraGood(
name="Good 2", unit_price=20, quantity=1, created_by=user.id, project_id=project.id, billable=False
)
good3 = ExtraGood(
name="Good 3", unit_price=30, quantity=1, created_by=user.id, project_id=project.id, billable=True
)
db_session.add_all([good1, good2, good3])
db_session.commit()
# Get all goods
all_goods = ExtraGood.get_project_goods(project.id)
assert len(all_goods) == 3
# Get only billable goods
billable_goods = ExtraGood.get_project_goods(project.id, billable_only=True)
assert len(billable_goods) == 2
def test_get_total_amount(self, app, db_session):
"""Test calculating total amount for goods"""
client = Client(name="Test Client")
db_session.add(client)
db_session.commit()
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
project = Project(name="Test Project", client_id=client.id)
db_session.add(project)
db_session.commit()
# Create goods with different amounts
good1 = ExtraGood(
name="Good 1", unit_price=100, quantity=2, created_by=user.id, project_id=project.id, billable=True
)
good2 = ExtraGood(
name="Good 2", unit_price=50, quantity=3, created_by=user.id, project_id=project.id, billable=False
)
db_session.add_all([good1, good2])
db_session.commit()
# Total of all goods: 200 + 150 = 350
total = ExtraGood.get_total_amount(project_id=project.id)
assert total == 350.0
# Total of billable goods only: 200
billable_total = ExtraGood.get_total_amount(project_id=project.id, billable_only=True)
assert billable_total == 200.0
def test_get_goods_by_category(self, app, db_session):
"""Test grouping goods by category"""
client = Client(name="Test Client")
db_session.add(client)
db_session.commit()
user = User(username="testuser", email="test@example.com", role="user")
user.password_hash = "hash"
db_session.add(user)
db_session.commit()
project = Project(name="Test Project", client_id=client.id)
db_session.add(project)
db_session.commit()
# Create goods in different categories
good1 = ExtraGood(
name="Product 1", unit_price=100, quantity=1, created_by=user.id, project_id=project.id, category="product"
)
good2 = ExtraGood(
name="Product 2", unit_price=150, quantity=1, created_by=user.id, project_id=project.id, category="product"
)
good3 = ExtraGood(
name="Service 1", unit_price=200, quantity=1, created_by=user.id, project_id=project.id, category="service"
)
db_session.add_all([good1, good2, good3])
db_session.commit()
breakdown = ExtraGood.get_goods_by_category(project_id=project.id)
assert len(breakdown) == 2
# Find product category
product_cat = next((c for c in breakdown if c["category"] == "product"), None)
assert product_cat is not None
assert product_cat["total_amount"] == 250.0
assert product_cat["count"] == 2
# Find service category
service_cat = next((c for c in breakdown if c["category"] == "service"), None)
assert service_cat is not None
assert service_cat["total_amount"] == 200.0
assert service_cat["count"] == 1