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.

ConstantValue
MAX_TRANSACTION_AMOUNT50000.00
MIN_TRANSACTION_AMOUNT0.01
MAX_PAYMENT_AMOUNT50000.00
MAX_REFUND_AMOUNT50000.00
MAX_STORE_CREDIT_AMOUNT10000.00
MAX_CASH_DRAWER_AMOUNT5000.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, but validate_amount replaces a zero minimum with MIN_TRANSACTION_AMOUNT (0.01) because Decimal('0.00') is falsy in the min_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.

Was this page helpful?