Core - Validators Documentation
Location: api/nextango/apps/core/validators.py
Last Updated: 2026-07-09
Overview
Core validators provide input sanitization against XSS and SQL-injection patterns, financial-amount validation, business-rule checks, and inventory-quantity validation. They raise django.core.exceptions.ValidationError (or the local subclasses SecurityValidationError and BusinessValidationError) rather than returning booleans, so callers use them inside try/except or let the exception propagate to the DRF exception handler documented in Exceptions.
InputSanitizer
Class methods for sanitizing untrusted text, identifiers, and email addresses.
sanitize_text(text, max_length=500, allow_html=False, field_name='field')
Strips control characters, checks the input against a set of XSS and SQL-injection regex patterns (raising SecurityValidationError if matched), strips <>"' characters when allow_html is False, and normalizes whitespace. Raises ValidationError if text is not a string or exceeds max_length.
sanitize_identifier(identifier, field_name='identifier')
Restricts a string to [a-zA-Z0-9_-], max 100 characters. Used for IDs and codes rather than free text.
sanitize_email(email)
Lowercases and trims the input, enforces a 254-character limit, and validates against a basic email regex.
from nextango.apps.core.validators import InputSanitizer
clean_name = InputSanitizer.sanitize_text(request.data['name'], max_length=255)
clean_code = InputSanitizer.sanitize_identifier(request.data['code'])
clean_email = InputSanitizer.sanitize_email(request.data['email'])
FinancialValidator
Class methods for validating and normalizing monetary amounts to Decimal.
| Constant | Value |
|---|---|
MAX_TRANSACTION_AMOUNT | 50000.00 |
MIN_TRANSACTION_AMOUNT | 0.01 |
MAX_PAYMENT_AMOUNT | 50000.00 |
MAX_REFUND_AMOUNT | 50000.00 |
MAX_STORE_CREDIT_AMOUNT | 10000.00 |
MAX_CASH_DRAWER_AMOUNT | 5000.00 |
validate_amount(amount, min_amount=None, max_amount=None, field_name='amount')
Converts a string, float, or Decimal to Decimal, stripping currency symbols and whitespace from string input. Rejects more than 2 decimal places, and enforces the min_amount/max_amount bounds (defaulting to MIN_TRANSACTION_AMOUNT/MAX_TRANSACTION_AMOUNT). Raises ValidationError on any failure.
Domain-specific wrappers
validate_payment_amount(amount): bounds[MIN_TRANSACTION_AMOUNT, MAX_PAYMENT_AMOUNT]validate_refund_amount(amount): effective bounds[0.01, MAX_REFUND_AMOUNT]. The wrapper passes a 0.00 floor, butvalidate_amountreplaces a zero minimum withMIN_TRANSACTION_AMOUNT(0.01) becauseDecimal('0.00')is falsy in themin_amount or ...fallback, so a 0.00 refund is rejected.validate_store_credit_amount(amount): bounds[0.01, MAX_STORE_CREDIT_AMOUNT]validate_cash_amount(amount): effective bounds[0.01, MAX_CASH_DRAWER_AMOUNT]. Same zero-floor replacement as refunds; a 0.00 amount is rejected.
from nextango.apps.core.validators import FinancialValidator
amount = FinancialValidator.validate_payment_amount('49.99')
BusinessRuleValidator
Class methods encoding operational business rules.
validate_store_operational_hours(store, operation_time=None)
Raises BusinessValidationError if operation_time (default: now) falls outside 7:00 AM to 11:00 PM, or if store.is_active is False. This is a fixed business-hours window, not store-specific operating hours.
validate_employee_permissions(employee, operation, amount=None)
Raises BusinessValidationError if the employee's status is not 'active'. For void, refund, or discount operations over $1000, requires the employee to have a manager attribute or a role. For void, cash_out, till_count, or employee_override, requires employee.role.name to contain 'supervisor'.
validate_transaction_integrity(transaction, operation, new_amount=None)
Validates that transaction.status is compatible with the requested operation (add_item, remove_item, payment, complete, void, refund). Blocks voiding a transaction more than 24 hours old. For payment operations, rejects a new_amount exceeding transaction.payment_balance by more than one cent.
InventoryValidator
validate_quantity(quantity, field_name='quantity')
Coerces to int, requires a positive value not exceeding 1000. Raises ValidationError otherwise.
validate_product_availability(product_variant, requested_quantity, store=None)
Raises BusinessValidationError if requested_quantity <= 0. Without a store, logs a warning and returns True (no store-scoped inventory check possible). With a store, looks up the matching InventoryLevel (by variant_sku, product, store, is_active=True) and compares requested_quantity against inventory_level.stock_available, raising BusinessValidationError if insufficient or if no matching InventoryLevel row exists.
Module-level functions
validate_json_data(data, allowed_keys, field_name='data')
Rejects a non-dict data, rejects any key not in allowed_keys, and confirms the payload is JSON-serializable.
validate_enum_choice(value, choices, field_name='field')
Requires value to be a string present in choices.