Compare commits
No commits in common. '3f1024d3420c79c6761baf175c26b5f10d5ba6b6' and 'cc02d0409748c68145a1f4702207a2281bfe6b2b' have entirely different histories.
3f1024d342
...
cc02d04097
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,40 +1,28 @@
|
|||||||
"""
|
"""
|
||||||
Inicializacao de banco de dados.
|
Inicialização de banco de dados
|
||||||
Cria tabelas e executa seed inicial em ambos os bancos.
|
Cria tabelas e faz seed dos dados iniciais
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app.db.database import Base, engine
|
from app.db.database import Base, engine
|
||||||
from app.db.mock_database import MockBase, mock_engine
|
|
||||||
from app.db.models import Tool
|
from app.db.models import Tool
|
||||||
from app.db.mock_models import Customer, Order, ReviewSchedule, Vehicle
|
from app.db.tool_seed import get_tools_definitions, seed_tools
|
||||||
from app.db.mock_seed import seed_mock_data
|
|
||||||
from app.db.tool_seed import seed_tools
|
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
def init_db():
|
||||||
"""Cria tabelas e executa seed inicial em ambos os bancos."""
|
"""Cria todas as tabelas e faz o seed dos dados iniciais"""
|
||||||
print("Inicializando bancos...")
|
print("📊 Inicializando banco de dados...")
|
||||||
|
|
||||||
try:
|
# Cria todas as tabelas
|
||||||
print("Criando tabelas PostgreSQL (tools)...")
|
print("🔨 Criando tabelas...")
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
print("Populando tools iniciais...")
|
|
||||||
seed_tools()
|
# Seed das tools
|
||||||
print("PostgreSQL OK.")
|
print("📥 Populando tools iniciais...")
|
||||||
except Exception as exc:
|
seed_tools()
|
||||||
print(f"Aviso: falha no PostgreSQL (tools): {exc}")
|
|
||||||
|
print("✅ Banco de dados inicializado com sucesso!")
|
||||||
try:
|
|
||||||
print("Criando tabelas MySQL (dados ficticios)...")
|
|
||||||
MockBase.metadata.create_all(bind=mock_engine)
|
|
||||||
print("Populando dados ficticios iniciais...")
|
|
||||||
seed_mock_data()
|
|
||||||
print("MySQL mock OK.")
|
|
||||||
except Exception as exc:
|
|
||||||
print(f"Aviso: falha no MySQL mock: {exc}")
|
|
||||||
|
|
||||||
print("Bancos inicializados com sucesso!")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
from sqlalchemy import create_engine
|
|
||||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
|
||||||
|
|
||||||
from app.core.settings import settings
|
|
||||||
|
|
||||||
|
|
||||||
if settings.mock_db_cloud_sql_connection_name:
|
|
||||||
# Cloud SQL MySQL via Unix socket
|
|
||||||
MOCK_DATABASE_URL = (
|
|
||||||
f"mysql+pymysql://{settings.mock_db_user}:{settings.mock_db_password}@/{settings.mock_db_name}"
|
|
||||||
f"?unix_socket=/cloudsql/{settings.mock_db_cloud_sql_connection_name}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
MOCK_DATABASE_URL = (
|
|
||||||
f"mysql+pymysql://{settings.mock_db_user}:{settings.mock_db_password}@"
|
|
||||||
f"{settings.mock_db_host}:{settings.mock_db_port}/{settings.mock_db_name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
mock_engine = create_engine(
|
|
||||||
MOCK_DATABASE_URL,
|
|
||||||
pool_pre_ping=True,
|
|
||||||
connect_args={"connect_timeout": 5},
|
|
||||||
)
|
|
||||||
|
|
||||||
SessionMockLocal = sessionmaker(
|
|
||||||
autocommit=False,
|
|
||||||
autoflush=False,
|
|
||||||
bind=mock_engine,
|
|
||||||
)
|
|
||||||
|
|
||||||
MockBase = declarative_base()
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Integer, String, Text
|
|
||||||
from sqlalchemy.sql import func
|
|
||||||
|
|
||||||
from app.db.mock_database import MockBase
|
|
||||||
|
|
||||||
|
|
||||||
class Vehicle(MockBase):
|
|
||||||
__tablename__ = "vehicles"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
modelo = Column(String(120), nullable=False)
|
|
||||||
categoria = Column(String(50), nullable=False, index=True)
|
|
||||||
preco = Column(Float, nullable=False, index=True)
|
|
||||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
|
||||||
|
|
||||||
|
|
||||||
class Customer(MockBase):
|
|
||||||
__tablename__ = "customers"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
cpf = Column(String(11), unique=True, nullable=False, index=True)
|
|
||||||
nome = Column(String(120), nullable=False)
|
|
||||||
score = Column(Integer, nullable=False)
|
|
||||||
limite_credito = Column(Float, nullable=False)
|
|
||||||
possui_restricao = Column(Boolean, nullable=False, default=False)
|
|
||||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
|
||||||
|
|
||||||
|
|
||||||
class Order(MockBase):
|
|
||||||
__tablename__ = "orders"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
numero_pedido = Column(String(40), unique=True, nullable=False, index=True)
|
|
||||||
cpf = Column(String(11), ForeignKey("customers.cpf"), nullable=False, index=True)
|
|
||||||
status = Column(String(20), nullable=False, default="Ativo")
|
|
||||||
motivo_cancelamento = Column(Text, nullable=True)
|
|
||||||
data_cancelamento = Column(DateTime, nullable=True)
|
|
||||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
|
||||||
updated_at = Column(
|
|
||||||
DateTime,
|
|
||||||
server_default=func.current_timestamp(),
|
|
||||||
onupdate=func.current_timestamp(),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ReviewSchedule(MockBase):
|
|
||||||
__tablename__ = "review_schedules"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
protocolo = Column(String(50), unique=True, nullable=False, index=True)
|
|
||||||
placa = Column(String(10), nullable=False, index=True)
|
|
||||||
data_hora = Column(DateTime, nullable=False)
|
|
||||||
status = Column(String(20), nullable=False, default="agendado")
|
|
||||||
created_at = Column(DateTime, server_default=func.current_timestamp())
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
import random
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from app.core.settings import settings
|
|
||||||
from app.db.mock_database import SessionMockLocal
|
|
||||||
from app.db.mock_models import Customer, Order, Vehicle
|
|
||||||
|
|
||||||
|
|
||||||
VEHICLE_MODELS = [
|
|
||||||
"Toyota Corolla",
|
|
||||||
"Honda Civic",
|
|
||||||
"Chevrolet Onix",
|
|
||||||
"Hyundai HB20",
|
|
||||||
"Volkswagen T-Cross",
|
|
||||||
"Jeep Compass",
|
|
||||||
"Fiat Argo",
|
|
||||||
"Nissan Kicks",
|
|
||||||
"Renault Duster",
|
|
||||||
"Ford Ranger",
|
|
||||||
]
|
|
||||||
|
|
||||||
CATEGORIES = ["hatch", "sedan", "suv", "pickup"]
|
|
||||||
NAMES = [
|
|
||||||
"Ana Souza",
|
|
||||||
"Bruno Lima",
|
|
||||||
"Carla Mendes",
|
|
||||||
"Diego Santos",
|
|
||||||
"Eduarda Alves",
|
|
||||||
"Felipe Rocha",
|
|
||||||
"Gabriela Costa",
|
|
||||||
"Henrique Martins",
|
|
||||||
"Isabela Ferreira",
|
|
||||||
"Joao Ribeiro",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def _cpf_from_index(index: int) -> str:
|
|
||||||
return str(10_000_000_000 + index).zfill(11)
|
|
||||||
|
|
||||||
|
|
||||||
def seed_mock_data() -> None:
|
|
||||||
if not settings.mock_seed_enabled:
|
|
||||||
return
|
|
||||||
|
|
||||||
rng = random.Random(42)
|
|
||||||
db = SessionMockLocal()
|
|
||||||
try:
|
|
||||||
if db.query(Vehicle).count() == 0:
|
|
||||||
vehicles = []
|
|
||||||
for idx in range(60):
|
|
||||||
model = VEHICLE_MODELS[idx % len(VEHICLE_MODELS)]
|
|
||||||
category = CATEGORIES[idx % len(CATEGORIES)]
|
|
||||||
base_price = 55_000 + (idx * 1_700)
|
|
||||||
noise = rng.randint(-7_000, 9_000)
|
|
||||||
vehicles.append(
|
|
||||||
Vehicle(
|
|
||||||
modelo=f"{model} {2020 + (idx % 6)}",
|
|
||||||
categoria=category,
|
|
||||||
preco=float(max(35_000, base_price + noise)),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
db.add_all(vehicles)
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
if db.query(Customer).count() == 0:
|
|
||||||
customers = []
|
|
||||||
for idx in range(120):
|
|
||||||
entropy = (idx * 9973) % 10_000
|
|
||||||
customers.append(
|
|
||||||
Customer(
|
|
||||||
cpf=_cpf_from_index(idx),
|
|
||||||
nome=f"{NAMES[idx % len(NAMES)]} {idx + 1}",
|
|
||||||
score=300 + (entropy % 550),
|
|
||||||
limite_credito=float(30_000 + (entropy * 12)),
|
|
||||||
possui_restricao=(idx % 11 == 0),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
db.add_all(customers)
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
if db.query(Order).count() == 0:
|
|
||||||
orders = []
|
|
||||||
for idx in range(40):
|
|
||||||
created = datetime(2026, 1, 1, 8, 0, 0)
|
|
||||||
orders.append(
|
|
||||||
Order(
|
|
||||||
numero_pedido=f"PED-{2026}{idx + 1:05d}",
|
|
||||||
cpf=_cpf_from_index(idx),
|
|
||||||
status="Ativo",
|
|
||||||
created_at=created,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
db.add_all(orders)
|
|
||||||
db.commit()
|
|
||||||
finally:
|
|
||||||
db.close()
|
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
from app.core.settings import settings
|
||||||
|
|
||||||
|
|
||||||
|
class FakerApiClient:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
base_url: Optional[str] = None,
|
||||||
|
locale: Optional[str] = None,
|
||||||
|
seed: Optional[int] = None,
|
||||||
|
):
|
||||||
|
self.base_url = (base_url or settings.fakerapi_base_url).rstrip("/")
|
||||||
|
self.locale = locale or settings.fakerapi_locale
|
||||||
|
self.seed = settings.fakerapi_seed if seed is None else seed
|
||||||
|
|
||||||
|
async def fetch_resource(
|
||||||
|
self,
|
||||||
|
resource: str,
|
||||||
|
quantity: int,
|
||||||
|
extra_params: Optional[Dict[str, Any]] = None,
|
||||||
|
) -> List[Dict[str, Any]]:
|
||||||
|
url = f"{self.base_url}/{resource.lstrip('/')}"
|
||||||
|
params: Dict[str, Any] = {
|
||||||
|
"_quantity": quantity,
|
||||||
|
"_locale": self.locale,
|
||||||
|
"_seed": self.seed,
|
||||||
|
}
|
||||||
|
if extra_params:
|
||||||
|
params.update(extra_params)
|
||||||
|
|
||||||
|
timeout = httpx.Timeout(connect=5.0, read=15.0, write=10.0, pool=5.0)
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"User-Agent": "orquestrador-fakerapi-client/1.0",
|
||||||
|
}
|
||||||
|
async with httpx.AsyncClient(timeout=timeout, headers=headers) as client:
|
||||||
|
try:
|
||||||
|
response = await client.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
payload = response.json()
|
||||||
|
except httpx.ReadTimeout:
|
||||||
|
# Retry once with smaller payload to reduce timeout risk in free/public APIs.
|
||||||
|
reduced_quantity = min(quantity, 20)
|
||||||
|
retry_params = dict(params)
|
||||||
|
retry_params["_quantity"] = reduced_quantity
|
||||||
|
response = await client.get(url, params=retry_params)
|
||||||
|
response.raise_for_status()
|
||||||
|
payload = response.json()
|
||||||
|
|
||||||
|
if isinstance(payload, dict) and isinstance(payload.get("data"), list):
|
||||||
|
return payload["data"]
|
||||||
|
if isinstance(payload, list):
|
||||||
|
return payload
|
||||||
|
return []
|
||||||
Binary file not shown.
Loading…
Reference in New Issue