diff --git a/.gitignore b/.gitignore index 412016a..5780dee 100644 --- a/.gitignore +++ b/.gitignore @@ -153,10 +153,3 @@ dmypy.json # Cython debug symbols cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/common/util.py b/common/util.py new file mode 100644 index 0000000..8e52e85 --- /dev/null +++ b/common/util.py @@ -0,0 +1,35 @@ +import re + + +class CommonsUtil: + + ALPHA_PATTERN = "[A-Za-záàâãéèêíïóôõöúçñÁÀÂÃÉÈÍÏÓÔÕÖÚÇÑ\\-_\\s]+$" + + ALPHA_NUMERIC_PATTERN = "[A-Za-z0-9.-_]+$" + + ALPHA_NUMERIC_CHARACTER_PATTERN = "[A-Za-z0-9_À-ÿ.-_\\s]+$" + + NUMERIC_PATTERN = "[0-9]+$" + + PHONE_NUMERIC_PATTERN = "([0-9]{2})?([0-9]{2})([0-9]{4,5})([0-9]{4})" + + def __init__(self): + pass + + def remove_characters(self, text: str) -> str: + return re.sub("[^0-9]", "", text) + + def find_numbers(self, text: str): + return re.findall(r"[0-9]+", text) + + def is_alpha_pattern(self, text: str): + return re.match(self.ALPHA_PATTERN, text) + + def is_numeric_pattern(self, text: str): + return re.match(self.NUMERIC_PATTERN, text) + + def is_alpha_numeric_character_pattern(self, text: str): + return re.match(self.ALPHA_NUMERIC_CHARACTER_PATTERN, text) + + def is_phone_pattern(self, text: str): + return re.match(self.PHONE_NUMERIC_PATTERN, text) diff --git a/pacientes/forms.py b/pacientes/forms.py index f7734ea..5eab260 100644 --- a/pacientes/forms.py +++ b/pacientes/forms.py @@ -1,8 +1,7 @@ -from tkinter import Widget from django import forms from .utils import AGENDAMENTO_FIXO_CHOICES, GENERO_CHOICES from .models import Paciente -import re +from common.util import CommonsUtil from django.core.validators import ( MinLengthValidator, @@ -12,56 +11,21 @@ from datetime import datetime -class PacienteForm(forms.ModelForm): - - # nome = forms.CharField( - # validators=[ - # MinLengthValidator( - # 3, "Limite mínimo de 3 caracteres permitido para campo Nome" - # ), - # MaxLengthValidator( - # 30, - # message="Limite máximo de 30 caracteres permitido para campo Nome", - # ), - # RegexValidator( - # regex=r"^([a-zA-Zà-úÀ-Ú]\s)+$", - # message="Informe apenas texto para campo Nome", - # ), - # ], - # required=False, - # max_length=30, - # widget=forms.TextInput( - # attrs={ - # "placeholder": "olá papai", - # "name": "nome", - # "id": "nome", - # "class": "", - # } - # ), - # ) +class PacienteForm(forms.ModelForm, CommonsUtil): nome = forms.CharField( label="Nome", - max_length=30, + max_length=60, required=False, widget=forms.TextInput( - attrs={"name": "nome", "id": "nome", "autocomplete": "off"} + attrs={ + "name": "nome", + "id": "nome", + "autocomplete": "off", + } ), ) - # data_de_nascimento = forms.DateField( - # label="Data de Nascimento", - # input_formats=("%m/%d/%Y"), - # required=False, - # widget=forms.DateInput( - # attrs={ - # "type": "date", - # "name": "dataNascimento", - # "id": "dataNascimento", - # "autocomplete": "off", - # } - # ), - # ) data_de_nascimento = forms.DateField( label="Data de Nascimento", required=False, @@ -76,16 +40,19 @@ class PacienteForm(forms.ModelForm): }, ), ) + genero = forms.ChoiceField( + label="Gênero", required=False, widget=forms.RadioSelect(), choices=GENERO_CHOICES, ) - cartao_sus = forms.IntegerField( + cartao_sus = forms.CharField( label="Cartão SUS", + max_length=15, required=False, - widget=forms.NumberInput( + widget=forms.TextInput( attrs={ "name": "cartaoSUS", "id": "cartaoSUS", @@ -100,12 +67,11 @@ class PacienteForm(forms.ModelForm): required=False, choices=AGENDAMENTO_FIXO_CHOICES, widget=forms.RadioSelect(), - initial=2, ) telefone = forms.CharField( label="Telefone", - max_length=30, + max_length=18, required=False, widget=forms.TextInput( attrs={ @@ -119,31 +85,42 @@ class PacienteForm(forms.ModelForm): rua = forms.CharField( label="Rua", - max_length=50, + max_length=60, required=False, widget=forms.TextInput( attrs={"name": "rua", "id": "rua", "autocomplete": "off"} ), ) - numero = forms.IntegerField( + numero = forms.CharField( label="Número", + max_length=7, required=False, - widget=forms.NumberInput(attrs={"name": "numero", "id": "numero"}), + widget=forms.TextInput( + attrs={ + "name": "numero", + "id": "numero", + "autocomplete": "off", + } + ), ) complemento = forms.CharField( label="Complemento", - max_length=40, + max_length=60, required=False, widget=forms.TextInput( - attrs={"name": "complemento", "id": "complemento", "autocomplete": "off"} + attrs={ + "name": "complemento", + "id": "complemento", + "autocomplete": "off", + } ), ) ponto_referencia = forms.CharField( label="Ponto de Referência", - max_length=40, + max_length=60, required=False, widget=forms.TextInput( attrs={ @@ -154,213 +131,6 @@ class PacienteForm(forms.ModelForm): ), ) - # nome = ( - # forms.CharField( - # validators=[ - # MinLengthValidator( - # 3, "Limite mínimo de 3 caracteres permitido para campo Nome" - # ), - # MaxLengthValidator( - # 30, - # message="Limite máximo de 30 caracteres permitido para campo Nome", - # ), - # RegexValidator( - # regex=r"^([a-zA-Zà-úÀ-Ú]\s)+$", - # message="Informe apenas texto para campo Nome", - # ), - # ], - # max_length=30, - # required=True, - # widget=forms.TextInput( - # attrs={ - # "placeholder": "* Nome", - # "class": "form-text-input", - # "name": "nome", - # "id": "nome", - # } - # ), - # ), - # ) - - # sobre_nome = ( - # forms.CharField( - # validators=[ - # MinLengthValidator(3, "Limite mínimo de 3 caracteres"), - # MaxLengthValidator( - # 60, - # message="Limite máximo de 30 caracteres", - # ), - # RegexValidator( - # regex=r"^([a-zA-Zà-úÀ-Ú]\s)+$", - # message="Formato texto inválido", - # ), - # ], - # max_length=60, - # required=True, - # widget=forms.TextInput( - # attrs={ - # "placeholder": "* Sobre nome", - # "class": "form-text-input", - # "name": "sobreNome", - # "id": "sobreNome", - # } - # ), - # ), - # ) - - # # '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2024-01-15', '01/15/2024', '01/15/24' - # data_de_nascimento = ( - # forms.DateField( - # required=True, - # widget=forms.DateInput( - # format="%m/%d/%Y", - # attrs={ - # "type": "date", - # "placeholder": "* dd/mm/yyyy", - # "class": "form-text-input", - # "name": "dataNascimento", - # "id": "dataNascimento", - # }, - # ), - # error_messages={"invalid": "Formato data inválido"}, - # ), - # ) - - # genero = forms.ChoiceField(choices=GENERO_CHOICES, widget=forms.RadioSelect()) - - # cartao_sus = forms.CharField() - - # telefone = ( - # forms.CharField( - # validators=[ - # RegexValidator( - # regex=r"(\([0-9]{2}\))\s([9]{1})?([0-9]{4})-([0-9]{4})", - # message="Formato inválido", - # ), - # ], - # max_length=15, - # required=True, - # widget=forms.TextInput( - # attrs={ - # "type": "tel", - # "placeholder": "* (99) 9999-9999", - # "class": "form-text-input", - # "name": "telefone", - # "id": "telefone", - # } - # ), - # ), - # ) - - # rua = ( - # forms.CharField( - # validators=[ - # MinLengthValidator(5, "Limite mínimo de 5 caracteres"), - # MaxLengthValidator( - # 80, - # message="Limite máximo de 80 caracteres", - # ), - # RegexValidator( - # regex=r"^([a-zA-Zà-úÀ-Ú0-9]|-|_|.|º|\s)+$", - # message="Formato texto inválido", - # ), - # ], - # max_length=60, - # required=True, - # widget=forms.TextInput( - # attrs={ - # "placeholder": "* Sobre nome", - # "class": "form-text-input", - # "name": "sobreNome", - # "id": "sobreNome", - # } - # ), - # ), - # ) - - # numero = ( - # forms.IntegerField( - # required=True, - # widget=forms.NumberInput( - # attrs={ - # "placeholder": "* Número", - # "class": "form-text-input", - # "name": "sobreNome", - # "id": "sobreNome", - # } - # ), - # error_messages={"invalid": "Campo necessário"}, - # ), - # ) - - # complemento = ( - # forms.CharField( - # validators=[ - # MinLengthValidator(5, "Limite mínimo de 5 caracteres"), - # MaxLengthValidator( - # 60, - # message="Limite máximo de 60 caracteres", - # ), - # RegexValidator( - # regex=r"[^A-Za-z0-9\\s]+", - # message="Formato texto inválido", - # ), - # ], - # max_length=60, - # required=True, - # widget=forms.TextInput( - # attrs={ - # "placeholder": "Sobre nome", - # "class": "form-text-input", - # "name": "sobreNome", - # "id": "sobreNome", - # } - # ), - # ), - # ) - - # ponto_referencia = ( - # forms.CharField( - # validators=[ - # RegexValidator( - # regex=r"^([a-zA-Zà-úÀ-Ú]\s)+$", - # message="Formato texto inválido", - # ), - # ], - # max_length=15, - # required=True, - # widget=forms.TextInput( - # attrs={ - # "placeholder": "", - # "class": "form-text-input", - # "name": "pontoReferencia", - # "id": "pontoReferencia", - # } - # ), - # ), - # ) - - # def clean(self): - - # super(PacienteForm, self).clean() - - # nome = forms.CharField( - # validators=[ - # # MinLengthValidator( - # # 3, "Limite mínimo de 3 caracteres permitido para campo Nome" - # # ), - # MaxLengthValidator( - # 30, - # message="Limite máximo de 30 caracteres permitido para campo Nome", - # ), - # RegexValidator( - # regex=r"^([a-zA-Zà-úÀ-Ú]\s)+$", - # message="Informe apenas texto para campo Nome", - # ), - # ], - # error_messages={"required": "Campo necessário"}, - # ) - class Meta: model = Paciente @@ -373,14 +143,14 @@ def clean(self): super().clean() - valid_alpha = "[A-Za-záàâãéèêíïóôõöúçñÁÀÂÃÉÈÍÏÓÔÕÖÚÇÑ\\-_\\s]+$" - - valid_alpha_numeric = "[A-Za-z0-9_À-ÿ.-_\\s]+$" + errors = {} nome = self.cleaned_data.get("nome") data_de_nascimento = self.cleaned_data.get("data_de_nascimento") + genero = self.cleaned_data.get("genero") + cartao_sus = self.cleaned_data.get("cartao_sus") agendamento_fixo = self.cleaned_data.get("agendamento_fixo") @@ -397,38 +167,118 @@ def clean(self): # NOME if not nome: - raise forms.ValidationError( - {"nome": "Campo obrigatório, deve conter de 5 a 60 caracteres"} - ) + errors["nome"] = "Campo nome obrigatório" - if len(nome) < 5 or len(nome) > 60: - raise forms.ValidationError( - {"nome": "Campo deve conter de 5 a 60 caracteres"} - ) + if nome: - if re.match(valid_alpha, nome) is None: - raise forms.ValidationError( - {"nome": "Campo inválido, informe apenas texto"} - ) + if len(nome) < 5 or len(nome) > 60: + errors["nome"] = ( + "Certifique-se de que o valor tenha entre 5 a 60 caracteres" + ) + + elif not self.is_alpha_pattern(nome): + errors["nome"] = ( + "Certifique-se de que o valor tenha apenas caracteres texto" + ) # DATA_DE_NASCIMENTO if not data_de_nascimento: - raise forms.ValidationError({"data_de_nascimento": "Campo obrigatório"}) + errors["data_de_nascimento"] = "Campo data de nascimento obrigatório" + + if data_de_nascimento: + + ano = int(datetime.now().year - (data_de_nascimento.year)) - ano = int(datetime.now().year - (data_de_nascimento.year)) + if ano == -1 or ano > 100: + errors["data_de_nascimento"] = "Informe uma data de nascimento válida" - if ano == -1 or ano > 100: - raise forms.ValidationError( - {"data_de_nascimento": "Informe uma data válida"} - ) + if not genero: + errors["genero"] = "Campo gênero obrigatório" # CARTAO_SUS if not cartao_sus: - raise forms.ValidationError({"cartao_sus": "Campo obrigatório"}) + errors["cartao_sus"] = "Campo cartão SUS obrigatório" - if not cartao_sus: - raise forms.ValidationError({"cartao_sus": "Campo obrigatório"}) + if cartao_sus: - # CARTAO_SUS + if len(cartao_sus) != 15: + errors["cartao_sus"] = ( + "Campo cartão SUS deve possuir um tamanho de 15 dígitos" + ) + + elif not self.is_numeric_pattern(cartao_sus): + errors["cartao_sus"] = ( + "Formato de campo inválido para cartão SUS, informe apenas números" + ) + + if not agendamento_fixo: + errors["agendamento_fixo"] = "Selecione uma opção para agendamento fixo" + + if not telefone: + errors["telefone"] = "Campo telefone obrigatório" + + if telefone: + + if len(self.remove_characters(telefone)) != 13 or not self.is_phone_pattern( + self.remove_characters(telefone) + ): + errors["telefone"] = ( + "Certifique-se de que o número de telefone esteja correto" + ) + + if not rua: + errors["rua"] = "Campo rua obrigatório" + + if rua: + + if len(rua) < 5 or len(rua) > 60: + errors["rua"] = ( + "Certifique-se de que o valor tenha entre 5 a 60 caracteres" + ) + + elif not self.is_alpha_numeric_character_pattern(rua): + errors["rua"] = ( + "Certifique-se de que o valor tenha apenas caracteres texto" + ) + + if not numero: + errors["numero"] = "Campo número obrigatório" + + if numero: + + if len(numero) > 7: + errors["numero"] = ( + "Certifique-se de que o valor tenha no máximo 7 caracteres" + ) + + elif not self.find_numbers(numero): + errors["numero"] = "Número de endereço obrigatório" + + if complemento: + + if len(complemento) < 5 or len(complemento) > 60: + errors["complemento"] = ( + "Certifique-se de que o valor tenha entre 5 a 60 caracteres" + ) + + elif not self.is_alpha_numeric_character_pattern(complemento): + errors["complemento"] = ( + "Certifique-se de que o valor tenha apenas caracteres texto" + ) + + if ponto_referencia: + + if len(ponto_referencia) < 5 or len(ponto_referencia) > 60: + errors["ponto_referencia"] = ( + "Certifique-se de que o valor tenha entre 5 a 60 caracteres" + ) + + elif not self.is_alpha_numeric_character_pattern(ponto_referencia): + errors["ponto_referencia"] = ( + "Certifique-se de que o valor tenha apenas caracteres texto" + ) + + if errors: + raise forms.ValidationError(errors) return self.cleaned_data diff --git a/pacientes/migrations/0016_alter_paciente_complemento_alter_paciente_numero_and_more.py b/pacientes/migrations/0016_alter_paciente_complemento_alter_paciente_numero_and_more.py new file mode 100644 index 0000000..990afeb --- /dev/null +++ b/pacientes/migrations/0016_alter_paciente_complemento_alter_paciente_numero_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.0.4 on 2024-04-30 14:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pacientes", "0015_alter_paciente_cartao_sus_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="paciente", + name="complemento", + field=models.CharField(max_length=60), + ), + migrations.AlterField( + model_name="paciente", + name="numero", + field=models.CharField(max_length=5), + ), + migrations.AlterField( + model_name="paciente", + name="ponto_referencia", + field=models.CharField(max_length=60), + ), + migrations.AlterField( + model_name="paciente", + name="rua", + field=models.CharField(max_length=60), + ), + migrations.AlterField( + model_name="paciente", + name="telefone", + field=models.CharField(max_length=13), + ), + ] diff --git a/pacientes/migrations/0017_alter_paciente_agendamento_fixo.py b/pacientes/migrations/0017_alter_paciente_agendamento_fixo.py new file mode 100644 index 0000000..18e5a02 --- /dev/null +++ b/pacientes/migrations/0017_alter_paciente_agendamento_fixo.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.4 on 2024-04-30 14:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pacientes", "0016_alter_paciente_complemento_alter_paciente_numero_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="paciente", + name="agendamento_fixo", + field=models.IntegerField(choices=[(1, "SIM"), (2, "Não")]), + ), + ] diff --git a/pacientes/migrations/0018_alter_paciente_numero.py b/pacientes/migrations/0018_alter_paciente_numero.py new file mode 100644 index 0000000..770dbd3 --- /dev/null +++ b/pacientes/migrations/0018_alter_paciente_numero.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.4 on 2024-04-30 18:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pacientes", "0017_alter_paciente_agendamento_fixo"), + ] + + operations = [ + migrations.AlterField( + model_name="paciente", + name="numero", + field=models.CharField(max_length=7), + ), + ] diff --git a/pacientes/models.py b/pacientes/models.py index c0a648f..b613687 100644 --- a/pacientes/models.py +++ b/pacientes/models.py @@ -17,20 +17,17 @@ class Status(models.IntegerChoices): cartao_sus = models.CharField(max_length=15, unique=True) - agendamento_fixo = models.IntegerField( - choices=AGENDAMENTO_FIXO_CHOICES, - default=Status.ATIVO, - ) + agendamento_fixo = models.IntegerField(choices=AGENDAMENTO_FIXO_CHOICES) - telefone = models.CharField(max_length=18) + telefone = models.CharField(max_length=13) - rua = models.CharField(max_length=50) + rua = models.CharField(max_length=60) - numero = models.IntegerField() + numero = models.CharField(max_length=7) - complemento = models.CharField(max_length=40) + complemento = models.CharField(max_length=60) - ponto_referencia = models.CharField(max_length=40) + ponto_referencia = models.CharField(max_length=60) status = models.IntegerField(default=Status.ATIVO) diff --git a/pacientes/templates/formulario_paciente.html b/pacientes/templates/formulario_paciente.html index 571df96..6c8bd9d 100644 --- a/pacientes/templates/formulario_paciente.html +++ b/pacientes/templates/formulario_paciente.html @@ -25,23 +25,21 @@