diff --git a/01 - Estrutura de dados/desafio.py b/01 - Estrutura de dados/desafio.py index 2ce9ef27..82e04c68 100644 --- a/01 - Estrutura de dados/desafio.py +++ b/01 - Estrutura de dados/desafio.py @@ -1,151 +1,311 @@ +from abc import ABC, abstractproperty +from datetime import datetime import textwrap +class Cliente: + def __init__(self, endereco): + self.endereco = endereco + self.contas = [] -def menu(): - menu = """\n - ================ MENU ================ - [d]\tDepositar - [s]\tSacar - [e]\tExtrato - [nc]\tNova conta - [lc]\tListar contas - [nu]\tNovo usuário - [q]\tSair - => """ - return input(textwrap.dedent(menu)) + def realizar_transacao(self, conta, transacao): + transacao.registrar(conta) + def adicionar_conta(self, conta): + self.contas.append(conta) -def depositar(saldo, valor, extrato, /): - if valor > 0: - saldo += valor - extrato += f"Depósito:\tR$ {valor:.2f}\n" - print("\n=== Depósito realizado com sucesso! ===") - else: - print("\n@@@ Operação falhou! O valor informado é inválido. @@@") - return saldo, extrato +class PessoaFisica(Cliente): + def __init__(self, nome, data_nascimento, cpf, endereco): + super().__init__(endereco) + self.nome = nome + self.data_nascimento = data_nascimento + self.cpf = cpf -def sacar(*, saldo, valor, extrato, limite, numero_saques, limite_saques): - excedeu_saldo = valor > saldo - excedeu_limite = valor > limite - excedeu_saques = numero_saques >= limite_saques +class Conta: + def __init__(self, numero, cliente): + self._saldo = 0 + self._numero = numero + self._agencia = "0001" + self._cliente = cliente + self._historico = Historico() - if excedeu_saldo: - print("\n@@@ Operação falhou! Você não tem saldo suficiente. @@@") + @classmethod + def nova_conta(cls, cliente, numero): + return cls(numero, cliente) - elif excedeu_limite: - print("\n@@@ Operação falhou! O valor do saque excede o limite. @@@") + @property + def saldo(self): + return self._saldo - elif excedeu_saques: - print("\n@@@ Operação falhou! Número máximo de saques excedido. @@@") + @property + def numero(self): + return self._numero - elif valor > 0: - saldo -= valor - extrato += f"Saque:\t\tR$ {valor:.2f}\n" - numero_saques += 1 - print("\n=== Saque realizado com sucesso! ===") + @property + def agencia(self): + return self._agencia - else: - print("\n@@@ Operação falhou! O valor informado é inválido. @@@") + @property + def historico(self): + return self._historico + + def sacar(self, valor): + saldo = self.saldo + excedeu_saldo = valor > saldo + + if excedeu_saldo: + print("Operação falhou. Você não tem saldo suficiente.") + elif valor > 0: + self._saldo -= valor + print("Saque realizado com sucesso.") + return True + else: + print("Operação falhou. O valor informado é inválido.") + return False + + def depositar(self, valor): + if valor > 0: + self._saldo += valor + print("Depósito realizado com sucesso") + return True + else: + print("Operação falhou. Valor informado é inválido") + return False + + +class ContaCorrente(Conta): + def __init__(self, numero, cliente, limite=500, limite_saques=3): + super().__init__(numero, cliente) + self.limite = limite + self.limite_saques = limite_saques + + def sacar(self, valor): + numero_saques = len( + [transacao for transacao in self.historico.transacoes + if transacao["tipo"] == Saque.__name__] + ) + + excedeu_limite = valor > self.limite + excedeu_saques = numero_saques >= self.limite_saques + + if excedeu_limite: + print("Operação falhou. O valor do saque excede o limite") + elif excedeu_saques: + print("Operação falhou. O número máximo de saques foi excedido") + else: + return super().sacar(valor) + return False + + def __str__(self): + return f""" + Agência:\t{self.agencia} + C/C:\t\t{self.numero} + Titular:\t{self._cliente.nome} + """ + + +class Historico: + def __init__(self): + self._transacoes = [] - return saldo, extrato + @property + def transacoes(self): + return self._transacoes + def adicionar_transacoes(self, transacao): + self._transacoes.append( + { + "tipo": transacao.__class__.__name__, + "valor": transacao.valor, + "data": datetime.now().strftime("%d-%m-%Y %H:%M:%S"), + } + ) -def exibir_extrato(saldo, /, *, extrato): - print("\n================ EXTRATO ================") - print("Não foram realizadas movimentações." if not extrato else extrato) - print(f"\nSaldo:\t\tR$ {saldo:.2f}") - print("==========================================") +class Transacao(ABC): + @property + @abstractproperty + def valor(self): + pass -def criar_usuario(usuarios): - cpf = input("Informe o CPF (somente número): ") - usuario = filtrar_usuario(cpf, usuarios) + @abstractproperty + def registrar(self, conta): + pass - if usuario: - print("\n@@@ Já existe usuário com esse CPF! @@@") + +class Saque(Transacao): + def __init__(self, valor): + self._valor = valor + + @property + def valor(self): + return self._valor + + def registrar(self, conta): + sucesso_transacao = conta.sacar(self.valor) + if sucesso_transacao: + conta.historico.adicionar_transacoes(self) + + +class Deposito(Transacao): + def __init__(self, valor): + self._valor = valor + + @property + def valor(self): + return self._valor + + def registrar(self, conta): + sucesso_transacao = conta.depositar(self.valor) + if sucesso_transacao: + conta.historico.adicionar_transacoes(self) + + +def menu(): + menu = """ + ======================== MENU ======================== + [d] Depositar + [s] Sacar + [e] Extrato + [nc] Nova Conta + [lc] Listar Contas + [nu] Novo Usuário + [q] Sair + + => """ + return input(textwrap.dedent(menu)) + + +def criar_cliente(clientes): + cpf = input("Informe o CPF do cliente: ") + cliente = filtrar_cliente(cpf, clientes) + + if cliente: + print("Já existe cliente com esse CPF") return nome = input("Informe o nome completo: ") data_nascimento = input("Informe a data de nascimento (dd-mm-aaaa): ") endereco = input("Informe o endereço (logradouro, nro - bairro - cidade/sigla estado): ") - usuarios.append({"nome": nome, "data_nascimento": data_nascimento, "cpf": cpf, "endereco": endereco}) + cliente = PessoaFisica(nome=nome, data_nascimento=data_nascimento, cpf=cpf, endereco=endereco) + + clientes.append(cliente) + print("\nCliente criado com sucesso") + - print("=== Usuário criado com sucesso! ===") +def depositar(clientes): + cpf = input("Informe o CPF do cliente: ") + cliente = filtrar_cliente(cpf, clientes) + if not cliente: + print("Cliente não encontrado") + return + + valor = float(input("Informe o valor do depósito: ")) + transacao = Deposito(valor) + + conta = recuperar_conta_cliente(cliente) + if not conta: + return + + cliente.realizar_transacao(conta, transacao) + + +def filtrar_cliente(cpf, clientes): + clientes_filtrados = [cliente for cliente in clientes if cliente.cpf == cpf] + return clientes_filtrados[0] if clientes_filtrados else None + + +def sacar(clientes): + cpf = input("Informe o CPF do cliente: ") + cliente = filtrar_cliente(cpf, clientes) + + if not cliente: + print("Cliente não encontrado") + return + + valor = float(input("Informe o valor do saque: ")) + transacao = Saque(valor) + + conta = recuperar_conta_cliente(cliente) + if not conta: + return + + cliente.realizar_transacao(conta, transacao) + + +def exibir_extrato(clientes): + cpf = input("Informe o CPF do cliente: ") + cliente = filtrar_cliente(cpf, clientes) + + if not cliente: + print("Cliente não encontrado") + return + + conta = recuperar_conta_cliente(cliente) + if not conta: + return -def filtrar_usuario(cpf, usuarios): - usuarios_filtrados = [usuario for usuario in usuarios if usuario["cpf"] == cpf] - return usuarios_filtrados[0] if usuarios_filtrados else None + print("\n================= EXTRATO =================") + transacoes = conta.historico.transacoes + extrato = "" + if not transacoes: + extrato = "Não foram realizadas movimentações." + else: + for transacao in transacoes: + extrato += f"\n{transacao['tipo']}:\n\tR$ {transacao['valor']:.2f} em {transacao['data']}" -def criar_conta(agencia, numero_conta, usuarios): - cpf = input("Informe o CPF do usuário: ") - usuario = filtrar_usuario(cpf, usuarios) + print(extrato) + print(f"\nSaldo:\n\tR$ {conta.saldo: .2f}") + print("================================================") + + +def criar_conta(numero_conta, clientes, contas): + cpf = input("Informe o CPF do cliente: ") + cliente = filtrar_cliente(cpf, clientes) + + if not cliente: + print("Cliente não encontrado") + return - if usuario: - print("\n=== Conta criada com sucesso! ===") - return {"agencia": agencia, "numero_conta": numero_conta, "usuario": usuario} + conta = ContaCorrente.nova_conta(cliente=cliente, numero=numero_conta) + contas.append(conta) + cliente.adicionar_conta(conta) - print("\n@@@ Usuário não encontrado, fluxo de criação de conta encerrado! @@@") + print("\nConta criada com sucesso") def listar_contas(contas): for conta in contas: - linha = f"""\ - Agência:\t{conta['agencia']} - C/C:\t\t{conta['numero_conta']} - Titular:\t{conta['usuario']['nome']} - """ print("=" * 100) - print(textwrap.dedent(linha)) + print(textwrap.dedent(str(conta))) def main(): - LIMITE_SAQUES = 3 - AGENCIA = "0001" - - saldo = 0 - limite = 500 - extrato = "" - numero_saques = 0 - usuarios = [] + clientes = [] contas = [] while True: opcao = menu() if opcao == "d": - valor = float(input("Informe o valor do depósito: ")) - - saldo, extrato = depositar(saldo, valor, extrato) + depositar(clientes) elif opcao == "s": - valor = float(input("Informe o valor do saque: ")) - - saldo, extrato = sacar( - saldo=saldo, - valor=valor, - extrato=extrato, - limite=limite, - numero_saques=numero_saques, - limite_saques=LIMITE_SAQUES, - ) + sacar(clientes) elif opcao == "e": - exibir_extrato(saldo, extrato=extrato) + exibir_extrato(clientes) elif opcao == "nu": - criar_usuario(usuarios) + criar_cliente(clientes) elif opcao == "nc": numero_conta = len(contas) + 1 - conta = criar_conta(AGENCIA, numero_conta, usuarios) - - if conta: - contas.append(conta) + criar_conta(numero_conta, clientes, contas) elif opcao == "lc": listar_contas(contas) @@ -154,7 +314,17 @@ def main(): break else: - print("Operação inválida, por favor selecione novamente a operação desejada.") + print("Operação inválida, por favor selecione novamente a operação desejada") + + +def recuperar_conta_cliente(cliente): + if not cliente.contas: + print("Cliente não possui conta") + return None + + # Retorna a primeira conta encontrada + return cliente.contas[0] +# Executa o programa main()