[MVPTN-126] feat(Item): Adiciona o processamento de itens enviados através do pedido

This commit is contained in:
Keven 2025-11-08 20:35:02 -03:00
parent 0339cffc21
commit f836daa07c
25 changed files with 811 additions and 194 deletions

View file

@ -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

View file

@ -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})"

View file

@ -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}")

View file

@ -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"]

View file

@ -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

View file

@ -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()

11
main.py
View file

@ -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():

View file

@ -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

View file

@ -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),
}

View file

@ -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
# ----------------------------------------------------

View file

@ -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
)
},
}

View file

@ -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

View file

@ -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
# ----------------------------------------------------

View file

@ -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
@ -46,11 +56,14 @@ 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)):
@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)

View file

@ -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

View file

@ -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

View file

@ -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)
# ----------------------------------------------------

View file

@ -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,
)

View file

@ -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

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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