-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement new types of key #1
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
from pixqrcode.model.merchant_account import MerchantAccount | ||
from pixqrcode.model.pix import Pix | ||
from pixqrcode.utils.crc16 import crc16 | ||
|
||
from pixqrcode.service.validate_pix import ValidatePix | ||
import re | ||
|
||
class GenerateCode: | ||
def __init__(self): | ||
|
@@ -11,7 +12,11 @@ def left_zero(self, text: str): | |
return str(len(text)).zfill(2) | ||
|
||
def generate(self, pix: Pix): | ||
return f"00020126360014{self.merchant.globally_unique_identifier}0114{pix.mobile}520400005303986540" \ | ||
valPix = ValidatePix(pix) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. O ValidatePix é chamado no init.py dentro do metodo is_valid() |
||
detect_type = valPix.detect_type_key | ||
code = detect_type() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tu pode instanciar a classe direto e já puxar o método não precisaria passar para dentro de outra variável. |
||
|
||
return f"00020126360014{self.merchant.globally_unique_identifier}{code}{pix.mobile}520400005303986540" \ | ||
f"{len(pix.amount.__str__())}{pix.amount.__str__()}5802{pix.country_code}59{self.left_zero(pix.name)}" \ | ||
f"{pix.name}60{self.left_zero(pix.city)}{pix.city}" \ | ||
f"62{str(len(pix.reference_label) + 4).zfill(2)}05{self.left_zero(pix.reference_label)}" \ | ||
|
@@ -22,4 +27,4 @@ def crc16code(self, query: str) -> str: | |
|
||
def format_code(self, pix: Pix): | ||
hash_payment = self.generate(pix) | ||
return f"{hash_payment}{self.crc16code(hash_payment).upper()[2:]}".strip() | ||
return f"{hash_payment}{self.crc16code(hash_payment).upper()[2:]}".strip() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,20 +47,85 @@ def reference_label(self): | |
else: | ||
self.pix.reference_label = FormatValues.texts_no_space(self.pix.reference_label) | ||
|
||
def mobile(self): | ||
if not self.pix.mobile: | ||
raise PixError("telefone nao informado") | ||
def validateCPF(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. o padrão para o nome dos métodos também segue como lowercase (snake_case). Mesmo CPF sendo "nome" o aconselhável é seguir como os demais métodos. |
||
cpf = self.pix.mobile | ||
cpf = re.sub('\D', '', cpf) | ||
|
||
numbers = [int(digit) for digit in cpf if digit.isdigit()] | ||
if len(numbers) != 11 or len(set(numbers)) == 1: | ||
return False | ||
|
||
sum_of_products = sum(a*b for a, b in zip(numbers[0:9], range(10, 1, -1))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A logica de validação de CPF ficou um pouco confusa sobre qual digito é. Coloque um comentário para ajudar a ler no futuro sobre qual é qual mais precisamente, vai ajudar bastante quando tu tem blocos de códigos parecidos |
||
expected_digit = (sum_of_products * 10 % 11) % 10 | ||
if numbers[9] != expected_digit: | ||
return False | ||
|
||
sum_of_products = sum(a*b for a, b in zip(numbers[0:10], range(11, 1, -1))) | ||
expected_digit = (sum_of_products * 10 % 11) % 10 | ||
if numbers[10] != expected_digit: | ||
return False | ||
|
||
return True | ||
|
||
""" | ||
Valida o tipo de chave e retorna o codigo de acordo com o BC | ||
""" | ||
def detect_type_key(self): | ||
key = self.pix.mobile | ||
regex = re.search(r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9]+\.[a-zA-Z\.a-zA-Z]{1,10}$', key) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. o nome da variável pode deixar confuso durante o uso ao longo do código, talvez ser mais especifico |
||
# 0111 - CPF | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Números mágicos nunca são bem vindos em códigos de produção. Nesse caso aqui tu poderia utilizar uma classe do tipo Enum para definir os nomes e valores Ex: EMAIL = 0125 |
||
# 0111 - CNPJ | ||
# 0125 - EMAIL | ||
# 0114 - Telefone | ||
|
||
code = "" | ||
if regex is None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No fluxo de validação da chave ele acaba realizando uma dupla função, Descobrir qual tipo de chave é se é email, cpf, cnpj ou telefone e validar a chave, isso torna o fluxo mais difícil de entender e tb com if um dentro do outro como é esse o caso aqui. Ai o que é interessante de se fazer, ter fluxos distintos para isso. Em um você Descobrir qual tipo de chave é e o segundo validar a chave com base no tipo se houver um match. Podendo assim ter vários métodos um para cada tipo de chave, e ai chamar um método que identifica o tipo de chave no validade (linha 14) e chama o método corresponde para aquele tipo de chave. |
||
key_numbers = re.sub('\D', '', key) | ||
if len(key_numbers) == 10: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. O pix não utiliza de números fixos para chaves (Até onde eu saiba), apenas telefones celulares por costume |
||
#valida se é um telefone fixo | ||
code = '0114' | ||
|
||
self.pix.mobile = FormatValues.mobile(self.pix.mobile) | ||
if not re.match(r'^.55[\d]{3}', self.pix.mobile): | ||
if not re.match(r'^55[\d]{3}', self.pix.mobile): | ||
self.pix.mobile = f"+55{self.pix.mobile}" | ||
if len(key_numbers) == 12: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Varios if verificam o mesmo valor |
||
#valida se é um telefone com DDI | ||
code = '0114' | ||
|
||
if len(key_numbers) == 13: | ||
#valida se é um celular com DDI | ||
code = '0114' | ||
|
||
elif self.validateCPF(): | ||
#valida se é um cpf com base nos calculos de digitos | ||
code = '0111' | ||
elif len(key_numbers) == 11: | ||
#se na ultima validacao nao retornou true é bem provavel que seja celular | ||
|
||
code = '0114' | ||
elif len(key_numbers) == 14: | ||
#verifica se é cnpj | ||
code = '0111' #creio que o codigo esteja errado, nao achei nada sobre | ||
else: | ||
self.pix.mobile = f"+{self.pix.mobile}" | ||
raise Exception("A chave informada não foi identificada") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Voltar o Exception aqui vai disparar um erro que não está padronizado para tratamento. Utilizar a classe PixError, ai quando houver um erro que precise ser reportado tu não corre o risco de parar o código simulando uma Exception genérica. |
||
else: | ||
# É email | ||
code = '0125' | ||
|
||
return code | ||
|
||
def mobile(self): | ||
if not self.pix.mobile: | ||
raise PixError("Chave nao informado") | ||
code = self.detect_type_key() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Em um debug do código, o método de detect_type_key executou duas vezes. Eu deduzo que isso não seja o comportamento espero |
||
if code == '0114': | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Evitar a utilização de números mágicos como esse ao longo do código. |
||
self.pix.mobile = FormatValues.mobile(self.pix.mobile) | ||
if not re.match(r'^.55[\d]{3}', self.pix.mobile): | ||
if not re.match(r'^55[\d]{3}', self.pix.mobile): | ||
self.pix.mobile = f"+55{self.pix.mobile}" | ||
else: | ||
self.pix.mobile = f"+{self.pix.mobile}" | ||
|
||
if 14 > len(self.pix.mobile) < 14: | ||
raise PixError("telefone curto ou longo") | ||
if 14 > len(self.pix.mobile) < 14: | ||
raise PixError("telefone curto ou longo") | ||
|
||
if not re.match(r'^.+55[\d]{3}', self.pix.mobile): | ||
raise PixError("telefone sem o DDD") | ||
if not re.match(r'^.+55[\d]{3}', self.pix.mobile): | ||
raise PixError("telefone sem o DDD") | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aqui seguir o padrão de ter lowercase (snake_case) para as variáveis dentro de funções