[BE-01] feat: Implementação de CRUD da tela de Caixa
This commit is contained in:
commit
f353cf630f
42 changed files with 1230 additions and 0 deletions
9
Api/.gitattributes
vendored
Normal file
9
Api/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Normaliza finais de linha
|
||||
* text=auto
|
||||
|
||||
# Força Python e arquivos de configuração a usarem LF
|
||||
*.py text eol=lf
|
||||
*.sh text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.yaml text eol=lf
|
||||
*.env text eol=lf
|
||||
38
Api/.gitignore
vendored
Normal file
38
Api/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Ambiente virtual
|
||||
venv/
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Bytecode compilado
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Arquivos temporários do sistema
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs e databases locais
|
||||
*.log
|
||||
*.sqlite3
|
||||
|
||||
# VSCode
|
||||
.vscode/
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
||||
|
||||
# Arquivos de testes ou builds
|
||||
*.coverage
|
||||
htmlcov/
|
||||
coverage.xml
|
||||
dist/
|
||||
build/
|
||||
.eggs/
|
||||
*.egg-info/
|
||||
|
||||
# Cache do pip
|
||||
pip-wheel-metadata/
|
||||
*.egg
|
||||
.cache/
|
||||
.tox/
|
||||
26
Api/Dockerfile
Normal file
26
Api/Dockerfile
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Usa a imagem oficial do Python
|
||||
FROM python:3.12-slim
|
||||
|
||||
# Define diretório de trabalho no container
|
||||
WORKDIR /app
|
||||
|
||||
# Copia o arquivo de dependências
|
||||
COPY requirements.txt .
|
||||
|
||||
# Instala dependências no sistema e no Python
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc libffi-dev libssl-dev python3-dev firebird-dev \
|
||||
&& pip install --upgrade pip \
|
||||
&& pip install --no-cache-dir -r requirements.txt \
|
||||
&& apt-get remove -y gcc \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copia o restante do projeto para o container
|
||||
COPY . .
|
||||
|
||||
# Expõe a porta padrão do Uvicorn/FastAPI
|
||||
EXPOSE 8000
|
||||
|
||||
# Comando para iniciar o servidor
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
BIN
Api/FBCLIENT.DLL
Normal file
BIN
Api/FBCLIENT.DLL
Normal file
Binary file not shown.
26
Api/README.md
Normal file
26
Api/README.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# 🧾 MyDocs - Gerador de Documentos
|
||||
|
||||
Aplicação web para gerenciamento de empresas e geração automatizada de documentos com base em **minutas personalizadas** e **informações cadastradas**.
|
||||
|
||||
## 🚀 Funcionalidades
|
||||
|
||||
### ✅ Concluídas:
|
||||
- **Autenticação de Usuário**
|
||||
- Sistema de login seguro
|
||||
- **CRUD de Empresas**
|
||||
- Cadastro, edição, visualização e exclusão de empresas
|
||||
|
||||
### 🛠️ Em Desenvolvimento:
|
||||
- **Gerador de Documentos**
|
||||
- Geração dinâmica de documentos com base em minutas e dados de empresas
|
||||
- **Cadastro de Minutas**
|
||||
- Sistema para criação e gerenciamento de templates/minutas de documentos
|
||||
- **Cadastro de Produtos**
|
||||
- Cadastro de produtos vinculados a empresas ou documentos
|
||||
|
||||
## 🧩 Tecnologias Utilizadas
|
||||
|
||||
- **Backend:** Python / FastApi
|
||||
- **Frontend:** React / NextJs
|
||||
- **Banco de Dados:** MySQL
|
||||
- **Autenticação:** JWT
|
||||
13
Api/api/v1/api.py
Normal file
13
Api/api/v1/api.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Importa o gerenciador de rotas do FastAPI
|
||||
from fastapi import APIRouter
|
||||
|
||||
# Importa os módulos de rotas específicos
|
||||
from api.v1.packages.administrative.endpoints import c_caixa_item
|
||||
|
||||
# Cria uma instância do APIRouter que vai agregar todas as rotas da API
|
||||
api_router = APIRouter()
|
||||
|
||||
# Inclui as rotas de caixa
|
||||
api_router.include_router(
|
||||
c_caixa_item.router, prefix="/administrativo/caixa", tags=["Caixa"]
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from core.base.base_action import BaseAction
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
from api.v1.packages.administrative.repositories.c_caixa_item.delete import Delete
|
||||
|
||||
class DeleteAction(BaseAction):
|
||||
|
||||
def execute(self, caixa_item_schema : CaixaItemSchema):
|
||||
|
||||
# Instânciamento de repoistório
|
||||
delete = Delete()
|
||||
|
||||
# Retorna o resultado da operação
|
||||
return delete.execute(caixa_item_schema)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
from core.base.base_action import BaseAction
|
||||
from api.v1.packages.administrative.repositories.c_caixa_item.index import Index
|
||||
|
||||
class IndexAction(BaseAction):
|
||||
|
||||
def execute(self):
|
||||
|
||||
# Instânciamento de repositório
|
||||
index = Index()
|
||||
|
||||
# Retorna todos produtos
|
||||
return index.execute()
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
from api.v1.packages.administrative.repositories.c_caixa_item.create import Create
|
||||
from core.base.base_action import BaseAction
|
||||
|
||||
class SaveAction(BaseAction):
|
||||
|
||||
def execute(self, caixa_item_schema : CaixaItemSchema):
|
||||
|
||||
# Instância o repositório desejado
|
||||
create = Create()
|
||||
|
||||
# Executa o respositório desejado
|
||||
return create.execute(caixa_item_schema)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
from api.v1.packages.administrative.repositories.c_caixa_item.show import Show
|
||||
from core.base.base_action import BaseAction
|
||||
|
||||
class ShowAction(BaseAction):
|
||||
|
||||
def execute(self, caixa_item_schema : CaixaItemSchema):
|
||||
|
||||
# Instânciamento do repositório
|
||||
show = Show()
|
||||
|
||||
# Retorna os dados localizados
|
||||
return show.execute(caixa_item_schema)
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# Importação de bibliotecas
|
||||
from core.utils.dynamic_import import DynamicImport
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
class CCaixaItemController:
|
||||
|
||||
def index(self):
|
||||
|
||||
# Importação da classe desejad
|
||||
indexService = DynamicImport.service("administrative", "c_caixa_item", "index_service", "IndexService")
|
||||
|
||||
# Intânciamento da classe service
|
||||
self.indexService = indexService()
|
||||
|
||||
# Lista todos os produtos
|
||||
return self.indexService.execute()
|
||||
|
||||
def create(self, caixa_item_schema: CaixaItemSchema):
|
||||
|
||||
# Importação da classe desejada
|
||||
createService = DynamicImport.service("administrative", "c_caixa_item", "save_service", "SaveService")
|
||||
|
||||
# Intânciamento da classe service
|
||||
self.createService = createService()
|
||||
|
||||
# Lista todos os produtos
|
||||
return self.createService.execute(caixa_item_schema)
|
||||
|
||||
def show(self, caixa_item_schema: CaixaItemSchema):
|
||||
# Importação da classe desejad
|
||||
showService = DynamicImport.service("administrative", "c_caixa_item", "show_service", "ShowService")
|
||||
|
||||
# Intânciamento da classe service
|
||||
self.showService = showService()
|
||||
|
||||
# Lista todos os produtos
|
||||
return self.showService.execute(caixa_item_schema)
|
||||
|
||||
def delete(self, caixa_item_schema: CaixaItemSchema):
|
||||
# Importação da classe desejad
|
||||
deleteService = DynamicImport.service("administrative", "c_caixa_item", "delete_service", "DeleteService")
|
||||
|
||||
# Intânciamento da classe service
|
||||
self.deleteService = deleteService()
|
||||
|
||||
# Lista todos os produtos
|
||||
return self.deleteService.execute(caixa_item_schema)
|
||||
59
Api/api/v1/packages/administrative/endpoints/c_caixa_item.py
Normal file
59
Api/api/v1/packages/administrative/endpoints/c_caixa_item.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Importação de bibliotecas
|
||||
from fastapi import APIRouter, status, Depends
|
||||
from api.v1.packages.administrative.controllers.c_caixa_item_controller import CCaixaItemController
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
# Inicializar o roteaodr para as rotas de produtos
|
||||
router = APIRouter()
|
||||
|
||||
# Instãnciamento do controller desejado
|
||||
cCaixaItemController = CCaixaItemController()
|
||||
|
||||
@router.get("/", status_code=status.HTTP_200_OK)
|
||||
async def index():
|
||||
# Busca todos os produtos cadastrados
|
||||
response = cCaixaItemController.index()
|
||||
|
||||
# Retornar os dados localizados
|
||||
return {
|
||||
"data": response
|
||||
}
|
||||
|
||||
@router.post('/', status_code=status.HTTP_201_CREATED)
|
||||
async def save(caixa_item_schema: CaixaItemSchema):
|
||||
|
||||
# Salva o produto desejado
|
||||
response = cCaixaItemController.create(caixa_item_schema)
|
||||
|
||||
# Retorna a informação desejada
|
||||
return {
|
||||
"data": response
|
||||
}
|
||||
|
||||
@router.get('/{caixa_item_id}', status_code=status.HTTP_200_OK)
|
||||
async def show(caixa_item_id : int):
|
||||
|
||||
# Armazena o produto id no Schema
|
||||
CaixaItemSchema.caixa_item_id = caixa_item_id
|
||||
|
||||
# Salva o produto desejado
|
||||
response = cCaixaItemController.show(CaixaItemSchema)
|
||||
|
||||
# Retorna a informação desejada
|
||||
return {
|
||||
"data": response
|
||||
}
|
||||
|
||||
@router.delete('/{caixa_item_id}', status_code=status.HTTP_200_OK)
|
||||
async def delete(caixa_item_id : int):
|
||||
|
||||
# Armazena o produto id no Schema
|
||||
CaixaItemSchema.caixa_item_id = caixa_item_id
|
||||
|
||||
# Salva o produto desejado
|
||||
response = cCaixaItemController.delete(CaixaItemSchema)
|
||||
|
||||
# Retorna a informação desejada
|
||||
return {
|
||||
"data": response
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Importação de bibliotecas
|
||||
from core.base.base_repository import BaseRepository
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
class Create(BaseRepository):
|
||||
|
||||
def execute(self, caixa_item : CaixaItemSchema):
|
||||
|
||||
# Realiza a inserção do registro
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO C_CAIXA_ITEM (
|
||||
CAIXA_ITEM_ID,
|
||||
CAIXA_SERVICO_ID
|
||||
) VALUES (
|
||||
?,
|
||||
?
|
||||
);
|
||||
""",
|
||||
(
|
||||
caixa_item.caixa_item_id, caixa_item.caixa_servico_id,
|
||||
),
|
||||
)
|
||||
|
||||
# Comita a transação
|
||||
self.commit()
|
||||
|
||||
# Retorna como verdadeiro se for salvo com sucesso
|
||||
return True
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
from core.base.base_repository import BaseRepository
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
class Delete(BaseRepository):
|
||||
|
||||
def execute(self, caixa_item : CaixaItemSchema):
|
||||
|
||||
# Realiza a remoção
|
||||
self.cursor.execute(""" DELETE FROM c_caixa_item cci WHERE cci.caixa_item_id = ?""", (caixa_item.caixa_item_id,))
|
||||
|
||||
# Comita a transação
|
||||
self.commit()
|
||||
|
||||
return True
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# Importação de bibliotecas
|
||||
from core.base.base_repository import BaseRepository
|
||||
|
||||
class Index(BaseRepository):
|
||||
|
||||
def execute(self):
|
||||
|
||||
self.cursor.execute("""SELECT * FROM c_caixa_item cci""")
|
||||
columns = [col[0] for col in self.cursor.description] # lista dos nomes das colunas
|
||||
results = []
|
||||
for row in self.cursor.fetchall():
|
||||
results.append({columns[i]: row[i] for i in range(len(columns))})
|
||||
self.commit()
|
||||
return results
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
from core.base.base_repository import BaseRepository
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
class Show(BaseRepository):
|
||||
|
||||
def execute(self, caixa_item_schema: CaixaItemSchema):
|
||||
|
||||
# Executa a busca pelo ID usando placeholder correto (?)
|
||||
self.cursor.execute(
|
||||
"""SELECT * FROM c_caixa_item cci WHERE cci.caixa_item_id = ?""",
|
||||
(caixa_item_schema.caixa_item_id,) # Importante: precisa ser tupla!
|
||||
)
|
||||
|
||||
row = self.cursor.fetchone()
|
||||
|
||||
if not row:
|
||||
return None
|
||||
|
||||
# Transforma em dict associativo
|
||||
columns = [desc[0].lower() for desc in self.cursor.description]
|
||||
return dict(zip(columns, row))
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
from datetime import date, datetime
|
||||
|
||||
class CaixaItemSchema(BaseModel):
|
||||
especie_pagamento: Optional[str] = None
|
||||
caixa_item_id: Optional[int] = None
|
||||
caixa_servico_id: Optional[int] = None
|
||||
usuario_servico_id: Optional[int] = None
|
||||
usuario_caixa_id: Optional[int] = None
|
||||
chave_servico: Optional[str] = None
|
||||
descricao: Optional[str] = None
|
||||
data_pagamento: Optional[date] = None
|
||||
situacao: Optional[str] = None
|
||||
tipo_documento: Optional[str] = None
|
||||
tipo_transacao: Optional[str] = None
|
||||
valor_servico: Optional[float] = None
|
||||
valor_pago: Optional[float] = None
|
||||
observacao: Optional[str] = None
|
||||
caixa_cheque_id: Optional[int] = None
|
||||
hora_pagamento: Optional[datetime] = None
|
||||
caixa_id: Optional[int] = None
|
||||
recibo_id: Optional[int] = None
|
||||
tipo_servico: Optional[str] = None
|
||||
qtd: Optional[int] = None
|
||||
apresentante: Optional[str] = None
|
||||
mensalista_id: Optional[int] = None
|
||||
quitado_caixa_id: Optional[int] = None
|
||||
registrado: Optional[bool] = None
|
||||
emolumento: Optional[float] = None
|
||||
taxa_judiciaria: Optional[float] = None
|
||||
fundesp: Optional[float] = None
|
||||
desconto: Optional[float] = None
|
||||
valor_documento: Optional[float] = None
|
||||
outra_taxa1: Optional[float] = None
|
||||
chave_servico_sec: Optional[str] = None
|
||||
emolumento_item_id: Optional[int] = None
|
||||
caixa_registroselo_id: Optional[int] = None
|
||||
fundo_ri: Optional[float] = None
|
||||
valor_recibo: Optional[float] = None
|
||||
boleto_pdf: Optional[str] = None # ou `bytes` se for binário
|
||||
boleto_vencimento: Optional[date] = None
|
||||
iss: Optional[float] = None
|
||||
nlote: Optional[int] = None
|
||||
tabela: Optional[str] = None
|
||||
campo_id: Optional[int] = None
|
||||
boleto_id: Optional[int] = None
|
||||
valor_adicional: Optional[float] = None
|
||||
pix_id: Optional[int] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
from fastapi import HTTPException, status
|
||||
from api.v1.packages.administrative.actions.c_caixa_item.delete_action import DeleteAction
|
||||
from api.v1.packages.administrative.actions.c_caixa_item.show_action import ShowAction
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
|
||||
class DeleteService:
|
||||
|
||||
def execute(self, caixa_item_schema: CaixaItemSchema):
|
||||
|
||||
# Instânciamento de classe
|
||||
showAction = ShowAction()
|
||||
|
||||
# Obtem o registro desejado
|
||||
data = showAction.execute(caixa_item_schema)
|
||||
|
||||
# Verifica se o registro não existe
|
||||
if not data:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail='Não foi possível localizar o registro'
|
||||
)
|
||||
|
||||
# Instânciamento de ações
|
||||
deleteAction = DeleteAction()
|
||||
|
||||
# Retorna todos produtos desejados
|
||||
return deleteAction.execute(caixa_item_schema)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
from api.v1.packages.administrative.actions.c_caixa_item.index_action import IndexAction
|
||||
|
||||
class IndexService:
|
||||
|
||||
def execute(self):
|
||||
|
||||
# Instânciamento de ações
|
||||
indexAction = IndexAction()
|
||||
|
||||
# Retorna todos produtos desejados
|
||||
return indexAction.execute()
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from api.v1.packages.administrative.actions.c_caixa_item.save_action import SaveAction
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
|
||||
class SaveService:
|
||||
|
||||
def execute(self, caixa_item_schema: CaixaItemSchema):
|
||||
|
||||
# Instânciamento de ações
|
||||
saveAction = SaveAction()
|
||||
|
||||
# Retorna todos produtos desejados
|
||||
return saveAction.execute(caixa_item_schema)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
from fastapi import HTTPException, status
|
||||
from api.v1.packages.administrative.actions.c_caixa_item.show_action import ShowAction
|
||||
from api.v1.packages.administrative.schemas.c_caixa_item_schema import CaixaItemSchema
|
||||
|
||||
|
||||
class ShowService:
|
||||
|
||||
def execute(self, caixa_item_schema: CaixaItemSchema):
|
||||
|
||||
# Instânciamento de ações
|
||||
showAction = ShowAction()
|
||||
|
||||
# Retorna todos produtos desejados
|
||||
data = showAction.execute(caixa_item_schema)
|
||||
|
||||
# Verifica se foi localizado o registro
|
||||
if not data:
|
||||
# Retorna uma exceção
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail='Não foi possível localizar o registro'
|
||||
)
|
||||
|
||||
# Retorna a informação localizada
|
||||
return data
|
||||
10
Api/config/database.json
Normal file
10
Api/config/database.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"firebird": {
|
||||
"host": "localhost",
|
||||
"name": "C:\\Users\\keven\\OneDrive\\Desktop\\Orius\\CALCILANDIA.FDB",
|
||||
"port": 3050,
|
||||
"user": "SYSDBA",
|
||||
"password": "masterkey",
|
||||
"charset": "UTF8"
|
||||
}
|
||||
}
|
||||
34
Api/core/auth.py
Normal file
34
Api/core/auth.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from pytz import timezone
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from jose import jwt
|
||||
|
||||
from core.configs import settings
|
||||
|
||||
# Define o esquema OAuth2 para login
|
||||
oauth2_schema = OAuth2PasswordBearer(
|
||||
tokenUrl=f"{settings.API_V1_STR}/usuarios/login"
|
||||
)
|
||||
|
||||
# Função para criar um token JWT
|
||||
def create_token(tipo_token: str, tempo_vida: timedelta, sub: str) -> str:
|
||||
payload = {}
|
||||
sp = timezone('America/Sao_Paulo')
|
||||
expira = datetime.now(tz=sp) + tempo_vida
|
||||
|
||||
payload["type"] = tipo_token
|
||||
payload["exp"] = expira
|
||||
payload["iat"] = datetime.now(tz=sp)
|
||||
payload["sub"] = str(sub)
|
||||
|
||||
return jwt.encode(payload, settings.JWT_SECRET, algorithm=settings.ALGORITHM)
|
||||
|
||||
|
||||
# Criação do token de acesso (access_token)
|
||||
def create_access_token(sub: str) -> str:
|
||||
return create_token(
|
||||
tipo_token='access_token',
|
||||
tempo_vida=timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES),
|
||||
sub=sub
|
||||
)
|
||||
16
Api/core/base/base_action.py
Normal file
16
Api/core/base/base_action.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from abc import ABC, abstractmethod
|
||||
|
||||
class BaseAction:
|
||||
|
||||
"""
|
||||
Classe abstrata base para todos as actions do sistema.
|
||||
Obriga implementação de um método execute().
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, *args, **kwargs):
|
||||
"""
|
||||
Método abstrato obrigatório a ser implementado pelas subclasses.
|
||||
Deve conter a lógica principal do repositório.
|
||||
"""
|
||||
pass
|
||||
43
Api/core/base/base_repository.py
Normal file
43
Api/core/base/base_repository.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from core.database import get_connection
|
||||
|
||||
class BaseRepository(ABC):
|
||||
"""
|
||||
Classe abstrata base para todos os repositórios do sistema.
|
||||
Fornece conexão com o banco de dados e obriga implementação de um método execute().
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Inicializa a conexão e o cursor do banco de dados.
|
||||
Essa conexão deve ser usada pelas subclasses.
|
||||
"""
|
||||
self.conn = get_connection()
|
||||
self.cursor = self.conn.cursor()
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, *args, **kwargs):
|
||||
"""
|
||||
Método abstrato obrigatório a ser implementado pelas subclasses.
|
||||
Deve conter a lógica principal do repositório.
|
||||
"""
|
||||
pass
|
||||
|
||||
def commit(self):
|
||||
"""
|
||||
Realiza o commit da transação.
|
||||
"""
|
||||
self.conn.commit()
|
||||
|
||||
def rollback(self):
|
||||
"""
|
||||
Realiza o rollback da transação.
|
||||
"""
|
||||
self.conn.rollback()
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Fecha cursor e conexão.
|
||||
"""
|
||||
self.cursor.close()
|
||||
self.conn.close()
|
||||
26
Api/core/configs.py
Normal file
26
Api/core/configs.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from pydantic_settings import BaseSettings
|
||||
|
||||
# Classe de configurações globais da aplicação
|
||||
class Settings(BaseSettings):
|
||||
# Prefixo base das rotas da API
|
||||
API_V1_STR: str = '/api/v1'
|
||||
|
||||
# URL de conexão com o banco MySQL
|
||||
# Formato: mysql://usuario:senha@host:porta/banco
|
||||
DB_URL: str = "mysql://root:root@127.0.0.1:3306/mydocs"
|
||||
|
||||
# Chave secreta para geração dos tokens JWT
|
||||
JWT_SECRET: str = 'WYe1zwtlDkh39_X3X3qTSICFDxts4VQrMyGLxnEpGUg'
|
||||
|
||||
# Algoritmo usado para assinar o token
|
||||
ALGORITHM: str = 'HS256'
|
||||
|
||||
# Tempo de expiração do token JWT (em minutos): 1 semana
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7
|
||||
|
||||
# Configuração interna do Pydantic
|
||||
class Config:
|
||||
case_sensitive = True # Respeita letras maiúsculas/minúsculas nas variáveis de ambiente
|
||||
|
||||
# Instância única das configurações
|
||||
settings: Settings = Settings()
|
||||
22
Api/core/database.py
Normal file
22
Api/core/database.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import fdb
|
||||
from core.utils.config import Config
|
||||
|
||||
def get_connection():
|
||||
"""
|
||||
Constrói e retorna uma conexão com o banco MySQL
|
||||
utilizando os dados da URL definida nas configurações.
|
||||
"""
|
||||
|
||||
# Obtem as configurações de banco de dados
|
||||
database = Config.get()
|
||||
|
||||
# Constrói o DSN no formato 'hostname/port:database_path'
|
||||
# E essa string é passada como o PRIMEIRO ARGUMENTO POSICIONAL
|
||||
connection_dsn = f"{database.firebird.host}/{database.firebird.port}:{database.firebird.name}"
|
||||
|
||||
return fdb.connect(
|
||||
connection_dsn, # Este é o DSN completo que o driver espera
|
||||
user=database.firebird.user,
|
||||
password=database.firebird.password,
|
||||
charset=database.firebird.charset
|
||||
)
|
||||
64
Api/core/deps.py
Normal file
64
Api/core/deps.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# core/deps.py
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from jose import jwt, JWTError
|
||||
from core.configs import settings
|
||||
from api.v1.packages.users.models.users.users_model import UserModel # <--- Importe o UserModel
|
||||
|
||||
# Define o esquema de segurança OAuth2 (token tipo Bearer)
|
||||
oauth2_schema = OAuth2PasswordBearer(
|
||||
tokenUrl=f"{settings.API_V1_STR}/usuarios/login"
|
||||
)
|
||||
|
||||
# Função que retorna o usuário autenticado com base no token JWT
|
||||
def get_current_user(token: str = Depends(oauth2_schema)) -> dict:
|
||||
credential_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail='Could not validate credentials',
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
settings.JWT_SECRET,
|
||||
algorithms=[settings.ALGORITHM],
|
||||
options={"verify_aud": False}
|
||||
)
|
||||
|
||||
user_id: str = payload.get("sub")
|
||||
|
||||
if user_id is None:
|
||||
raise credential_exception
|
||||
|
||||
except JWTError:
|
||||
raise credential_exception
|
||||
|
||||
# --- NOVO: Buscar os dados completos do usuário do banco de dados ---
|
||||
# Convert user_id para int, se ele for um string no JWT e int no banco
|
||||
try:
|
||||
user_id_int = int(user_id)
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Invalid user ID format in token."
|
||||
)
|
||||
|
||||
# Use o UserModel para buscar os dados completos
|
||||
# Adicione um try-except para a chamada ao modelo para capturar erros de DB
|
||||
try:
|
||||
user = UserModel.get_by_id(user_id_int)
|
||||
except Exception as e: # Captura qualquer erro ao buscar no DB
|
||||
print(f"Error fetching user in get_current_user: {e}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to retrieve user data. {str(e)}"
|
||||
)
|
||||
|
||||
if not user:
|
||||
# Se o usuário não for encontrado no DB (mas o token era válido para um ID),
|
||||
# pode indicar um usuário deletado ou um ID inválido no token.
|
||||
raise credential_exception # Ou HTTPException(404, "User associated with token not found")
|
||||
|
||||
return user # Retorna o dicionário completo do usuário
|
||||
31
Api/core/security.py
Normal file
31
Api/core/security.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# core/security.py
|
||||
|
||||
from passlib.context import CryptContext # Contexto de criptografia de senhas
|
||||
from passlib.exc import UnknownHashError # Exceção para hashes não reconhecidos
|
||||
|
||||
# Define contexto de criptografia com esquema bcrypt
|
||||
CRYPTO = CryptContext(schemes=['bcrypt'], deprecated='auto')
|
||||
|
||||
def verify_senha_api(plain_senha_api: str, hashed_senha_api: str) -> bool:
|
||||
"""
|
||||
Compara a senha fornecida em texto puro com o hash armazenado.
|
||||
Retorna False em caso de erro ou formato inválido.
|
||||
"""
|
||||
try:
|
||||
if not plain_senha_api or not hashed_senha_api:
|
||||
return False # Garante que nenhum dos valores seja nulo ou vazio
|
||||
|
||||
# Verifica se a senha corresponde ao hash
|
||||
return CRYPTO.verify(plain_senha_api, hashed_senha_api)
|
||||
|
||||
except UnknownHashError:
|
||||
return False # Hash inválido ou não reconhecido pelo passlib
|
||||
|
||||
except Exception:
|
||||
return False # Falha genérica na verificação
|
||||
|
||||
def hash_senha_api(plain_senha_api: str) -> str:
|
||||
"""
|
||||
Gera o hash da senha em texto puro.
|
||||
"""
|
||||
return CRYPTO.hash(plain_senha_api) # Retorna a senha criptografada com bcrypt
|
||||
4
Api/core/system/exceptions.py
Normal file
4
Api/core/system/exceptions.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# exceptions.py
|
||||
class BusinessRuleException(Exception):
|
||||
def __init__(self, message: str):
|
||||
self.message = message
|
||||
42
Api/core/system/handlers.py
Normal file
42
Api/core/system/handlers.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# handlers.py
|
||||
import traceback
|
||||
from fastapi import Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from core.system.exceptions import BusinessRuleException
|
||||
|
||||
def register_exception_handlers(app):
|
||||
|
||||
@app.exception_handler(BusinessRuleException)
|
||||
async def business_rule_exception_handler(request: Request, exc: BusinessRuleException):
|
||||
return JSONResponse(
|
||||
status_code=422,
|
||||
content={"error": "Regra de negócio", "detail": exc.message}
|
||||
)
|
||||
|
||||
@app.exception_handler(StarletteHTTPException)
|
||||
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={"error": "HTTP Error", "detail": exc.detail}
|
||||
)
|
||||
|
||||
@app.exception_handler(RequestValidationError)
|
||||
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
||||
return JSONResponse(
|
||||
status_code=400,
|
||||
content={"error": "Erro de validação", "detail": exc.errors()}
|
||||
)
|
||||
|
||||
@app.exception_handler(Exception)
|
||||
async def global_exception_handler(request: Request, exc: Exception):
|
||||
return JSONResponse(
|
||||
status_code=500,
|
||||
content={
|
||||
"error": "Erro Interno do Servidor",
|
||||
"type": type(exc).__name__,
|
||||
"message": str(exc),
|
||||
"trace": traceback.format_exc()
|
||||
}
|
||||
)
|
||||
8
Api/core/utils/cep.py
Normal file
8
Api/core/utils/cep.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
class CEP:
|
||||
|
||||
@staticmethod
|
||||
def validate(data: str) -> bool:
|
||||
|
||||
# Valida e retorna a informação
|
||||
return len(data) == 8
|
||||
34
Api/core/utils/cnpj.py
Normal file
34
Api/core/utils/cnpj.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import re
|
||||
|
||||
class CNPJ:
|
||||
|
||||
@staticmethod
|
||||
def validate(data: str) -> bool:
|
||||
|
||||
# Remove caracteres não numéricos
|
||||
data = re.sub(r'\D', '', data)
|
||||
|
||||
# Verifica se tem 14 dígitos
|
||||
if len(data) != 14:
|
||||
return False
|
||||
|
||||
# CNPJs com todos os dígitos iguais são inválidos
|
||||
if data == data[0] * 14:
|
||||
return False
|
||||
|
||||
# Calcula os dois dígitos verificadores
|
||||
def calcular_digito(data, peso):
|
||||
soma = sum(int(a) * b for a, b in zip(data, peso))
|
||||
resto = soma % 11
|
||||
return '0' if resto < 2 else str(11 - resto)
|
||||
|
||||
# Primeiro dígito verificador
|
||||
peso1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
|
||||
digito1 = calcular_digito(data[:12], peso1)
|
||||
|
||||
# Segundo dígito verificador
|
||||
peso2 = [6] + peso1
|
||||
digito2 = calcular_digito(data[:12] + digito1, peso2)
|
||||
|
||||
# Verifica se os dígitos batem
|
||||
return data[-2:] == digito1 + digito2
|
||||
20
Api/core/utils/config.py
Normal file
20
Api/core/utils/config.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import json
|
||||
from types import SimpleNamespace
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Config:
|
||||
|
||||
@staticmethod
|
||||
def get():
|
||||
# Caminho absoluto do arquivo atual
|
||||
base_dir = Path(__file__).resolve().parent
|
||||
|
||||
# Caminho absoluto para o config.json (subindo dois níveis e entrando em config/)
|
||||
config_path = base_dir.parent.parent / 'config' / 'database.json'
|
||||
|
||||
# Carrega o JSON como objeto acessível por ponto
|
||||
with open(config_path, 'r') as f:
|
||||
config = json.load(f, object_hook=lambda d: SimpleNamespace(**d))
|
||||
|
||||
return config
|
||||
17
Api/core/utils/dynamic_import.py
Normal file
17
Api/core/utils/dynamic_import.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import importlib
|
||||
|
||||
class DynamicImport:
|
||||
|
||||
state = "go"
|
||||
base = "api.v1.packages"
|
||||
|
||||
@staticmethod
|
||||
def service(package: str, table: str, name: str, class_name : str):
|
||||
try:
|
||||
module_file = f"{name}"
|
||||
path = f"{DynamicImport.base}.{package}.services.{table}.{DynamicImport.state}.{module_file}"
|
||||
module = importlib.import_module(path)
|
||||
clazz = getattr(module, class_name)
|
||||
return clazz
|
||||
except (ImportError, AttributeError) as e:
|
||||
raise ImportError(f"Erro ao importar '{class_name}' de '{path}': {e}")
|
||||
10
Api/core/utils/email.py
Normal file
10
Api/core/utils/email.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import re
|
||||
|
||||
class Email:
|
||||
|
||||
@staticmethod
|
||||
def validate(data: str) -> str:
|
||||
# Validação de email
|
||||
default = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
|
||||
if not re.match(default, data):
|
||||
raise f"Email inválido: {data}"
|
||||
12
Api/core/utils/phone.py
Normal file
12
Api/core/utils/phone.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
class Phone:
|
||||
|
||||
@staticmethod
|
||||
def validate_cellphone(data: str) -> bool:
|
||||
# Verifica e retorna se o numero de celular é igual a 11
|
||||
return len(data) == 11
|
||||
|
||||
@staticmethod
|
||||
def validate_telephone(data: str) -> bool:
|
||||
# Verifica e retorna se o numero de telefone é igual a 11
|
||||
return len(data) == 10
|
||||
18
Api/core/utils/text.py
Normal file
18
Api/core/utils/text.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import re
|
||||
import html
|
||||
|
||||
class Text:
|
||||
|
||||
@staticmethod
|
||||
def sanitize(data: str) -> str:
|
||||
"""Trim spaces, escape HTML entities, collapse multiple spaces."""
|
||||
data = data.strip()
|
||||
data = html.escape(data)
|
||||
data = re.sub(r"\s+", " ", data)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def just_numbers(data: str) -> str:
|
||||
""" Mantêm apenas os numeros """
|
||||
data = re.sub(r"[^\d]", "", data)
|
||||
return data
|
||||
31
Api/core/validation.py
Normal file
31
Api/core/validation.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# utils/validation.py
|
||||
|
||||
import re
|
||||
import html
|
||||
|
||||
class InputSanitizer:
|
||||
|
||||
@staticmethod
|
||||
def clean_text(text: str) -> str:
|
||||
"""Trim spaces, escape HTML entities, collapse multiple spaces."""
|
||||
text = text.strip()
|
||||
text = html.escape(text)
|
||||
text = re.sub(r"\s+", " ", text)
|
||||
return text
|
||||
|
||||
@staticmethod
|
||||
def is_valid_email(email: str) -> bool:
|
||||
"""Check if email has a valid structure"""
|
||||
return bool(re.match(r"^[\w\.-]+@[\w\.-]+\.\w+$", email))
|
||||
|
||||
@staticmethod
|
||||
def has_script(text: str) -> bool:
|
||||
"""Detect basic XSS attempts"""
|
||||
return "<script" in text.lower() or "javascript:" in text.lower()
|
||||
|
||||
@staticmethod
|
||||
def is_safe(text: str) -> bool:
|
||||
"""Detect common XSS/SQL injection characters or patterns"""
|
||||
blacklist = ["<script", "javascript:", "--", ";", "/*", "*/", "@@", "char(", "nchar(", "varchar(", "alter", "drop", "exec"]
|
||||
text_lower = text.lower()
|
||||
return not any(p in text_lower for p in blacklist)
|
||||
49
Api/main.py
Normal file
49
Api/main.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# main.py
|
||||
|
||||
# Ajuste para garantir que o diretório base do projeto seja incluído no PYTHONPATH
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Adiciona o diretório atual (onde está o main.py) ao sys.path
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Importa a classe principal do FastAPI
|
||||
from fastapi import FastAPI
|
||||
from core.system.handlers import register_exception_handlers
|
||||
|
||||
# Importa o middleware de CORS
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
# Importa as configurações globais da aplicação
|
||||
from core.configs import settings
|
||||
|
||||
# Importa o roteador principal da API versão 1
|
||||
from api.v1.api import api_router
|
||||
|
||||
# Instancia o app FastAPI com um título personalizado
|
||||
app = FastAPI(title='API Mydocs')
|
||||
|
||||
register_exception_handlers(app)
|
||||
|
||||
# Adiciona o middleware de CORS
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:3000"], # Domínio do frontend
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Inclui as rotas da versão 1 da API com prefixo definido em settings (ex: /api/v1)
|
||||
app.include_router(api_router, prefix=settings.API_V1_STR)
|
||||
|
||||
# Executa o servidor com Uvicorn se este arquivo for executado diretamente
|
||||
if __name__ == '__main__':
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"main:app", # Caminho do app para execução
|
||||
host="0.0.0.0", # Disponibiliza a aplicação externamente
|
||||
port=8000, # Porta padrão
|
||||
log_level='info', # Define o nível de log para desenvolvimento
|
||||
reload=True # Ativa auto-reload durante desenvolvimento
|
||||
)
|
||||
39
Api/requirements.txt
Normal file
39
Api/requirements.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
annotated-types==0.7.0
|
||||
anyio==4.9.0
|
||||
asyncpg==0.30.0
|
||||
bcrypt==3.2.0
|
||||
cffi==1.17.1
|
||||
click==8.2.1
|
||||
colorama==0.4.6
|
||||
cryptography==45.0.2
|
||||
dnspython==2.7.0
|
||||
ecdsa==0.19.1
|
||||
email_validator==2.2.0
|
||||
fastapi==0.115.12
|
||||
future==1.0.0
|
||||
greenlet==3.2.2
|
||||
h11==0.16.0
|
||||
idna==3.10
|
||||
mysql-connector-python==9.3.0
|
||||
packaging==25.0
|
||||
passlib==1.7.4
|
||||
protobuf==5.29.4
|
||||
pyasn1==0.4.8
|
||||
pycparser==2.22
|
||||
pydantic==2.11.4
|
||||
pydantic-settings==2.9.1
|
||||
pydantic_core==2.33.2
|
||||
PyMySQL==1.1.1
|
||||
python-dateutil==2.9.0.post0
|
||||
python-dotenv==1.1.0
|
||||
python-jose==3.4.0
|
||||
python-multipart==0.0.20
|
||||
pytz==2025.2
|
||||
rsa==4.9.1
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
SQLAlchemy==2.0.41
|
||||
starlette==0.46.2
|
||||
typing-inspection==0.4.0
|
||||
typing_extensions==4.13.2
|
||||
uvicorn==0.34.2
|
||||
224
Orius.postman_collection.json
Normal file
224
Orius.postman_collection.json
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
{
|
||||
"info": {
|
||||
"_postman_id": "385c0e34-a414-4987-9f55-cf650e80f25c",
|
||||
"name": "Orius",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "41558252"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Administrativo",
|
||||
"item": [
|
||||
{
|
||||
"name": "Caixa",
|
||||
"item": [
|
||||
{
|
||||
"name": "All",
|
||||
"protocolProfileBehavior": {
|
||||
"disableBodyPruning": true
|
||||
},
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{BearerToken}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "formdata",
|
||||
"formdata": [
|
||||
{
|
||||
"key": "username",
|
||||
"value": "keven@softwiki.com.br",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "123",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{BaseUrlV1}}administrativo/caixa",
|
||||
"host": [
|
||||
"{{BaseUrlV1}}administrativo"
|
||||
],
|
||||
"path": [
|
||||
"caixa"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Create",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{BearerToken}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"especie_pagamento\": \"D\",\r\n \"caixa_item_id\" : 12,\r\n \"caixa_servico_id\": 9,\r\n \"usuario_servico_id\": 123456,\r\n \"usuario_caixa_id\": null,\r\n \"chave_servico\": null,\r\n \"descricao\": \"1\",\r\n \"data_pagamento\": null,\r\n \"situacao\": \"3\",\r\n \"tipo_documento\": \"C\",\r\n \"tipo_transacao\": \"C\",\r\n \"valor_servico\": 61,\r\n \"valor_pago\": 61,\r\n \"observacao\": null,\r\n \"caixa_cheque_id\": null,\r\n \"hora_pagamento\": null,\r\n \"caixa_id\": null,\r\n \"recibo_id\": null,\r\n \"tipo_servico\": \"17\",\r\n \"qtd\": 1,\r\n \"apresentante\": \"1\",\r\n \"mensalista_id\": null,\r\n \"quitado_caixa_id\": null,\r\n \"registrado\": 1,\r\n \"emolumento\": 33,\r\n \"taxa_judiciaria\": 14,\r\n \"fundesp\": 13,\r\n \"desconto\": 0,\r\n \"valor_documento\": 0,\r\n \"outra_taxa1\": 0,\r\n \"chave_servico_sec\": null,\r\n \"emolumento_item_id\": null,\r\n \"caixa_registroselo_id\": null,\r\n \"fundo_ri\": null,\r\n \"valor_recibo\": null,\r\n \"boleto_pdf\": null,\r\n \"boleto_vencimento\": null,\r\n \"iss\": 1,\r\n \"nlote\": 0,\r\n \"tabela\": \"1\",\r\n \"campo_id\": 5,\r\n \"boleto_id\": null,\r\n \"valor_adicional\": null,\r\n \"pix_id\": null\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{BaseUrlV1}}administrativo/caixa",
|
||||
"host": [
|
||||
"{{BaseUrlV1}}administrativo"
|
||||
],
|
||||
"path": [
|
||||
"caixa"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Get",
|
||||
"protocolProfileBehavior": {
|
||||
"disableBodyPruning": true
|
||||
},
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{BearerToken}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "formdata",
|
||||
"formdata": [
|
||||
{
|
||||
"key": "username",
|
||||
"value": "keven@softwiki.com.br",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "123",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{BaseUrlV1}}administrativo/caixa/3",
|
||||
"host": [
|
||||
"{{BaseUrlV1}}administrativo"
|
||||
],
|
||||
"path": [
|
||||
"caixa",
|
||||
"3"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "Delete",
|
||||
"request": {
|
||||
"auth": {
|
||||
"type": "bearer",
|
||||
"bearer": [
|
||||
{
|
||||
"key": "token",
|
||||
"value": "{{BearerToken}}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"method": "DELETE",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "formdata",
|
||||
"formdata": [
|
||||
{
|
||||
"key": "username",
|
||||
"value": "keven@softwiki.com.br",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "123",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{BaseUrlV1}}administrativo/caixa/1",
|
||||
"host": [
|
||||
"{{BaseUrlV1}}administrativo"
|
||||
],
|
||||
"path": [
|
||||
"caixa",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"event": [
|
||||
{
|
||||
"listen": "prerequest",
|
||||
"script": {
|
||||
"type": "text/javascript",
|
||||
"packages": {},
|
||||
"exec": [
|
||||
""
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"type": "text/javascript",
|
||||
"packages": {},
|
||||
"exec": [
|
||||
""
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"variable": [
|
||||
{
|
||||
"key": "BaseUrlV1",
|
||||
"value": "http://127.0.0.1:8000/api/v1/",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"key": "BearerToken",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoiYWNjZXNzX3Rva2VuIiwiZXhwIjoxNzUwNjMxNDYxLCJpYXQiOjE3NTAwMjY2NjEsInN1YiI6IjEzIn0.Qnf9kpxgCCUKzjIi3lwR2LZUfpKQeaWhEDUHHZjpBis",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue