From b85557194bd07219eded1a17977467983049c982 Mon Sep 17 00:00:00 2001 From: keven Date: Tue, 28 Oct 2025 18:10:28 -0300 Subject: [PATCH] =?UTF-8?q?[MVPTN-34]=20feat(Calculo):=20Implementa=20Busc?= =?UTF-8?q?a=20de=20parametros,=20pesquisa=20em=20faixa=20de=20valores=20e?= =?UTF-8?q?=20o=20calculo=20r=C3=A1pido?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .code-workspace | 144 +++++++++++++++++ actions/validations/cep.py | 3 +- actions/values/values.py | 14 ++ ..._emolumento_item_get_faixa_valor_action.py | 74 +++++++++ .../g_emolumento_item_index_action.py | 16 +- .../controllers/g_calculo_controller.py | 6 +- .../endpoints/g_calculo_endpoint.py | 2 +- .../g_emolumento_item_index_repository.py | 11 +- .../schemas/g_calculo_schema.py | 18 +-- .../schemas/g_emolumento_item_schema.py | 2 + .../g_calculo/go/g_calculo_rapido_service.py | 147 +++++++++++++++--- .../go/g_emolumento_item_index_service.py | 19 ++- .../g_config/g_config_by_nome_show_action.py | 20 +++ .../g_config/g_config_show_by_nome_action.py | 19 +++ .../g_config_show_by_nome_repository.py | 31 ++++ .../v1/parametros/schemas/g_config_schema.py | 29 ++++ .../g_config/g_config_show_by_nome_service.py | 18 +++ python_limpa_cache.bat | 89 +++++++++++ 18 files changed, 616 insertions(+), 46 deletions(-) create mode 100644 .code-workspace create mode 100644 actions/values/values.py create mode 100644 packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_get_faixa_valor_action.py create mode 100644 packages/v1/parametros/actions/g_config/g_config_by_nome_show_action.py create mode 100644 packages/v1/parametros/actions/g_config/g_config_show_by_nome_action.py create mode 100644 packages/v1/parametros/repositories/g_config/g_config_show_by_nome_repository.py create mode 100644 packages/v1/parametros/schemas/g_config_schema.py create mode 100644 packages/v1/parametros/services/g_config/g_config_show_by_nome_service.py create mode 100644 python_limpa_cache.bat diff --git a/.code-workspace b/.code-workspace new file mode 100644 index 0000000..835a301 --- /dev/null +++ b/.code-workspace @@ -0,0 +1,144 @@ +{ + "folders": [ + { "path": "D:/IIS/Orius/api" } + ], + "settings": { + // === GERAL === + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + }, + "editor.formatOnPaste": false, + "editor.formatOnType": false, + "editor.minimap.enabled": false, + "files.trimTrailingWhitespace": true, + "files.autoSave": "onFocusChange", + "telemetry.telemetryLevel": "off", + "update.mode": "manual", + + // === PERFORMANCE === + "files.watcherExclude": { + "**/__pycache__/**": true, + "**/.mypy_cache/**": true, + "**/.pytest_cache/**": true, + "**/.venv/**": true, + "**/venv/**": true, + "**/.git/**": true + }, + "search.exclude": { + "**/__pycache__": true, + "**/.git": true, + "**/.mypy_cache": true, + "**/.pytest_cache": true + }, + + // === PYTHON === + "python.defaultInterpreterPath": "D:/IIS/Orius/api/venv/Scripts/python.exe", + "python.analysis.typeCheckingMode": "off", + "python.analysis.useLibraryCodeForTypes": true, + "python.languageServer": "Pylance", + "python.formatting.provider": "black", + "python.formatting.blackArgs": ["--line-length", "100"], + "python.linting.enabled": true, + "python.linting.pylintEnabled": false, + "python.linting.flake8Enabled": true, + "python.linting.flake8Args": ["--max-line-length=100"], + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.formatOnSave": true + }, + + // === TERMINAIS INTEGRADOS === + "terminal.integrated.profiles.windows": { + "FastAPI Dev": { + "path": "cmd.exe", + "args": [ + "/k", + "cd D:\\IIS\\Orius\\api && venv\\Scripts\\activate && uvicorn main:app --reload --log-level debug" + ] + }, + "FastAPI Prod": { + "path": "cmd.exe", + "args": [ + "/k", + "cd D:\\IIS\\Orius\\api && venv\\Scripts\\activate && uvicorn main:app --host 0.0.0.0 --port 8000" + ] + }, + "Python Shell": { + "path": "cmd.exe", + "args": ["/k", "cd D:\\IIS\\Orius\\api && venv\\Scripts\\activate"] + }, + "Git Bash": { + "path": "C:\\Program Files\\Git\\bin\\bash.exe" + } + }, + "terminal.integrated.defaultProfile.windows": "Git Bash", + + // === GIT === + "git.enabled": true, + "git.autorefresh": false, + "git.fetchOnPull": true, + "git.confirmSync": false, + + // === VISUAL === + "workbench.colorTheme": "Default Dark Modern", + "window.zoomLevel": 0, + "breadcrumbs.enabled": true, + "explorer.compactFolders": false, + + // === TESTES === + "python.testing.pytestEnabled": true, + "python.testing.unittestEnabled": false, + "python.testing.autoTestDiscoverOnSaveEnabled": true, + + // === MISC === + "files.exclude": { + "**/.DS_Store": true, + "**/*.log": true + } + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "Debug FastAPI", + "type": "python", + "request": "launch", + "module": "uvicorn", + "args": [ + "main:app", + "--reload", + "--host", + "127.0.0.1", + "--port", + "8000" + ], + "jinja": true, + "justMyCode": true, + "cwd": "${workspaceFolder}", + "env": { + "PYTHONPATH": "${workspaceFolder}" + } + }, + { + "name": "Pytest All", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/venv/Scripts/pytest.exe", + "args": ["-v"], + "console": "integratedTerminal" + } + ] + }, + "extensions": { + "recommendations": [ + // === PYTHON === + "ms-python.python", + "ms-python.black-formatter", + "ms-python.flake8", + "ms-python.pylance", + "littlefoxteam.vscode-python-test-adapter", + + // === GIT === + "eamodio.gitlens", diff --git a/actions/validations/cep.py b/actions/validations/cep.py index 025eefc..21bf1c4 100644 --- a/actions/validations/cep.py +++ b/actions/validations/cep.py @@ -1,8 +1,7 @@ - class CEP: @staticmethod def validate(data: str) -> bool: # Valida e retorna a informação - return len(data) == 8 \ No newline at end of file + return len(data) == 8 diff --git a/actions/values/values.py b/actions/values/values.py new file mode 100644 index 0000000..a9ebd4c --- /dev/null +++ b/actions/values/values.py @@ -0,0 +1,14 @@ +from decimal import ROUND_HALF_UP, Decimal + + +class Values: + + @staticmethod + def percent(value: Decimal, percent: Decimal) -> Decimal: + + return value / percent + + @staticmethod + def money(scale: str, value: Decimal) -> Decimal: + + return value.quantize(scale, rounding=ROUND_HALF_UP) diff --git a/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_get_faixa_valor_action.py b/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_get_faixa_valor_action.py new file mode 100644 index 0000000..c7710fa --- /dev/null +++ b/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_get_faixa_valor_action.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from decimal import Decimal +from typing import Iterable, Optional, Protocol, Any + + +class EmolumentoItemLike(Protocol): + """Protocolo mínimo esperado para um item de emolumento.""" + + valor_inicio: Optional[Decimal] + valor_fim: Optional[Decimal] + + +class GEmolumentoItemGetFaixaValorAction: + """ + Responsável por escolher, dentre uma coleção de itens de emolumento, + aquele cuja faixa [valor_inicio, valor_fim] contem o valor_documento. + - Se houver mais de um candidato, prioriza o de maior valor_inicio (faixa mais específica). + - Se não houver faixa que contenha o valor_documento, tenta a faixa 'aberta' (valor_fim nulo). + - Persistindo a ausência, retorna o item cujo valor_inicio é o mais próximo abaixo do valor_documento. + """ + + @staticmethod + def _para_decimal(valor: Any, padrao: str = "0") -> Decimal: + return valor if isinstance(valor, Decimal) else Decimal(str(valor or padrao)) + + def execute( + self, + itens: Iterable[EmolumentoItemLike], + valor_documento: Decimal, + ) -> EmolumentoItemLike: + lista = list(itens) + if not lista: + raise ValueError("Nenhum item de emolumento foi informado.") + + valor_doc = self._para_decimal(valor_documento) + + candidatos: list[tuple[Decimal, Decimal, EmolumentoItemLike]] = [] + abertos: list[tuple[Decimal, EmolumentoItemLike]] = [] + abaixo: list[tuple[Decimal, EmolumentoItemLike]] = [] + + for item in lista: + ini = self._para_decimal(getattr(item, "valor_inicio", None)) + fim_raw = getattr(item, "valor_fim", None) + fim = ( + self._para_decimal(fim_raw, padrao="Infinity") + if fim_raw is not None + else Decimal("Infinity") + ) + + if ini <= valor_doc <= fim: + candidatos.append((ini, fim, item)) + elif fim == Decimal("Infinity") and ini <= valor_doc: + abertos.append((ini, item)) + elif ini <= valor_doc: + abaixo.append((ini, item)) + + if candidatos: + candidatos.sort(key=lambda t: (t[0], t[1])) # maior ini e menor fim + return candidatos[-1][2] + + if abertos: + abertos.sort(key=lambda t: t[0]) # maior ini + return abertos[-1][1] + + if abaixo: + abaixo.sort(key=lambda t: t[0]) # maior ini + return abaixo[-1][1] + + # Fallback: não há faixa adequada nem valores abaixo; devolve o de menor valor_inicio + lista_ordenada = sorted( + lista, key=lambda it: self._para_decimal(getattr(it, "valor_inicio", None)) + ) + return lista_ordenada[0] diff --git a/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_index_action.py b/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_index_action.py index 93e92cb..15f8e6a 100644 --- a/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_index_action.py +++ b/packages/v1/administrativo/actions/g_emolumento_item/g_emolumento_item_index_action.py @@ -1,6 +1,10 @@ from abstracts.action import BaseAction -from packages.v1.administrativo.repositories.g_emolumento_item.g_emolumento_item_index_repository import GEmolumentoItemIndexRepository -from packages.v1.administrativo.schemas.g_emolumento_item_schema import GEmolumentoItemIndexSchema +from packages.v1.administrativo.repositories.g_emolumento_item.g_emolumento_item_index_repository import ( + GEmolumentoItemIndexRepository, +) +from packages.v1.administrativo.schemas.g_emolumento_item_schema import ( + GEmolumentoItemIndexSchema, +) class GEmolumentoItemIndexAction(BaseAction): @@ -9,7 +13,9 @@ class GEmolumentoItemIndexAction(BaseAction): de listagem de todos os registros na tabela G_NATUREZA_TITULO. """ - def execute(self, g_emolumento_item_emolumento_index_schema: GEmolumentoItemIndexSchema): + def execute( + self, g_emolumento_item_emolumento_index_schema: GEmolumentoItemIndexSchema + ): """ Executa a operação de listagem no banco de dados. @@ -28,7 +34,9 @@ class GEmolumentoItemIndexAction(BaseAction): # ---------------------------------------------------- # Execução do repositório # ---------------------------------------------------- - response = g_emolumento_item_index_repository.execute(g_emolumento_item_emolumento_index_schema) + response = g_emolumento_item_index_repository.execute( + g_emolumento_item_emolumento_index_schema + ) # ---------------------------------------------------- # Retorno da informação diff --git a/packages/v1/administrativo/controllers/g_calculo_controller.py b/packages/v1/administrativo/controllers/g_calculo_controller.py index 3cac1de..f5b4ef1 100644 --- a/packages/v1/administrativo/controllers/g_calculo_controller.py +++ b/packages/v1/administrativo/controllers/g_calculo_controller.py @@ -1,5 +1,7 @@ from actions.dynamic_import.dynamic_import import DynamicImport -from packages.v1.administrativo.schemas.g_calculo_schema import GCalculoRapidoSchema +from packages.v1.administrativo.schemas.g_calculo_schema import ( + GCalculoRapidoSchema, +) class GCalculoController: @@ -27,6 +29,6 @@ class GCalculoController: # Execução da listagem return { - "message": "Registros de G_EMOLUMENTO localizados com sucesso.", + "message": "Cálculo realizado com sucesso", "data": self.rapido_service.execute(g_calculo_rapido_schema), } diff --git a/packages/v1/administrativo/endpoints/g_calculo_endpoint.py b/packages/v1/administrativo/endpoints/g_calculo_endpoint.py index 4ab8581..566d569 100644 --- a/packages/v1/administrativo/endpoints/g_calculo_endpoint.py +++ b/packages/v1/administrativo/endpoints/g_calculo_endpoint.py @@ -30,7 +30,7 @@ g_calculo_controller = GCalculoController() async def index( g_calculo_rapido_schema: GCalculoRapidoSchema, current_user: dict = Depends(get_current_user), -) -> ResponseGCalculoRapidoSchema: +): """ Retorna todos os registros da tabela G_EMOLUMENTO. """ diff --git a/packages/v1/administrativo/repositories/g_emolumento_item/g_emolumento_item_index_repository.py b/packages/v1/administrativo/repositories/g_emolumento_item/g_emolumento_item_index_repository.py index 6eb64a0..80e4a95 100644 --- a/packages/v1/administrativo/repositories/g_emolumento_item/g_emolumento_item_index_repository.py +++ b/packages/v1/administrativo/repositories/g_emolumento_item/g_emolumento_item_index_repository.py @@ -1,5 +1,8 @@ from abstracts.repository import BaseRepository -from packages.v1.administrativo.schemas.g_emolumento_item_schema import GEmolumentoItemIndexSchema +from packages.v1.administrativo.schemas.g_emolumento_item_schema import ( + GEmolumentoItemIndexSchema, +) + class GEmolumentoItemIndexRepository(BaseRepository): """ @@ -7,7 +10,9 @@ class GEmolumentoItemIndexRepository(BaseRepository): na tabela t_censec_qualidade. """ - def execute(self, g_emolumento_item_emolumento_index_schema: GEmolumentoItemIndexSchema): + def execute( + self, g_emolumento_item_emolumento_index_schema: GEmolumentoItemIndexSchema + ): """ Executa a consulta SQL para buscar todos os registros. @@ -32,4 +37,4 @@ class GEmolumentoItemIndexRepository(BaseRepository): response = self.fetch_all(sql, params) # Retorna os dados localizados - return response \ No newline at end of file + return response diff --git a/packages/v1/administrativo/schemas/g_calculo_schema.py b/packages/v1/administrativo/schemas/g_calculo_schema.py index 2333754..cc4aca4 100644 --- a/packages/v1/administrativo/schemas/g_calculo_schema.py +++ b/packages/v1/administrativo/schemas/g_calculo_schema.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict from typing import Optional @@ -8,6 +8,7 @@ class GCalculoRapidoSchema(BaseModel): observacao: Optional[str] = None quantidade: Optional[int] = None emolumento_id: Optional[float] = None + valor_documento: Optional[float] = None class Config: from_attributes = True @@ -15,12 +16,11 @@ class GCalculoRapidoSchema(BaseModel): class ResponseGCalculoRapidoSchema(GCalculoRapidoSchema): - valor_documento: Optional[str] = None - valor_emolumento: Optional[str] = None - valor_taxa_judiciaria: Optional[str] = None - valor_fundos: Optional[str] = None - valor_iss: Optional[str] = None - valor_total: Optional[str] = None + valor_emolumento: Optional[float] = None + valor_taxa_judiciaria: Optional[float] = None + valor_fundos: Optional[float] = None + valor_iss: Optional[float] = None + valor_total: Optional[float] = None - class Config: - from_attributes = True + # valida e coerce em atribuições após criar o objeto + model_config = ConfigDict(from_attributes=True, validate_assignment=True) diff --git a/packages/v1/administrativo/schemas/g_emolumento_item_schema.py b/packages/v1/administrativo/schemas/g_emolumento_item_schema.py index d7f6d0d..69485f3 100644 --- a/packages/v1/administrativo/schemas/g_emolumento_item_schema.py +++ b/packages/v1/administrativo/schemas/g_emolumento_item_schema.py @@ -1,6 +1,7 @@ from pydantic import BaseModel from typing import Optional + # ---------------------------------------------------- # Schema base - representa a tabela G_EMOLUMENTO_ITEM # ---------------------------------------------------- @@ -48,6 +49,7 @@ class GEmolumentoItemIdSchema(BaseModel): class Config: from_attributes = True + # ---------------------------------------------------- # Schema para localizar um registro pelo EmolumentoId (GET /{id}) # ---------------------------------------------------- diff --git a/packages/v1/administrativo/services/g_calculo/go/g_calculo_rapido_service.py b/packages/v1/administrativo/services/g_calculo/go/g_calculo_rapido_service.py index b8ffa89..8071377 100644 --- a/packages/v1/administrativo/services/g_calculo/go/g_calculo_rapido_service.py +++ b/packages/v1/administrativo/services/g_calculo/go/g_calculo_rapido_service.py @@ -1,37 +1,146 @@ -from packages.v1.administrativo.controllers.g_calculo_controller import ( +from __future__ import annotations + +from decimal import Decimal +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, + 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_index_service import ( - GEmolumentoIndexService, -) 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 GCalculoRapidoService: + """ + 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 execute(self, g_calculo_rapido_schema: GCalculoRapidoSchema): + 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) - # Instâciamento da classe que busca o emolumento - g_emolumento_show_service = GEmolumentoShowService() + def execute(self, data: GCalculoRapidoSchema) -> ResponseGCalculoRapidoSchema: - # Busca o emolumento de acordo com o informado - response_g_emolumento_show_service = g_emolumento_show_service.execute( - GEmolumentoIdSchema(emolumento_id=g_calculo_rapido_schema.emolumento_id) + # Busca os parâmetros da aplicação + periodo_id = float( + self._config_service.execute( + GConfigNomeSchema(nome="PERIODO_PADRAO", sistema_id=2) + ).valor ) - # Instânciamento da classe que busca os itens do emolumento - g_emolumento_show_service = GEmolumentoIndexService() + # 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, + ) - response_g_emolumento_show_service = g_emolumento_show_service.execute( - GEmolumentoItemSchema( - emolumento_id=response_g_emolumento_show_service.emolumento_id + # 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, ) ) - # ---------------------------------------------------- - # Retorno da informação - # ---------------------------------------------------- - return response_g_emolumento_show_service + # 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 ResponseGCalculoRapidoSchema( + apresentante=data.apresentante, + observacao=data.observacao, + emolumento_id=float(data.emolumento_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_item/go/g_emolumento_item_index_service.py b/packages/v1/administrativo/services/g_emolumento_item/go/g_emolumento_item_index_service.py index 9ef62d8..88a8035 100644 --- a/packages/v1/administrativo/services/g_emolumento_item/go/g_emolumento_item_index_service.py +++ b/packages/v1/administrativo/services/g_emolumento_item/go/g_emolumento_item_index_service.py @@ -1,7 +1,11 @@ -from packages.v1.administrativo.actions.g_emolumento_item.g_emolumento_item_index_action import GEmolumentoItemIndexAction +from packages.v1.administrativo.actions.g_emolumento_item.g_emolumento_item_index_action import ( + GEmolumentoItemIndexAction, +) from fastapi import HTTPException, status -from packages.v1.administrativo.schemas.g_emolumento_item_schema import GEmolumentoItemIndexSchema +from packages.v1.administrativo.schemas.g_emolumento_item_schema import ( + GEmolumentoItemIndexSchema, +) class GEmolumentoItemIndexService: @@ -10,8 +14,9 @@ class GEmolumentoItemIndexService: de listagem de registros na tabela G_EMOLUMENTO_ITEM. """ - def execute(self, g_emolumento_item_emolumento_index_schema: GEmolumentoItemIndexSchema): - + def execute( + self, g_emolumento_item_emolumento_index_schema: GEmolumentoItemIndexSchema + ): """ Executa a operação de busca de todos os registros no banco de dados. @@ -30,7 +35,9 @@ class GEmolumentoItemIndexService: # ---------------------------------------------------- # Execução da ação # ---------------------------------------------------- - data = g_emolumento_item_index_action.execute(g_emolumento_item_emolumento_index_schema) + data = g_emolumento_item_index_action.execute( + g_emolumento_item_emolumento_index_schema + ) # ---------------------------------------------------- # Verificação de retorno @@ -38,7 +45,7 @@ class GEmolumentoItemIndexService: if not data: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, - detail="Não foi possível localizar registros de G_EMOLUMENTO_ITEM." + detail="Não foi possível localizar registros de G_EMOLUMENTO_ITEM.", ) # ---------------------------------------------------- diff --git a/packages/v1/parametros/actions/g_config/g_config_by_nome_show_action.py b/packages/v1/parametros/actions/g_config/g_config_by_nome_show_action.py new file mode 100644 index 0000000..56bcb9a --- /dev/null +++ b/packages/v1/parametros/actions/g_config/g_config_by_nome_show_action.py @@ -0,0 +1,20 @@ +from packages.v1.parametros.repositories.g_config.g_config_show_by_nome_repository import ( + GConfigShowByNomeRepository, +) +from packages.v1.parametros.schemas.g_config_schema import ( + GConfigNomeSchema, + GConfigResponseSchema, +) +from packages.v1.sequencia.repositories.g_sequencia.get import Get +from abstracts.action import BaseAction + + +class GConfigShowByNomeAction(BaseAction): + + def execute(self, g_config_nome_schema: GConfigNomeSchema) -> GConfigResponseSchema: + + # Instânciamento de repositório + g_config_show_by_nome_repository = GConfigShowByNomeRepository() + + # Execução do repositório + return g_config_show_by_nome_repository.execute(g_config_nome_schema) diff --git a/packages/v1/parametros/actions/g_config/g_config_show_by_nome_action.py b/packages/v1/parametros/actions/g_config/g_config_show_by_nome_action.py new file mode 100644 index 0000000..1f8fde3 --- /dev/null +++ b/packages/v1/parametros/actions/g_config/g_config_show_by_nome_action.py @@ -0,0 +1,19 @@ +from packages.v1.parametros.repositories.g_config.g_config_show_by_nome_repository import ( + GConfigShowByNomeRepository, +) +from packages.v1.parametros.schemas.g_config_schema import ( + GConfigNomeSchema, + GConfigResponseSchema, +) +from abstracts.action import BaseAction + + +class GConfigShowByNomeAction(BaseAction): + + def execute(self, g_config_nome_schema: GConfigNomeSchema) -> GConfigResponseSchema: + + # Instânciamento de repositório + g_config_show_by_nome_repository = GConfigShowByNomeRepository() + + # Execução do repositório + return g_config_show_by_nome_repository.execute(g_config_nome_schema) diff --git a/packages/v1/parametros/repositories/g_config/g_config_show_by_nome_repository.py b/packages/v1/parametros/repositories/g_config/g_config_show_by_nome_repository.py new file mode 100644 index 0000000..410a2e0 --- /dev/null +++ b/packages/v1/parametros/repositories/g_config/g_config_show_by_nome_repository.py @@ -0,0 +1,31 @@ +from abstracts.repository import BaseRepository +from packages.v1.parametros.schemas.g_config_schema import ( + GConfigNomeSchema, + GConfigResponseSchema, +) + + +class GConfigShowByNomeRepository(BaseRepository): + + def execute(self, g_config_nome_schema: GConfigNomeSchema) -> GConfigResponseSchema: + + # Montagem da consulta sql + sql = """ SELECT + FIRST 1 GC.* + FROM G_CONFIG GC + JOIN G_CONFIG_GRUPO GCG ON GC.CONFIG_GRUPO_ID = GCG.CONFIG_GRUPO_ID + WHERE GC.NOME LIKE :nome + AND GCG.SISTEMA_ID = :sistema_id + """ + + # Preenchimento dos parâmetros + params = { + "nome": g_config_nome_schema.nome, + "sistema_id": g_config_nome_schema.sistema_id, + } + + # Execução do sql + response = self.fetch_one(sql, params) + + # Transforma em dict associativo + return response diff --git a/packages/v1/parametros/schemas/g_config_schema.py b/packages/v1/parametros/schemas/g_config_schema.py new file mode 100644 index 0000000..2486732 --- /dev/null +++ b/packages/v1/parametros/schemas/g_config_schema.py @@ -0,0 +1,29 @@ +from typing import Optional +from pydantic import BaseModel, ConfigDict + + +class GConfigSchema(BaseModel): + config_id: Optional[float] = None + config_grupo_id: Optional[float] = None + config_padrao_id: Optional[float] = None + secao: Optional[str] = None + nome: Optional[str] = None + valor: Optional[str] = None + descricao: Optional[str] = None + texto: Optional[str] = None + terminal: Optional[str] = None + tipo_valor: Optional[str] = None + atualizado: Optional[str] = None + + # substitui a antiga inner class Config + model_config = ConfigDict(from_attributes=True) + + +class GConfigResponseSchema(GConfigSchema): + model_config = ConfigDict(from_attributes=True) + + +class GConfigNomeSchema(BaseModel): + nome: str = None + sistema_id: float = None + model_config = ConfigDict(from_attributes=True) diff --git a/packages/v1/parametros/services/g_config/g_config_show_by_nome_service.py b/packages/v1/parametros/services/g_config/g_config_show_by_nome_service.py new file mode 100644 index 0000000..0137b93 --- /dev/null +++ b/packages/v1/parametros/services/g_config/g_config_show_by_nome_service.py @@ -0,0 +1,18 @@ +from packages.v1.parametros.actions.g_config.g_config_show_by_nome_action import ( + GConfigShowByNomeAction, +) +from packages.v1.parametros.schemas.g_config_schema import ( + GConfigNomeSchema, + GConfigResponseSchema, +) + + +class GConfigShowByNomeService: + + def execute(self, g_config_nome_schema: GConfigNomeSchema) -> GConfigResponseSchema: + + # Instânciamento de Action + g_config_show_by_nome_action = GConfigShowByNomeAction() + + # Execução da Ação + return g_config_show_by_nome_action.execute(g_config_nome_schema) diff --git a/python_limpa_cache.bat b/python_limpa_cache.bat new file mode 100644 index 0000000..b9507bd --- /dev/null +++ b/python_limpa_cache.bat @@ -0,0 +1,89 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +:: ===== Configuração/ajuda ===== +if /I "%~1"=="-h" goto :help +if /I "%~1"=="/h" goto :help +if /I "%~1"=="--help" goto :help + +:: Pasta raiz = 1º argumento ou pasta atual +set "ROOT=%~1" +if not defined ROOT set "ROOT=%cd%" + +:: Checa flag /dry-run em qualquer argumento +set "DRYRUN=" +for %%A in (%*) do ( + if /I "%%~A"=="/dry-run" set "DRYRUN=1" +) + +:: Normaliza ROOT removendo aspas extras +for %%# in ("%ROOT%") do set "ROOT=%%~f#" + +if not exist "%ROOT%" ( + echo [ERRO] Pasta nao encontrada: "%ROOT%" + exit /b 1 +) + +:: ===== Timestamp e log ===== +set "TS=%date%_%time%" +set "TS=%TS:/=%" +set "TS=%TS::=%" +set "TS=%TS:.=%" +set "TS=%TS: =0%" +set "LOG=%ROOT%\cleanup_pycache_%TS%.log" + +echo ================================================== > "%LOG%" +echo Limpeza de __pycache__ >> "%LOG%" +echo Pasta raiz: "%ROOT%" >> "%LOG%" +if defined DRYRUN (echo Modo: DRY-RUN (apenas listar) >> "%LOG%") else (echo Modo: EXECUTANDO REMOCOES >> "%LOG%") +echo Iniciado: %date% %time% >> "%LOG%" +echo ================================================== >> "%LOG%" + +set /a FOUND=0, OK=0, ERR=0 + +:: ===== Procura e (opcionalmente) remove ===== +for /f "delims=" %%D in ('dir /ad /b /s "%ROOT%\__pycache__" 2^>nul') do ( + set /a FOUND+=1 + if defined DRYRUN ( + echo [LISTAR] "%%D" + >>"%LOG%" echo [LISTAR] "%%D" + ) else ( + echo [APAGAR] "%%D" + rd /s /q "%%D" 1>nul 2>nul + if exist "%%D" ( + set /a ERR+=1 + >>"%LOG%" echo [FALHA] "%%D" + ) else ( + set /a OK+=1 + >>"%LOG%" echo [OK] "%%D" + ) + ) +) + +echo.>>"%LOG%" +echo Pastas encontradas: %FOUND% >> "%LOG%" +echo Removidas com sucesso: %OK% >> "%LOG%" +echo Falhas: %ERR% >> "%LOG%" +echo Finalizado: %date% %time% >> "%LOG%" + +:: ===== Resumo no console ===== +echo. +echo ===== RESUMO ===== +echo Pasta raiz: "%ROOT%" +if defined DRYRUN (echo Modo: DRY-RUN ^(nao removeu nada^)) +echo Pastas encontradas: %FOUND% +if not defined DRYRUN ( + echo Removidas com sucesso: %OK% + echo Falhas: %ERR% +) +echo Log salvo em: "%LOG%" +exit /b 0 + +:help +echo Uso: +echo cleanup_pycache.bat [PASTA_RAIZ] [/dry-run] +echo. +echo Ex.: cleanup_pycache.bat "D:\Projetos\MeuApp" +echo Ex.: cleanup_pycache.bat /dry-run +echo Ex.: cleanup_pycache.bat "D:\Repos" /dry-run +exit /b 0