Source code for stoqlib.lib.validators

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4

##
## Copyright (C) 2005, 2006 Async Open Source <http://www.async.com.br>
## All rights reserved
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., or visit: http://www.gnu.org/.
##
"""Validators for stoq applications"""

from decimal import Decimal
import datetime
import os
import re

from kiwi.datatypes import converter, ValidationError

from stoqlib.lib.formatters import raw_phone_number, raw_postal_code
from stoqlib.lib.translation import stoqlib_gettext

_ = stoqlib_gettext

POSTAL_CODE_CHAR_LEN = 8

#
# Date validatores
#


[docs]def is_date_in_interval(date, start_date, end_date): """Check if a certain date is in an interval. The function accepts None values for start_date and end_date and, in this case, return True if there is no interval to check.""" assert isinstance(date, datetime.datetime) q1 = q2 = True if start_date: assert isinstance(start_date, datetime.datetime) q1 = date >= start_date if end_date: assert isinstance(end_date, datetime.datetime) q2 = date <= end_date return q1 and q2
# # Phone number validators #
[docs]def validate_phone_number(phone_number): if not isinstance(phone_number, basestring): return False phone_number = raw_phone_number(phone_number) if phone_number and phone_number[0] == '0': phone_number = phone_number[1:] return len(phone_number) in range(7, 12)
# # Adress validators #
[docs]def validate_postal_code(postal_code): if not postal_code: return False return len(raw_postal_code(postal_code)) == POSTAL_CODE_CHAR_LEN
[docs]def validate_area_code(code): """Validates Brazilian area codes""" if isinstance(code, basestring): try: code = converter.from_string(int, code) except ValidationError: return False # Valid brazilian codes are on the range of 10-99 return 10 <= code <= 99
# # Document Validators #
[docs]def validate_cpf(cpf): cpf = ''.join(re.findall(r'\d', str(cpf))) if not cpf or len(cpf) < 11: return False # FIXME: use modulo11 from algorithms.py # With the first 9 digits, we calculate the last two digits (verifiers) new = map(int, cpf)[:9] while len(new) < 11: s = sum([(len(new) + 1 - i) * v for i, v in enumerate(new)]) % 11 if s > 1: verifier_digit = 11 - s else: verifier_digit = 0 if cpf[len(new)] != str(verifier_digit): return False else: new.append(verifier_digit) return True
[docs]def validate_cnpj(cnpj): """Validates a cnpj. :param cnpj: the cnpj to validate. Can be a string or number. If it's a string, only the digits will be used. """ cnpj = ''.join(re.findall(r'\d', str(cnpj))) if not cnpj or len(cnpj) != 14: return False # FIXME: use modulo11 from algorithms.py # With the first 12 digts, we calculate the last 2 digits (verifiers) new = map(int, cnpj)[:12] verification_base = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] while len(new) < 14: s = sum([x * y for (x, y) in zip(new, verification_base)]) % 11 if s > 1: verifier_digit = 11 - s else: verifier_digit = 0 if cnpj[len(new)] != str(verifier_digit): return False else: new.append(verifier_digit) verification_base.insert(0, 6) return True
[docs]def validate_cfop(cfop): """Validates C.F.O.P. code Valid C.F.O.P. format: '9.999', where 9 is any digit in 0-9. """ if not isinstance(cfop, basestring): return False if not '.' in cfop: return False first_part, last_part = cfop.split('.') if not first_part.isdigit() or not last_part.isdigit(): return False if not len(first_part) == 1 or not len(last_part) == 3: return False return True
# # Misc validators # def _validate_type(type_, value): if isinstance(value, basestring): try: # Just converting to see if any errors are raised. converter.from_string(type_, value) except ValidationError: return False else: if not isinstance(value, type_): return False return True
[docs]def validate_int(value): """Validates an integer. Returns if the value is a valid integer, or, in case it's a string, if it can be converted to an integer. """ return _validate_type(int, value)
[docs]def validate_decimal(value): """Validates an Decimal. Returns if the value is a valid Decimal, or, in case it's a string, if it can be converted to an Decimal. """ return _validate_type(Decimal, value)
[docs]def validate_directory(path): """Find out if a directory exists""" return os.path.exists(os.path.expanduser(path))
[docs]def validate_percentage(value): """Se if a given value is a valid percentage. Works for int, float, Decimal and basestring (if it can be converted to Decimal). """ if isinstance(value, basestring): try: value = converter.from_string(Decimal, value) except ValidationError: return False return 0 <= value <= 100
[docs]def validate_email(value): """Try to validate an email address. """ exp = r"^[^@]+@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$" return re.match(exp, value) is not None
[docs]def validate_cst(cst): """Try to validate a CST to PIS/COFINS tax.""" valid_cst = [1, 2, 3, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 55, 56, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 98, 99] if cst in valid_cst: return True return False