""" Category Marshmallow Schema Validation and serialization schema for Category model. Handles input validation, data transformation, and JSON serialization. """ from marshmallow import Schema, fields, validate, validates, ValidationError import re class CategorySchema(Schema): """ Schema for Category model validation and serialization. Provides input validation for: - Name: Required, 1-100 characters, unique - Description: Optional text field - Color: Optional hex color code validation - is_active: Boolean field with default True """ # Fields with validation id = fields.Integer(dump_only=True) # Read-only field name = fields.String( required=True, validate=[ validate.Length(min=1, max=100, error="Name must be 1-100 characters"), validate.Regexp( r'^[a-zA-Z0-9\s\-_&]+$', error="Name can only contain letters, numbers, spaces, hyphens, underscores, and ampersands" ) ] ) description = fields.String( allow_none=True, validate=validate.Length(max=500, error="Description cannot exceed 500 characters") ) color = fields.String( allow_none=True, validate=validate.Length(equal=7, error="Color must be exactly 7 characters (e.g., #FF5733)") ) is_active = fields.Boolean(load_default=True) created_at = fields.DateTime(dump_only=True, format='iso') @validates('color') def validate_color(self, value, **kwargs): """Validate hex color format.""" if value is not None: # Check if it's a valid hex color code hex_pattern = r'^#[0-9A-Fa-f]{6}$' if not re.match(hex_pattern, value): raise ValidationError("Color must be a valid hex code (e.g., #FF5733)") class Meta: """Schema configuration.""" ordered = True # Preserve field order in output class CategoryCreateSchema(CategorySchema): """Schema for creating new categories.""" class Meta: """Schema configuration for creation.""" exclude = ('id', 'created_at') ordered = True class CategoryUpdateSchema(CategorySchema): """Schema for updating existing categories.""" # Make all fields optional for partial updates name = fields.String( required=False, validate=[ validate.Length(min=1, max=100, error="Name must be 1-100 characters"), validate.Regexp( r'^[a-zA-Z0-9\s\-_&]+$', error="Name can only contain letters, numbers, spaces, hyphens, underscores, and ampersands" ) ] ) class Meta: """Schema configuration for updates.""" exclude = ('id', 'created_at') ordered = True class CategoryListSchema(Schema): """Schema for category list with optional transaction count.""" id = fields.Integer() name = fields.String() description = fields.String(allow_none=True) color = fields.String(allow_none=True) is_active = fields.Boolean() created_at = fields.DateTime(format='iso') transaction_count = fields.Integer(allow_none=True) class Meta: """Schema configuration.""" ordered = True