Files
dtf-system/kanban/tiny.py
Cauê Faleiros 98c951d374
Some checks failed
Validate, publish and deploy / validate (push) Successful in 2m2s
Validate, publish and deploy / publish-and-deploy (push) Failing after 8s
first commit
2026-09-15 16:42:34 -03:00

90 lines
3.1 KiB
Python

"""
Cliente da API do Tiny (Olist) — v3, OAuth2 client credentials.
ATENÇÃO Wagner: confirmar na documentação oficial antes de subir:
- o endpoint exato de marcadores do pedido
- o limite de requisições por minuto (dimensiona o worker)
- se o refresh token expira e com que frequência
Este módulo isola a API: se o endpoint mudar, muda só aqui.
"""
from __future__ import annotations
import os
import time
import httpx
BASE = os.environ.get("TINY_BASE", "https://api.tiny.com.br/public-api/v3")
CLIENT_ID = os.environ["TINY_CLIENT_ID"]
CLIENT_SECRET = os.environ["TINY_CLIENT_SECRET"]
TOKEN_URL = os.environ["TINY_TOKEN_URL"]
_token: dict = {"valor": None, "expira": 0.0}
def _acesso() -> str:
if _token["valor"] and time.time() < _token["expira"] - 60:
return _token["valor"]
r = httpx.post(TOKEN_URL, data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
}, timeout=20)
r.raise_for_status()
d = r.json()
_token["valor"] = d["access_token"]
_token["expira"] = time.time() + d.get("expires_in", 3600)
return _token["valor"]
def _headers() -> dict:
return {"Authorization": f"Bearer {_acesso()}", "Content-Type": "application/json"}
def buscar_pedido(numero: str) -> dict:
r = httpx.get(f"{BASE}/pedidos", params={"numero": numero},
headers=_headers(), timeout=20)
r.raise_for_status()
itens = r.json().get("itens") or []
if not itens:
raise LookupError(f"pedido {numero} não encontrado no Tiny")
return itens[0]
def transferido_para_deposito(sku: str, deposito: str, dias: int) -> float:
"""
Soma o que foi transferido para o depósito de impressão no período.
A Altus já faz essa transferência hoje, porque também revende insumo — o
depósito separa consumo interno de revenda. Por isso o aproveitamento sai
de graça: nenhum apontamento novo na sala.
ATENÇÃO Wagner: confirmar o endpoint de movimentações de estoque por
depósito na API v3 e o nome exato do depósito no cadastro.
"""
r = httpx.get(
f"{BASE}/estoque/movimentacoes",
params={"codigo": sku, "deposito": deposito, "dias": dias, "tipo": "E"},
headers=_headers(), timeout=30,
)
r.raise_for_status()
return sum(float(m.get("quantidade", 0)) for m in r.json().get("itens", []))
def marcador(numero: str, marcador: str) -> None:
"""
Troca o marcador do pedido. Substitui os marcadores de etapa do DTF,
preservando marcadores de outra natureza (multiempresa, VALE, Troca...).
"""
pedido = buscar_pedido(numero)
atuais = [m["descricao"] for m in pedido.get("marcadores", [])]
# só três marcadores de etapa vivem no Tiny; o resto do fluxo é do kanban
ETAPAS = {"DTF-RECEBIDA", "DTF-PRODUCAO", "CORRECAO DTF", "DTF-PRONTO"}
mantem = [m for m in atuais if m not in ETAPAS]
novos = mantem + [marcador]
r = httpx.put(f"{BASE}/pedidos/{pedido['id']}/marcadores",
json={"marcadores": [{"descricao": m} for m in novos]},
headers=_headers(), timeout=20)
r.raise_for_status()