diff --git a/actions/data/dict_to_namespace.py b/actions/data/dict_to_namespace.py new file mode 100644 index 0000000..0b37901 --- /dev/null +++ b/actions/data/dict_to_namespace.py @@ -0,0 +1,31 @@ +import json +from types import SimpleNamespace + + +def dict_to_namespace(d): + """ + Converte dict (ou string JSON) recursivamente em SimpleNamespace. + """ + # Caso venha uma string JSON + if isinstance(d, str): + try: + # tenta fazer parse do JSON interno + parsed = json.loads(d) + # se for mesmo JSON, converte recursivamente + return dict_to_namespace(parsed) + except (json.JSONDecodeError, TypeError): + # não era JSON, retorna string normal + return d + + # Caso seja um dicionário + if isinstance(d, dict): + return SimpleNamespace(**{k: dict_to_namespace(v) for k, v in d.items()}) + + # Caso seja lista/tupla + if isinstance(d, list): + return [dict_to_namespace(i) for i in d] + if isinstance(d, tuple): + return tuple(dict_to_namespace(i) for i in d) + + # Caso base (valor simples) + return d diff --git a/actions/data/dict_to_obj.py b/actions/data/dict_to_obj.py new file mode 100644 index 0000000..14d9707 --- /dev/null +++ b/actions/data/dict_to_obj.py @@ -0,0 +1,82 @@ +from typing import Any, Mapping, Iterable + + +class DictToObj: + """ + Converte dicts (aninhados) em objetos com acesso por ponto. + - d["x"] -> o.x + - Listas/tuplas são convertidas recursivamente. + - Mantém método parse() para voltar ao dict original. + """ + + __slots__ = ("__data__",) + + def __init__(self, data: Mapping[str, Any] | None = None): + object.__setattr__(self, "__data__", {}) + if data: + for k, v in data.items(): + self.__data__[k] = self._convert(v) + + # ===== Conversões ===== + @classmethod + def _convert(cls, value: Any) -> Any: + if isinstance(value, Mapping): + return cls(value) + if isinstance(value, list): + return [cls._convert(v) for v in value] + if isinstance(value, tuple): + return tuple(cls._convert(v) for v in value) + return value + + def parse(self) -> dict[str, Any]: + def back(v: Any) -> Any: + if isinstance(v, DictToObj): + return v.parse() + if isinstance(v, list): + return [back(i) for i in v] + if isinstance(v, tuple): + return tuple(back(i) for i in v) + return v + + return {k: back(v) for k, v in self.__data__.items()} + + # ===== Acesso por ponto / item ===== + def __getattr__(self, name: str) -> Any: + try: + return self.__data__[name] + except KeyError as e: + raise AttributeError(name) from e + + def __setattr__(self, name: str, value: Any) -> None: + # protege o atributo interno + if name == "__data__": + object.__setattr__(self, name, value) + else: + self.__data__[name] = self._convert(value) + + def __getitem__(self, key: str) -> Any: + return self.__data__[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.__data__[key] = self._convert(value) + + def __contains__(self, key: str) -> bool: + return key in self.__data__ + + def keys(self) -> Iterable[str]: + return self.__data__.keys() + + def items(self) -> Iterable[tuple[str, Any]]: + return self.__data__.items() + + def values(self) -> Iterable[Any]: + return self.__data__.values() + + def __iter__(self): + return iter(self.__data__) + + def __len__(self) -> int: + return len(self.__data__) + + def __repr__(self) -> str: + return f"DictToObj({self.__data__!r})" diff --git a/actions/data/json_to_dict.py b/actions/data/json_to_dict.py new file mode 100644 index 0000000..d368b0a --- /dev/null +++ b/actions/data/json_to_dict.py @@ -0,0 +1,37 @@ +import json +from pathlib import Path +from typing import Any, Union + + +class JsonToDict: + """ + Converte conteúdo JSON (string, bytes ou arquivo) em dicionário Python. + """ + + @staticmethod + def parse(data: Union[str, bytes, Path]) -> dict[str, Any]: + """ + Recebe uma string JSON, bytes ou caminho de arquivo .json + e retorna um dicionário Python. + """ + + try: + # Caso seja um caminho de arquivo + if isinstance(data, Path): + with open(data, "r", encoding="utf-8") as file: + return json.load(file) + + # Caso seja conteúdo JSON (str ou bytes) + if isinstance(data, bytes): + data = data.decode("utf-8") + + # Garante que é string JSON + if isinstance(data, str): + return json.loads(data) + + raise TypeError("Tipo de entrada inválido. Use str, bytes ou Path.") + + except json.JSONDecodeError as e: + raise ValueError(f"Erro ao decodificar JSON: {e}") + except Exception as e: + raise ValueError(f"Erro ao converter JSON para dict: {e}") diff --git a/actions/jwt/get_current_user.py b/actions/jwt/get_current_user.py index e70674d..18adb47 100644 --- a/actions/jwt/get_current_user.py +++ b/actions/jwt/get_current_user.py @@ -5,6 +5,7 @@ from actions.jwt.verify_token import VerifyToken # A classe que criamos anterio oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # Apenas requerido pelo FastAPI + def get_current_user(token: str = Depends(oauth2_scheme)): # Ação que válida o tokne @@ -13,12 +14,12 @@ def get_current_user(token: str = Depends(oauth2_scheme)): result = verify_token.execute(token) # Verifica se a resposta é diferente de inválida - if result['status'] != 'valid': + if result["status"] != "valid": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, - detail=result.get('message', 'Token inválido ou expirado'), + detail=result.get("message", "Token inválido ou expirado"), headers={"WWW-Authenticate": "Bearer"}, ) # Retorna apenas os dados do token - return result['payload'] + return result["payload"] diff --git a/actions/session/get_session.py b/actions/session/get_session.py new file mode 100644 index 0000000..1d87f78 --- /dev/null +++ b/actions/session/get_session.py @@ -0,0 +1,12 @@ +from typing import Any, Optional +from fastapi import Depends, Request, HTTPException, status + + +def get_session_user(request: Request) -> dict: + user = request.session.get("user") + if not user: + # ajuste conforme sua regra (pode só retornar None) + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail="Sessão inválida" + ) + return user diff --git a/actions/session/session_services.py b/actions/session/session_services.py new file mode 100644 index 0000000..de6b0bb --- /dev/null +++ b/actions/session/session_services.py @@ -0,0 +1,16 @@ +# services/session_service.py +from fastapi import Request + + +class SessionService: + def __init__(self, request: Request): + self._session = request.session + + def set(self, k, v): + self._session[k] = v + + def get(self, k, d=None): + return self._session.get(k, d) + + def clear(self): + self._session.clear() diff --git a/main.py b/main.py index 5dffb7b..1627693 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,8 @@ import os import platform import sys +from starlette.middleware.sessions import SessionMiddleware + # Adiciona o diretório atual (onde está o main.py) ao sys.path sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) @@ -53,6 +55,15 @@ app.add_middleware( allow_headers=["*"], ) +app.add_middleware( + SessionMiddleware, + secret_key="coloque-uma-secret-bem-grande-e-aleatoria", + session_cookie="sid", + same_site="lax", + https_only=True, + max_age=60 * 60 * 8, +) + @app.on_event("startup") async def on_startup(): diff --git a/packages/v1/administrativo/actions/g_emolumento/g_emolumento_index_by_sistema_id_action.py b/packages/v1/administrativo/actions/g_emolumento/g_emolumento_index_by_sistema_id_action.py new file mode 100644 index 0000000..5a53348 --- /dev/null +++ b/packages/v1/administrativo/actions/g_emolumento/g_emolumento_index_by_sistema_id_action.py @@ -0,0 +1,44 @@ +from abstracts.action import BaseAction +from packages.v1.administrativo.repositories.g_emolumento.g_emolumento_index_by_sistema_id_repository import ( + GEmolumentoIndexBySistemaIdRepository, +) +from packages.v1.administrativo.schemas.g_emolumento_schema import ( + GEmolumentoSistemaIdSchema, +) + + +class GEmolumentoIndexBySistemaIdAction(BaseAction): + """ + Serviço responsável por encapsular a lógica de negócio para a exibição + de um registro na tabela G_NATUREZA_TITULO. + """ + + def execute(self, g_emolumento_sistema_id_schema: GEmolumentoSistemaIdSchema): + """ + Executa a operação de exibição. + + Args: + g_emolumento_id_schema (GEmolumentoIdSchema): + O esquema com o ID do registro a ser exibido. + + Returns: + O resultado da operação de exibição. + """ + # ---------------------------------------------------- + # Instanciamento do repositório + # ---------------------------------------------------- + g_emolumento_index_by_sistema_id_repository = ( + GEmolumentoIndexBySistemaIdRepository() + ) + + # ---------------------------------------------------- + # Execução do repositório + # ---------------------------------------------------- + response = g_emolumento_index_by_sistema_id_repository.execute( + g_emolumento_sistema_id_schema + ) + + # ---------------------------------------------------- + # Retorno da informação + # ---------------------------------------------------- + return response diff --git a/packages/v1/administrativo/controllers/g_calculo_controller.py b/packages/v1/administrativo/controllers/g_calculo_controller.py index f5b4ef1..3fee34b 100644 --- a/packages/v1/administrativo/controllers/g_calculo_controller.py +++ b/packages/v1/administrativo/controllers/g_calculo_controller.py @@ -1,6 +1,7 @@ from actions.dynamic_import.dynamic_import import DynamicImport from packages.v1.administrativo.schemas.g_calculo_schema import ( GCalculoRapidoSchema, + GCalculoServico, ) @@ -32,3 +33,23 @@ class GCalculoController: "message": "Cálculo realizado com sucesso", "data": self.rapido_service.execute(g_calculo_rapido_schema), } + + # ---------------------------------------------------- + + # Lista todos os registros de G_EMOLUMENTO + # ---------------------------------------------------- + def servico(self, g_calculo_servico: GCalculoServico): + + # Importação da classe desejada + service = self.dynamic_import.service( + "g_calculo_servico_service", "GCalculoServicoService" + ) + + # Instância da classe service + self.service = service() + + # Execução da listagem + return { + "message": "Cálculo realizado com sucesso", + "data": self.service.execute(g_calculo_servico), + } diff --git a/packages/v1/administrativo/controllers/g_emolumento_controller.py b/packages/v1/administrativo/controllers/g_emolumento_controller.py index 45d3b2b..61dc37f 100644 --- a/packages/v1/administrativo/controllers/g_emolumento_controller.py +++ b/packages/v1/administrativo/controllers/g_emolumento_controller.py @@ -1,6 +1,7 @@ from actions.dynamic_import.dynamic_import import DynamicImport from packages.v1.administrativo.schemas.g_emolumento_schema import ( GEmolumentoSaveSchema, + GEmolumentoSistemaIdSchema, GEmolumentoUpdateSchema, GEmolumentoIdSchema, ) @@ -38,6 +39,26 @@ class GEmolumentoController: "data": self.index_service.execute(), } + # ---------------------------------------------------- + # Lista todos os registros de G_EMOLUMENTO + # ---------------------------------------------------- + def indexBySistemaId(self, g_emolumento_sistema_id: GEmolumentoSistemaIdSchema): + + # Importação da classe desejada + service = self.dynamic_import.service( + "g_emolumento_index_by_sistema_id_service", + "GEmolumentoIndexBySistemaIdService", + ) + + # Instância da classe service + self.service = service() + + # Execução da listagem + return { + "message": "Registros de G_EMOLUMENTO localizados com sucesso.", + "data": self.service.execute(g_emolumento_sistema_id), + } + # ---------------------------------------------------- # Busca um registro específico de G_EMOLUMENTO pelo ID # ---------------------------------------------------- diff --git a/packages/v1/administrativo/controllers/g_usuario_controller.py b/packages/v1/administrativo/controllers/g_usuario_controller.py index 90f7f3e..0faba45 100644 --- a/packages/v1/administrativo/controllers/g_usuario_controller.py +++ b/packages/v1/administrativo/controllers/g_usuario_controller.py @@ -1,3 +1,4 @@ +from fastapi import Request from actions.dynamic_import.dynamic_import import DynamicImport from packages.v1.administrativo.schemas.g_usuario_schema import ( GUsuarioSchema, @@ -25,7 +26,11 @@ class GUsuarioController: pass # Efetua o acesso junto ao sistema por um determinado usuário - def authenticate(self, g_usuario_authenticate_schema: GUsuarioAuthenticateSchema): + def authenticate( + self, + request: Request, + g_usuario_authenticate_schema: GUsuarioAuthenticateSchema, + ): # Importação de service de Authenticate authenticate_service = self.dynamic_import.service( @@ -40,7 +45,7 @@ class GUsuarioController: "message": "Usuário localizado com sucesso", "data": { "token": self.authenticate_service.execute( - g_usuario_authenticate_schema + g_usuario_authenticate_schema, request ) }, } diff --git a/packages/v1/administrativo/endpoints/g_calculo_endpoint.py b/packages/v1/administrativo/endpoints/g_calculo_endpoint.py index 566d569..8be1f26 100644 --- a/packages/v1/administrativo/endpoints/g_calculo_endpoint.py +++ b/packages/v1/administrativo/endpoints/g_calculo_endpoint.py @@ -6,6 +6,7 @@ from packages.v1.administrativo.controllers.g_calculo_controller import ( ) from packages.v1.administrativo.schemas.g_calculo_schema import ( GCalculoRapidoSchema, + GCalculoServico, ResponseGCalculoRapidoSchema, ) @@ -36,3 +37,23 @@ async def index( """ response = g_calculo_controller.rapido(g_calculo_rapido_schema) return response + + +# ---------------------------------------------------- +# Lista todos os registros de G_EMOLUMENTO +# ---------------------------------------------------- +@router.post( + "/servico", + status_code=status.HTTP_200_OK, + summary="Realiza um cáculo simples dos emolumentos", + response_description="Realiza um cáculo simples dos emolumentos", +) +async def servico( + g_calculo_servico: GCalculoServico, + current_user: dict = Depends(get_current_user), +): + """ + Retorna todos os registros da tabela G_EMOLUMENTO. + """ + response = g_calculo_controller.servico(g_calculo_servico) + return response diff --git a/packages/v1/administrativo/endpoints/g_emolumento_endpoint.py b/packages/v1/administrativo/endpoints/g_emolumento_endpoint.py index 6a5516e..ff61f6d 100644 --- a/packages/v1/administrativo/endpoints/g_emolumento_endpoint.py +++ b/packages/v1/administrativo/endpoints/g_emolumento_endpoint.py @@ -6,6 +6,7 @@ from packages.v1.administrativo.controllers.g_emolumento_controller import ( ) from packages.v1.administrativo.schemas.g_emolumento_schema import ( GEmolumentoSaveSchema, + GEmolumentoSistemaIdSchema, GEmolumentoUpdateSchema, GEmolumentoIdSchema, ) @@ -36,6 +37,25 @@ async def index(current_user: dict = Depends(get_current_user)): return response +# ---------------------------------------------------- +# Lista todos os registros de G_EMOLUMENTO +# ---------------------------------------------------- +@router.get( + "/sistema/{sistema_id}", + status_code=status.HTTP_200_OK, + summary="Lista todos os registros de G_EMOLUMENTO cadastrados", + response_description="Lista todos os registros de G_EMOLUMENTO cadastrados", +) +async def index(sistema_id: int, current_user: dict = Depends(get_current_user)): + """ + Retorna todos os registros da tabela G_EMOLUMENTO. + """ + response = g_emolumento_controller.indexBySistemaId( + GEmolumentoSistemaIdSchema(sistema_id=sistema_id) + ) + return response + + # ---------------------------------------------------- # Busca um registro específico de G_EMOLUMENTO pelo ID # ---------------------------------------------------- diff --git a/packages/v1/administrativo/endpoints/g_usuario_endpoint.py b/packages/v1/administrativo/endpoints/g_usuario_endpoint.py index 55db32a..ec4caaf 100644 --- a/packages/v1/administrativo/endpoints/g_usuario_endpoint.py +++ b/packages/v1/administrativo/endpoints/g_usuario_endpoint.py @@ -1,8 +1,10 @@ # Importação de bibliotecas from typing import Optional -from fastapi import APIRouter, Body, Depends, status +from fastapi import APIRouter, Body, Depends, status, Request from actions.jwt.get_current_user import get_current_user -from packages.v1.administrativo.controllers.g_usuario_controller import GUsuarioController +from packages.v1.administrativo.controllers.g_usuario_controller import ( + GUsuarioController, +) from packages.v1.administrativo.schemas.g_usuario_schema import ( GUsuarioSchema, GUsuarioAuthenticateSchema, @@ -11,7 +13,7 @@ from packages.v1.administrativo.schemas.g_usuario_schema import ( GUsuarioEmailSchema, GUsuarioCpfSchema, GUsuarioLoginSchema, - GUsuarioIdSchema + GUsuarioIdSchema, ) # Inicializa o roteador para as rotas de usuário @@ -20,24 +22,32 @@ router = APIRouter() # Instânciamento do controller desejado g_usuario_controller = GUsuarioController() + # Autenticação de usuário -@router.post('/authenticate', - status_code=status.HTTP_200_OK, - summary='Cria o token de acesso do usuário', - response_description='Retorna o token de acesso do usuário') -async def index(g_usuario_authenticate_schema : GUsuarioAuthenticateSchema): +@router.post( + "/authenticate", + status_code=status.HTTP_200_OK, + summary="Cria o token de acesso do usuário", + response_description="Retorna o token de acesso do usuário", +) +async def index( + request: Request, g_usuario_authenticate_schema: GUsuarioAuthenticateSchema +): # Efetua a autenticação de um usuário junto ao sistema - response = g_usuario_controller.authenticate(g_usuario_authenticate_schema) + response = g_usuario_controller.authenticate(g_usuario_authenticate_schema, request) # Retorna os dados localizados return response + # Dados do usuário logado -@router.get('/me', - status_code=status.HTTP_200_OK, - summary='Retorna os dados do usuário que efetuou o login', - response_description='Dados do usuário que efetuou o login' ) +@router.get( + "/me", + status_code=status.HTTP_200_OK, + summary="Retorna os dados do usuário que efetuou o login", + response_description="Dados do usuário que efetuou o login", +) async def me(current_user: dict = Depends(get_current_user)): # Busca os dados do usuário logado @@ -45,12 +55,15 @@ async def me(current_user: dict = Depends(get_current_user)): # Retorna os dados localizados return response - + + # Lista todos os usuários -@router.get('/', - status_code=status.HTTP_200_OK, - summary='Lista todos os usuário cadastrados', - response_description='Lista todos os usuário cadastrados') +@router.get( + "/", + status_code=status.HTTP_200_OK, + summary="Lista todos os usuário cadastrados", + response_description="Lista todos os usuário cadastrados", +) async def index(current_user: dict = Depends(get_current_user)): # Busca todos os usuários cadastrados @@ -59,12 +72,15 @@ async def index(current_user: dict = Depends(get_current_user)): # Retorna os dados localizados return response + # Localiza um usuário pelo email -@router.get('/email', - status_code=status.HTTP_200_OK, - summary='Busca um registro em especifico por e-mail informado', - response_description='Busca um registro em especifico') -async def getEmail(email : str, current_user: dict = Depends(get_current_user)): +@router.get( + "/email", + status_code=status.HTTP_200_OK, + summary="Busca um registro em especifico por e-mail informado", + response_description="Busca um registro em especifico", +) +async def getEmail(email: str, current_user: dict = Depends(get_current_user)): # Cria o schema com os dados recebidos usuario_schema = GUsuarioEmailSchema(email=email) @@ -75,12 +91,15 @@ async def getEmail(email : str, current_user: dict = Depends(get_current_user)): # Retorna os dados localizados return response + # Localiza um usuário pelo login -@router.get('/login', - status_code=status.HTTP_200_OK, - summary='Busca um registro em especifico por login informado', - response_description='Busca um registro em especifico') -async def getLogin(login : str, current_user: dict = Depends(get_current_user)): +@router.get( + "/login", + status_code=status.HTTP_200_OK, + summary="Busca um registro em especifico por login informado", + response_description="Busca um registro em especifico", +) +async def getLogin(login: str, current_user: dict = Depends(get_current_user)): # Cria o schema com os dados recebidos usuario_schema = GUsuarioLoginSchema(login=login) @@ -93,11 +112,13 @@ async def getLogin(login : str, current_user: dict = Depends(get_current_user)): # Localiza um usuário pelo cpf -@router.get('/cpf', - status_code=status.HTTP_200_OK, - summary='Busca um registro em especifico por número de CPF', - response_description='Busca um registro em especifico') -async def getCpf(cpf : str, current_user: dict = Depends(get_current_user)): +@router.get( + "/cpf", + status_code=status.HTTP_200_OK, + summary="Busca um registro em especifico por número de CPF", + response_description="Busca um registro em especifico", +) +async def getCpf(cpf: str, current_user: dict = Depends(get_current_user)): # Cria o schema com os dados recebidos usuario_schema = GUsuarioCpfSchema(cpf=cpf) @@ -108,12 +129,15 @@ async def getCpf(cpf : str, current_user: dict = Depends(get_current_user)): # Retorna os dados localizados return response + # Localiza um usuário pelo ID -@router.get('/{usuario_id}', - status_code=status.HTTP_200_OK, - summary='Busca um registro em especifico pelo ID do usuário', - response_description='Busca um registro em especifico') -async def show(usuario_id : int, current_user: dict = Depends(get_current_user)): +@router.get( + "/{usuario_id}", + status_code=status.HTTP_200_OK, + summary="Busca um registro em especifico pelo ID do usuário", + response_description="Busca um registro em especifico", +) +async def show(usuario_id: int, current_user: dict = Depends(get_current_user)): # Cria o schema com os dados recebidos usuario_schema = GUsuarioIdSchema(usuario_id=usuario_id) @@ -126,11 +150,15 @@ async def show(usuario_id : int, current_user: dict = Depends(get_current_user)) # Cadastro de usuários -@router.post('/', - status_code=status.HTTP_200_OK, - summary='Cadastra um usuário', - response_description='Cadastra um usuário') -async def save(usuario_schema : GUsuarioSaveSchema, current_user: dict = Depends(get_current_user)): +@router.post( + "/", + status_code=status.HTTP_200_OK, + summary="Cadastra um usuário", + response_description="Cadastra um usuário", +) +async def save( + usuario_schema: GUsuarioSaveSchema, current_user: dict = Depends(get_current_user) +): # Efetua o cadastro do usuário junto ao banco de dados response = g_usuario_controller.save(usuario_schema) @@ -138,12 +166,19 @@ async def save(usuario_schema : GUsuarioSaveSchema, current_user: dict = Depends # Retorna os dados localizados return response + # Atualiza os dados de usuário -@router.put('/{usuario_id}', - status_code=status.HTTP_200_OK, - summary='Atualiza um usuário', - response_description='Atualiza um usuário') -async def update(usuario_id : int, usuario_schema : GUsuarioUpdateSchema, current_user: dict = Depends(get_current_user)): +@router.put( + "/{usuario_id}", + status_code=status.HTTP_200_OK, + summary="Atualiza um usuário", + response_description="Atualiza um usuário", +) +async def update( + usuario_id: int, + usuario_schema: GUsuarioUpdateSchema, + current_user: dict = Depends(get_current_user), +): # Efetua a atualização dos dados de usuário response = g_usuario_controller.update(usuario_id, usuario_schema) @@ -151,12 +186,15 @@ async def update(usuario_id : int, usuario_schema : GUsuarioUpdateSchema, curren # Retorna os dados localizados return response -# Exclui um determinado usuário -@router.delete('/{usuario_id}', - status_code=status.HTTP_200_OK, - summary='Remove um usuário', - response_description='Remove um usuário') -async def delete(usuario_id : int, current_user: dict = Depends(get_current_user)): + +# Exclui um determinado usuário +@router.delete( + "/{usuario_id}", + status_code=status.HTTP_200_OK, + summary="Remove um usuário", + response_description="Remove um usuário", +) +async def delete(usuario_id: int, current_user: dict = Depends(get_current_user)): # Cria o schema com os dados recebidos usuario_schema = GUsuarioIdSchema(usuario_id=usuario_id) @@ -165,4 +203,4 @@ async def delete(usuario_id : int, current_user: dict = Depends(get_current_user response = g_usuario_controller.delete(usuario_schema) # Retorna os dados localizados - return response \ No newline at end of file + return response diff --git a/packages/v1/administrativo/repositories/g_emolumento/g_emolumento_index_by_sistema_id_repository.py b/packages/v1/administrativo/repositories/g_emolumento/g_emolumento_index_by_sistema_id_repository.py new file mode 100644 index 0000000..0010c1d --- /dev/null +++ b/packages/v1/administrativo/repositories/g_emolumento/g_emolumento_index_by_sistema_id_repository.py @@ -0,0 +1,33 @@ +from abstracts.repository import BaseRepository +from packages.v1.administrativo.schemas.g_emolumento_schema import ( + GEmolumentoSistemaIdSchema, +) + + +class GEmolumentoIndexBySistemaIdRepository(BaseRepository): + """ + Repositório para a operação de listagem de todos os registros + na tabela t_censec_qualidade. + """ + + def execute(self, g_emolumento_sistema_id: GEmolumentoSistemaIdSchema): + """ + Executa a consulta SQL para buscar todos os registros. + + Returns: + Uma lista de dicionários contendo os dados dos registros. + """ + # Montagem do SQL + sql = """ SELECT + GE.* + FROM G_EMOLUMENTO GE + WHERE GE.SISTEMA_ID = :sistema_id + """ + + params = {"sistema_id": g_emolumento_sistema_id.sistema_id} + + # Execução do sql + response = self.fetch_all(sql, params) + + # Retorna os dados localizados + return response diff --git a/packages/v1/administrativo/schemas/g_calculo_schema.py b/packages/v1/administrativo/schemas/g_calculo_schema.py index cc4aca4..86b9175 100644 --- a/packages/v1/administrativo/schemas/g_calculo_schema.py +++ b/packages/v1/administrativo/schemas/g_calculo_schema.py @@ -1,3 +1,4 @@ +from decimal import Decimal from pydantic import BaseModel, ConfigDict from typing import Optional @@ -14,6 +15,17 @@ class GCalculoRapidoSchema(BaseModel): from_attributes = True +class GCalculoServico(BaseModel): + + sistema_id: Optional[float] = None + emolumento_id: Optional[float] = None + valor_documento: Optional[float] = None + quantidade: Optional[Decimal] = None + + # valida e coerce em atribuições após criar o objeto + model_config = ConfigDict(from_attributes=True, validate_assignment=True) + + class ResponseGCalculoRapidoSchema(GCalculoRapidoSchema): valor_emolumento: Optional[float] = None diff --git a/packages/v1/administrativo/schemas/g_emolumento_schema.py b/packages/v1/administrativo/schemas/g_emolumento_schema.py index 7d7b0ff..87178cb 100644 --- a/packages/v1/administrativo/schemas/g_emolumento_schema.py +++ b/packages/v1/administrativo/schemas/g_emolumento_schema.py @@ -1,3 +1,4 @@ +from decimal import Decimal from pydantic import BaseModel from typing import Optional @@ -38,6 +39,16 @@ class GEmolumentoIdSchema(BaseModel): from_attributes = True +# ---------------------------------------------------- +# Schema para localizar um registro pelo ID (GET /{id}) +# ---------------------------------------------------- +class GEmolumentoSistemaIdSchema(BaseModel): + sistema_id: Decimal + + class Config: + from_attributes = True + + # ---------------------------------------------------- # Schema para criação (POST) # ---------------------------------------------------- diff --git a/packages/v1/administrativo/services/g_calculo/go/g_calculo_servico_service.py b/packages/v1/administrativo/services/g_calculo/go/g_calculo_servico_service.py new file mode 100644 index 0000000..245e0b6 --- /dev/null +++ b/packages/v1/administrativo/services/g_calculo/go/g_calculo_servico_service.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +from decimal import Decimal +from types import SimpleNamespace +from typing import Optional + +from actions.values.values import Values +from packages.v1.administrativo.actions.g_emolumento_item.g_emolumento_item_get_faixa_valor_action import ( + GEmolumentoItemGetFaixaValorAction, +) +from packages.v1.administrativo.schemas.g_calculo_schema import ( + GCalculoRapidoSchema, + GCalculoServico, + ResponseGCalculoRapidoSchema, +) +from packages.v1.administrativo.schemas.g_emolumento_item_schema import ( + GEmolumentoItemIndexSchema, +) +from packages.v1.administrativo.schemas.g_emolumento_schema import GEmolumentoIdSchema +from packages.v1.administrativo.services.g_emolumento.go.g_emolumento_show_service import ( + GEmolumentoShowService, +) +from packages.v1.administrativo.services.g_emolumento_item.go.g_emolumento_item_index_service import ( + GEmolumentoItemIndexService, +) +from packages.v1.parametros.schemas.g_config_schema import GConfigNomeSchema +from packages.v1.parametros.services.g_config.g_config_show_by_nome_service import ( + GConfigShowByNomeService, +) + + +class GCalculoServicoService: + """ + Cálculo rápido de emolumentos + taxas. + - Usa DI para serviços (facilita teste/mocks). + - Centraliza leitura de configs/percentuais. + - Normaliza moeda com quantize (por padrão 3 casas, conforme NUMERIC(14,3)). + """ + + def __init__( + self, + config_service: Optional[GConfigShowByNomeService] = None, + emolumento_show_service: Optional[GEmolumentoShowService] = None, + emolumento_item_index_service: Optional[GEmolumentoItemIndexService] = None, + emolumento_item_get_faixa_valor_action: Optional[ + GEmolumentoItemGetFaixaValorAction + ] = None, + scale: str = "0.001", # 3 casas decimais (ex.: Firebird NUMERIC(14,3)) + ) -> None: + self._config_service = config_service or GConfigShowByNomeService() + self._emolumento_show_service = ( + emolumento_show_service or GEmolumentoShowService() + ) + self._emolumento_item_index_service = ( + emolumento_item_index_service or GEmolumentoItemIndexService() + ) + self._emolumento_item_get_faixa_valor_action = ( + emolumento_item_get_faixa_valor_action + or GEmolumentoItemGetFaixaValorAction() + ) + self._scale = Decimal(scale) + + def execute(self, data: GCalculoServico): + + # Busca os parâmetros da aplicação + periodo_id = float( + self._config_service.execute( + GConfigNomeSchema(nome="PERIODO_PADRAO", sistema_id=data.sistema_id) + ).valor + ) + + # Gerar o percentual do iss de acordo com o parâmetro + percentual_iss = Values.percent( + Decimal( + self._config_service.execute( + GConfigNomeSchema(nome="PERCENTUAL_ISS", sistema_id=5) + ).valor + ), + 100, + ) + + # Gerar o percentual do iss de acordo com o parâmetro + percentual_fundos = Values.percent( + Decimal( + self._config_service.execute( + GConfigNomeSchema(nome="PERCENTUAL_FUNDOS_ESTADUAIS", sistema_id=5) + ).valor + ), + 100, + ) + + # Busca o emolumento desejado + emolumento = self._emolumento_show_service.execute( + GEmolumentoIdSchema(emolumento_id=data.emolumento_id) + ) + + # Busca os itens do emolumento + emolumento_itens = self._emolumento_item_index_service.execute( + GEmolumentoItemIndexSchema( + emolumento_id=float(emolumento.emolumento_id), + emolumento_periodo_id=periodo_id, + ) + ) + + # Se vier lista, usa o primeiro (ou ajuste a regra aqui, se necessário) + emolumento_item = self._emolumento_item_get_faixa_valor_action.execute( + emolumento_itens, Decimal(data.valor_documento) + ) + + # Converter o valor para decimal + quantidade = Decimal(data.quantidade) + + # Cálculos + emolumento_total = Values.money( + self._scale, (emolumento_item.valor_emolumento * quantidade) + ) + + taxa_judiciaria_total = Values.money( + self._scale, (emolumento_item.valor_taxa_judiciaria * quantidade) + ) + + iss_total = Values.money( + self._scale, + (emolumento_item.valor_emolumento * percentual_iss * quantidade), + ) + + fundos_total = Values.money( + self._scale, + (emolumento_item.valor_emolumento * percentual_fundos * quantidade), + ) + + total = Values.money( + self._scale, + (emolumento_total + taxa_judiciaria_total + iss_total + fundos_total), + ) + + # Resposta + return SimpleNamespace( + emolumento_id=float(data.emolumento_id), + emolumento_item_id=float(emolumento_item.emolumento_item_id), + valor_documento=float(data.valor_documento), + valor_emolumento=emolumento_total, + valor_taxa_judiciaria=taxa_judiciaria_total, + valor_iss=iss_total, + valor_fundos=fundos_total, + valor_total=total, + ) diff --git a/packages/v1/administrativo/services/g_emolumento/go/g_emolumento_index_by_sistema_id_service.py b/packages/v1/administrativo/services/g_emolumento/go/g_emolumento_index_by_sistema_id_service.py new file mode 100644 index 0000000..4b40cee --- /dev/null +++ b/packages/v1/administrativo/services/g_emolumento/go/g_emolumento_index_by_sistema_id_service.py @@ -0,0 +1,52 @@ +from fastapi import HTTPException, status + +from packages.v1.administrativo.actions.g_emolumento.g_emolumento_index_by_sistema_id_action import ( + GEmolumentoIndexBySistemaIdAction, +) +from packages.v1.administrativo.schemas.g_emolumento_schema import ( + GEmolumentoSistemaIdSchema, +) + + +class GEmolumentoIndexBySistemaIdService: + """ + Serviço responsável por encapsular a lógica de negócio para a operação + de listagem de registros na tabela G_EMOLUMENTO. + """ + + def execute(self, g_emolumento_index_by_sistema_id: GEmolumentoSistemaIdSchema): + """ + Executa a operação de busca de todos os registros no banco de dados. + + Args: + g_emolumento_index_schema (GEmolumentoIndexSchema): + Esquema que pode conter filtros ou parâmetros de busca. + + Returns: + A lista de registros encontrados. + """ + # ---------------------------------------------------- + # Instanciamento da ação + # ---------------------------------------------------- + g_emolumento_index_by_sistema_id_action = GEmolumentoIndexBySistemaIdAction() + + # ---------------------------------------------------- + # Execução da ação + # ---------------------------------------------------- + data = g_emolumento_index_by_sistema_id_action.execute( + g_emolumento_index_by_sistema_id + ) + + # ---------------------------------------------------- + # Verificação de retorno + # ---------------------------------------------------- + if not data: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Não foi possível localizar registros de G_EMOLUMENTO.", + ) + + # ---------------------------------------------------- + # Retorno da informação + # ---------------------------------------------------- + return data diff --git a/packages/v1/administrativo/services/g_usuario/go/g_usuario_authenticate_service.py b/packages/v1/administrativo/services/g_usuario/go/g_usuario_authenticate_service.py index 5374782..f679e8d 100644 --- a/packages/v1/administrativo/services/g_usuario/go/g_usuario_authenticate_service.py +++ b/packages/v1/administrativo/services/g_usuario/go/g_usuario_authenticate_service.py @@ -1,4 +1,4 @@ -from fastapi import HTTPException, status +from fastapi import HTTPException, status, Request from actions.jwt.create_token import CreateToken from packages.v1.administrativo.schemas.g_usuario_schema import ( GUsuarioAuthenticateSchema, @@ -14,7 +14,11 @@ from actions.security.security import Security class AuthenticateService: - def execute(self, g_usuario_authenticate_schema: GUsuarioAuthenticateSchema): + def execute( + self, + request: Request, + g_usuario_authenticate_schema: GUsuarioAuthenticateSchema, + ): # Instânciamento da action de authenticate get_by_authenticate_action = GetByAuthenticateAction() @@ -67,5 +71,8 @@ class AuthenticateService: "email": str(get_by_authenticate_result.email), } + # Cria os dados da sessão + request.session["user"] = jwtUser + # Retorna o token dos dados do usuário return create_token.execute("access-token", json.dumps(jwtUser)) diff --git a/packages/v1/servicos/balcao/endpoints/t_servico_pedido_endpoint.py b/packages/v1/servicos/balcao/endpoints/t_servico_pedido_endpoint.py index c60f28f..6056aac 100644 --- a/packages/v1/servicos/balcao/endpoints/t_servico_pedido_endpoint.py +++ b/packages/v1/servicos/balcao/endpoints/t_servico_pedido_endpoint.py @@ -1,5 +1,6 @@ # Importação de bibliotecas from fastapi import APIRouter, Depends, status +from actions.data.dict_to_namespace import dict_to_namespace from actions.jwt.get_current_user import get_current_user from packages.v1.servicos.balcao.controllers.t_servico_pedido_controller import ( TServicoPedidoController, @@ -72,7 +73,12 @@ async def save( """ Cria um novo registro na tabela T_SERVICO_PEDIDO. """ + current_user = dict_to_namespace(current_user) + + t_servico_pedido_schema.usuario_id = current_user.data.usuario_id + response = t_servico_pedido_controller.save(t_servico_pedido_schema) + return response diff --git a/packages/v1/servicos/balcao/repositories/t_servico_pedido/t_servico_pedido_save_repository.py b/packages/v1/servicos/balcao/repositories/t_servico_pedido/t_servico_pedido_save_repository.py index ffbc153..0df7d38 100644 --- a/packages/v1/servicos/balcao/repositories/t_servico_pedido/t_servico_pedido_save_repository.py +++ b/packages/v1/servicos/balcao/repositories/t_servico_pedido/t_servico_pedido_save_repository.py @@ -30,7 +30,9 @@ class TServicoPedidoSaveRepository(BaseRepository): # ---------------------------------------------------- # Preenchimento dos parâmetros # ---------------------------------------------------- - params = t_servico_pedido_save_schema.model_dump(exclude_unset=True) + params = t_servico_pedido_save_schema.model_dump( + exclude={"itens"}, exclude_unset=True + ) # ---------------------------------------------------- # Montagem do SQL dinâmico diff --git a/packages/v1/servicos/balcao/schemas/t_servico_itempedido_schema.py b/packages/v1/servicos/balcao/schemas/t_servico_itempedido_schema.py index 2dffe59..d97a163 100644 --- a/packages/v1/servicos/balcao/schemas/t_servico_itempedido_schema.py +++ b/packages/v1/servicos/balcao/schemas/t_servico_itempedido_schema.py @@ -8,55 +8,81 @@ from datetime import datetime # Schema base - representa a tabela T_SERVICO_ITEMPEDIDO # ---------------------------------------------------- class TServicoItemPedidoSchema(BaseModel): - servico_itempedido_id: Optional[int] = None - - servico_pedido_id: Optional[int] = None - servico_tipo_id: Optional[int] = None - pessoa_id: Optional[int] = None - pessoa_auxiliar_id: Optional[int] = None - + servico_itempedido_id: Optional[Decimal] = None + servico_pedido_id: Optional[Decimal] = None + servico_tipo_id: Optional[Decimal] = None valor: Optional[Decimal] = None qtd: Optional[Decimal] = None + pessoa_id: Optional[Decimal] = None + impressao_etiqueta: Optional[str] = None + situacao: Optional[str] = None + etiqueta_numero: Optional[Decimal] = None + pessoa_auxiliar_id: Optional[Decimal] = None + pessoa_sp_abono_rep: Optional[str] = None + tipo_item: Optional[str] = None + imprimir: Optional[str] = None + observacao: Optional[str] = None + impressao_direta: Optional[str] = None + selo_livro_id: Optional[Decimal] = None emolumento: Optional[Decimal] = None fundesp: Optional[Decimal] = None taxa_judiciaria: Optional[Decimal] = None desconto: Optional[Decimal] = None - valor_base_calculo: Optional[Decimal] = None - valor_avaliacao: Optional[Decimal] = None - - situacao: Optional[str] = None - tipo_item: Optional[str] = None desc_complementar: Optional[str] = None - nome_juridico: Optional[str] = None - motivo_diferido: Optional[str] = None - etiqueta_apenas_frete: Optional[str] = None # (campo char/flag) - - selo_livro_id: Optional[int] = None - etiqueta_numero: Optional[int] = None - certidao_ato_id: Optional[int] = None - indexacao_id: Optional[int] = None - nfse_id: Optional[int] = None - + valor_manual: Optional[str] = None + valor_documento: Optional[Decimal] = None + outra_taxa1: Optional[Decimal] = None + emolumento_item_id: Optional[Decimal] = None + certidao_impressa: Optional[str] = None + certidao_ato_id: Optional[Decimal] = None + emolumento_id: Optional[Decimal] = None + certidao_previsao: Optional[datetime] = None + certidao_ato_antigo: Optional[str] = None certidao_data_emissao: Optional[datetime] = None - certidao_data_lavratura: Optional[datetime] = None - certidao_texto: Optional[bytes] = None # BLOB (binário) - + certidao_texto: Optional[str] = None ato_antigo_tipo: Optional[str] = None + valor_iss: Optional[Decimal] = None + id_ato_isentado: Optional[Decimal] = None + motivo_isencao: Optional[str] = None + pessoas_etiquetas: Optional[Decimal] = None + abonador: Optional[str] = None + servico_cartao: Optional[str] = None + valor_informacoes_centrais: Optional[Decimal] = None + situacao_diferido: Optional[str] = None + sigla_numero: Optional[str] = None + motivo_diferido: Optional[str] = None + nome_juridico: Optional[str] = None + etiqueta_apenas_frente: Optional[str] = None + indexacao_id: Optional[Decimal] = None + certidao_data_lavratura: Optional[datetime] = None + nfse_id: Optional[Decimal] = None + qtd_pagina_certidao: Optional[Decimal] = None placa: Optional[str] = None dut: Optional[str] = None - pessoa_sp_abono_rep: Optional[str] = None - chave_importacao: Optional[int] = None + chave_importacao: Optional[Decimal] = None + etiqueta_unica: Optional[str] = None + fundo_abonador: Optional[str] = None + instrumento_publico: Optional[str] = None + data_lavratura_abono: Optional[datetime] = None + valor_base_calculo: Optional[Decimal] = None + valor_avaliacao: Optional[Decimal] = None + ato_abonado: Optional[Decimal] = None + transferencia_veiculo: Optional[str] = None + usar_a4: Optional[str] = None + cpf_abono_rep: Optional[str] = None + vrcext: Optional[Decimal] = None + valor_fundo_selo: Optional[Decimal] = None + averbacao: Optional[str] = None class Config: from_attributes = True - # ---------------------------------------------------- - -# Schema para localizar um registro pelo ID (GET /{id}) +# ---------------------------------------------------- +# Schema para listagem (GET index) # ---------------------------------------------------- class TServicoItemIndexSchema(BaseModel): - servico_pedido_id: int + servico_pedido_id: Optional[Decimal] = None class Config: from_attributes = True @@ -65,8 +91,8 @@ class TServicoItemIndexSchema(BaseModel): # ---------------------------------------------------- # Schema para localizar um registro pelo ID (GET /{id}) # ---------------------------------------------------- -class TServicoItemPedidoIdSchema(BaseModel): - servico_itempedido_id: int +class TServicoItemPedidoIdSchema(TServicoItemPedidoSchema): + servico_itempedido_id: Decimal class Config: from_attributes = True @@ -76,44 +102,7 @@ class TServicoItemPedidoIdSchema(BaseModel): # Schema para criação (POST) # - normalmente sem o ID (gerado pelo banco) # ---------------------------------------------------- -class TServicoItemPedidoSaveSchema(BaseModel): - servico_itempedido_id: Optional[int] = None - servico_pedido_id: Optional[int] = None - servico_tipo_id: Optional[int] = None - pessoa_id: Optional[int] = None - pessoa_auxiliar_id: Optional[int] = None - - valor: Optional[Decimal] = None - qtd: Optional[Decimal] = None - emolumento: Optional[Decimal] = None - fundesp: Optional[Decimal] = None - taxa_judiciaria: Optional[Decimal] = None - desconto: Optional[Decimal] = None - valor_base_calculo: Optional[Decimal] = None - valor_avaliacao: Optional[Decimal] = None - - situacao: Optional[str] = None - tipo_item: Optional[str] = None - desc_complementar: Optional[str] = None - nome_juridico: Optional[str] = None - motivo_diferido: Optional[str] = None - etiqueta_apenas_frete: Optional[str] = None - - selo_livro_id: Optional[int] = None - etiqueta_numero: Optional[int] = None - certidao_ato_id: Optional[int] = None - indexacao_id: Optional[int] = None - nfse_id: Optional[int] = None - - certidao_data_emissao: Optional[datetime] = None - certidao_data_lavratura: Optional[datetime] = None - certidao_texto: Optional[bytes] = None - - ato_antigo_tipo: Optional[str] = None - placa: Optional[str] = None - dut: Optional[str] = None - pessoa_sp_abono_rep: Optional[str] = None - chave_importacao: Optional[int] = None +class TServicoItemPedidoSaveSchema(TServicoItemPedidoSchema): class Config: from_attributes = True @@ -123,45 +112,7 @@ class TServicoItemPedidoSaveSchema(BaseModel): # Schema para atualização (PUT) # - inclui o ID + campos opcionais para alterar # ---------------------------------------------------- -class TServicoItemPedidoUpdateSchema(BaseModel): - servico_itempedido_id: Optional[int] = None - - servico_pedido_id: Optional[int] = None - servico_tipo_id: Optional[int] = None - pessoa_id: Optional[int] = None - pessoa_auxiliar_id: Optional[int] = None - - valor: Optional[Decimal] = None - qtd: Optional[Decimal] = None - emolumento: Optional[Decimal] = None - fundesp: Optional[Decimal] = None - taxa_judiciaria: Optional[Decimal] = None - desconto: Optional[Decimal] = None - valor_base_calculo: Optional[Decimal] = None - valor_avaliacao: Optional[Decimal] = None - - situacao: Optional[str] = None - tipo_item: Optional[str] = None - desc_complementar: Optional[str] = None - nome_juridico: Optional[str] = None - motivo_diferido: Optional[str] = None - etiqueta_apenas_frete: Optional[str] = None - - selo_livro_id: Optional[int] = None - etiqueta_numero: Optional[int] = None - certidao_ato_id: Optional[int] = None - indexacao_id: Optional[int] = None - nfse_id: Optional[int] = None - - certidao_data_emissao: Optional[datetime] = None - certidao_data_lavratura: Optional[datetime] = None - certidao_texto: Optional[bytes] = None - - ato_antigo_tipo: Optional[str] = None - placa: Optional[str] = None - dut: Optional[str] = None - pessoa_sp_abono_rep: Optional[str] = None - chave_importacao: Optional[int] = None +class TServicoItemPedidoUpdateSchema(TServicoItemPedidoSchema): class Config: from_attributes = True diff --git a/packages/v1/servicos/balcao/schemas/t_servico_pedido_schema.py b/packages/v1/servicos/balcao/schemas/t_servico_pedido_schema.py index 12eccd1..2dab1ef 100644 --- a/packages/v1/servicos/balcao/schemas/t_servico_pedido_schema.py +++ b/packages/v1/servicos/balcao/schemas/t_servico_pedido_schema.py @@ -1,26 +1,30 @@ from pydantic import BaseModel -from typing import Optional +from typing import Optional, List from decimal import Decimal from datetime import datetime +from packages.v1.servicos.balcao.schemas.t_servico_itempedido_schema import ( + TServicoItemPedidoSchema, +) + # ---------------------------------------------------- # Schema base - representa a tabela T_SERVICO_PEDIDO # ---------------------------------------------------- class TServicoPedidoSchema(BaseModel): - servico_pedido_id: int + servico_pedido_id: Decimal valor_pedido: Optional[Decimal] = None valor_pago: Optional[Decimal] = None - usuario_id: Optional[int] = None + usuario_id: Optional[Decimal] = None data_pedido: Optional[datetime] = None - mensalista_livrocaixa_id: Optional[int] = None + mensalista_livrocaixa_id: Optional[Decimal] = None observacao: Optional[str] = None - escrevente_id: Optional[int] = None + escrevente_id: Optional[Decimal] = None situacao: Optional[str] = None estornado: Optional[str] = None apresentante: Optional[str] = None - nfse_id: Optional[int] = None - chave_importacao: Optional[int] = None + nfse_id: Optional[Decimal] = None + chave_importacao: Optional[Decimal] = None cpfcnpj_apresentante: Optional[str] = None class Config: @@ -31,7 +35,7 @@ class TServicoPedidoSchema(BaseModel): # Schema para localizar um registro pelo ID (GET /{id}) # ---------------------------------------------------- class TServicoPedidoIdSchema(BaseModel): - servico_pedido_id: int + servico_pedido_id: Decimal class Config: from_attributes = True @@ -42,20 +46,21 @@ class TServicoPedidoIdSchema(BaseModel): # - normalmente sem o ID (gerado pelo banco) # ---------------------------------------------------- class TServicoPedidoSaveSchema(BaseModel): - servico_pedido_id: Optional[int] = None + servico_pedido_id: Optional[Decimal] = None valor_pedido: Optional[Decimal] = None valor_pago: Optional[Decimal] = None - usuario_id: Optional[int] = None + usuario_id: Optional[Decimal] = None data_pedido: Optional[datetime] = None - mensalista_livrocaixa_id: Optional[int] = None + mensalista_livrocaixa_id: Optional[Decimal] = None observacao: Optional[str] = None - escrevente_id: Optional[int] = None + escrevente_id: Optional[Decimal] = None situacao: Optional[str] = None estornado: Optional[str] = None apresentante: Optional[str] = None - nfse_id: Optional[int] = None - chave_importacao: Optional[int] = None + nfse_id: Optional[Decimal] = None + chave_importacao: Optional[Decimal] = None cpfcnpj_apresentante: Optional[str] = None + itens: Optional[List[TServicoItemPedidoSchema]] = None class Config: from_attributes = True @@ -66,19 +71,19 @@ class TServicoPedidoSaveSchema(BaseModel): # - inclui o ID + campos opcionais para alterar # ---------------------------------------------------- class TServicoPedidoUpdateSchema(BaseModel): - servico_pedido_id: Optional[int] = None + servico_pedido_id: Optional[Decimal] = None valor_pedido: Optional[Decimal] = None valor_pago: Optional[Decimal] = None - usuario_id: Optional[int] = None + usuario_id: Optional[Decimal] = None data_pedido: Optional[datetime] = None - mensalista_livrocaixa_id: Optional[int] = None + mensalista_livrocaixa_id: Optional[Decimal] = None observacao: Optional[str] = None - escrevente_id: Optional[int] = None + escrevente_id: Optional[Decimal] = None situacao: Optional[str] = None estornado: Optional[str] = None apresentante: Optional[str] = None - nfse_id: Optional[int] = None - chave_importacao: Optional[int] = None + nfse_id: Optional[Decimal] = None + chave_importacao: Optional[Decimal] = None cpfcnpj_apresentante: Optional[str] = None class Config: diff --git a/packages/v1/servicos/balcao/services/t_servico_pedido/go/t_servico_pedido_save_service.py b/packages/v1/servicos/balcao/services/t_servico_pedido/go/t_servico_pedido_save_service.py index 7974788..b84e247 100644 --- a/packages/v1/servicos/balcao/services/t_servico_pedido/go/t_servico_pedido_save_service.py +++ b/packages/v1/servicos/balcao/services/t_servico_pedido/go/t_servico_pedido_save_service.py @@ -1,3 +1,4 @@ +from datetime import datetime from packages.v1.servicos.balcao.actions.t_servico_pedido.t_servico_pedido_save_action import ( TServicoPedidoSaveAction, ) @@ -8,6 +9,9 @@ from packages.v1.servicos.balcao.schemas.t_servico_pedido_schema import ( from packages.v1.sequencia.services.g_sequencia.generate_service import ( GenerateService, ) +from packages.v1.servicos.balcao.services.t_servico_itempedido.go.t_servico_itempedido_save_service import ( + TServicoItemPedidoSaveService, +) class TServicoPedidoSaveService: @@ -43,8 +47,35 @@ class TServicoPedidoSaveService: # Atualiza o ID no schema t_servico_pedido_save_schema.servico_pedido_id = sequencia.sequencia + # Verifica se tem a data do pedido + if not t_servico_pedido_save_schema.data_pedido: + + t_servico_pedido_save_schema.data_pedido = datetime.now() + # ---------------------------------------------------- # Instanciamento e execução da Action de salvamento # ---------------------------------------------------- t_servico_pedido_save_action = TServicoPedidoSaveAction() - return t_servico_pedido_save_action.execute(t_servico_pedido_save_schema) + + # Obtenho a resposta da operação + response = t_servico_pedido_save_action.execute(t_servico_pedido_save_schema) + + # Verifica se o pedido foi salvo + if ( + response.servico_pedido_id > 0 + and len(t_servico_pedido_save_schema.itens) > 0 + ): + + # Import a classe de salvar os intes + t_servico_itempedido_service = TServicoItemPedidoSaveService() + + # Percorre todos os itens salvos + for item in t_servico_pedido_save_schema.itens: + + # Define o id do item do serviço + item.servico_pedido_id = response.servico_pedido_id + + # Salva o item do pedido + t_servico_itempedido_service.execute(item) + + return response