Versão 1.0
This commit is contained in:
commit
13bcea2077
26 changed files with 1546 additions and 0 deletions
842
src/holmes/client.py
Normal file
842
src/holmes/client.py
Normal file
|
|
@ -0,0 +1,842 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
import requests
|
||||
|
||||
from src.models.erro_holmes import ErroHolmes
|
||||
from src.models.estoque_homes import EstoqueHolmes
|
||||
from src.models.proposta import Proposta
|
||||
from src.models.resultado import Resultado
|
||||
from src.repositories.estoque_repository import EstoqueRepository
|
||||
from src.utils.utils import extrair_proposta
|
||||
|
||||
class HolmesAPI:
|
||||
|
||||
def __init__(self):
|
||||
self.headers = {
|
||||
# "authorization": self._token_usuario(),
|
||||
"api_token": 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNmE4MzBjMzcwNDdlNzI1MTVlMDU1ZDFhIiwiaWF0IjoxNzg2OTczMjM5fQ.K-R2E6v7JjCJDJJfDhyZ8nwQwMiaVfbF2BtUvW-sNwQ',
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
def _somente_digitos(self, valor) -> str:
|
||||
return ''.join(c for c in str(valor or '') if c.isdigit())
|
||||
|
||||
def _token_usuario(self) -> str:
|
||||
url = "https://app-api.holmesdoc.io/v1/session"
|
||||
body = {"email": os.getenv('HOLMES_USER'), "password": os.getenv('HOLMES_PASS')}
|
||||
headers = {"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36"}
|
||||
response = requests.post(url, json=body, headers=headers)
|
||||
response.raise_for_status()
|
||||
dados = response.json()
|
||||
if "token" not in dados:
|
||||
logging.error(
|
||||
f"Login Holmes sem token (HTTP {response.status_code}): {str(dados)[:500]}"
|
||||
)
|
||||
raise RuntimeError("Login Holmes não retornou token")
|
||||
|
||||
return dados["token"]
|
||||
|
||||
def _build_payload_novos(self, proposta: Proposta) -> dict:
|
||||
start_event = 'StartEvent_1'
|
||||
|
||||
campos = [
|
||||
("e88ea290-8ce4-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
("ed2d30f0-8ce4-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
("f2fe24d0-8ce4-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
("2aafcff0-8cf4-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
("fad87d40-8ce4-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
("fdfd63f0-8ce4-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
("01109760-8ce5-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
("04ab7160-8ce5-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
("1b0974c0-8ce5-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
("23914b40-8ce5-11f1-9f28-e51e49945850", proposta.nome),
|
||||
("27b419f0-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
("398ac070-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
("3e7bb490-8ce5-11f1-9f28-e51e49945850", proposta.email),
|
||||
("6873d880-9ccc-11f1-b919-f777409ec14c", proposta.vendedor_holmes),
|
||||
]
|
||||
|
||||
payload = {
|
||||
"workflow": {
|
||||
"start_event": start_event,
|
||||
"property_values": [
|
||||
{"id": prop_id, "value": valor}
|
||||
for prop_id, valor in campos
|
||||
if valor is not None and str(valor).strip() != ''
|
||||
],
|
||||
"whats": "",
|
||||
"documents": [],
|
||||
"test": False
|
||||
}
|
||||
}
|
||||
logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
return payload
|
||||
|
||||
def _build_payload_usados(self, proposta: Proposta) -> dict:
|
||||
start_event = 'StartEvent_1'
|
||||
|
||||
campos = [
|
||||
("e88ea290-8ce4-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
("ed2d30f0-8ce4-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
("2aafcff0-8cf4-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
("f2fe24d0-8ce4-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
("fad87d40-8ce4-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
("fdfd63f0-8ce4-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
("01109760-8ce5-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
("04ab7160-8ce5-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
("08b38c20-8ce5-11f1-9f28-e51e49945850", proposta.placa),
|
||||
("1b0974c0-8ce5-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
("23914b40-8ce5-11f1-9f28-e51e49945850", proposta.nome),
|
||||
("27b419f0-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
("398ac070-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
("3e7bb490-8ce5-11f1-9f28-e51e49945850", proposta.email),
|
||||
("19c78c10-9d92-11f1-ad38-41765eab56e3", proposta.vendedor_holmes),
|
||||
]
|
||||
|
||||
payload = {
|
||||
"workflow": {
|
||||
"start_event": start_event,
|
||||
"property_values": [
|
||||
{"id": prop_id, "value": valor}
|
||||
for prop_id, valor in campos
|
||||
if valor is not None and str(valor).strip() != ''
|
||||
],
|
||||
"whats": "",
|
||||
"documents": [],
|
||||
"test": False
|
||||
}
|
||||
}
|
||||
logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
return payload
|
||||
|
||||
def _build_payload_imobilizado(self, proposta: Proposta) -> dict:
|
||||
start_event = 'StartEvent_1'
|
||||
|
||||
campos = [
|
||||
("e88ea290-8ce4-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
("ed2d30f0-8ce4-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
("f2fe24d0-8ce4-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
("2aafcff0-8cf4-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
("fad87d40-8ce4-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
("fdfd63f0-8ce4-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
("01109760-8ce5-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
("04ab7160-8ce5-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
("08b38c20-8ce5-11f1-9f28-e51e49945850", proposta.placa),
|
||||
("1b0974c0-8ce5-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
("23914b40-8ce5-11f1-9f28-e51e49945850", proposta.nome),
|
||||
("27b419f0-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
("398ac070-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
("3e7bb490-8ce5-11f1-9f28-e51e49945850", proposta.email),
|
||||
("d1b18d20-9d98-11f1-8298-cb4f6a31d606", proposta.vendedor_holmes),
|
||||
]
|
||||
|
||||
payload = {
|
||||
"workflow": {
|
||||
"start_event": start_event,
|
||||
"property_values": [
|
||||
{"id": prop_id, "value": valor}
|
||||
for prop_id, valor in campos
|
||||
if valor is not None and str(valor).strip() != ''
|
||||
],
|
||||
"whats": "",
|
||||
"documents": [],
|
||||
"test": False
|
||||
}
|
||||
}
|
||||
logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
return payload
|
||||
|
||||
def _build_payload_venda_direta(self, proposta: Proposta) -> dict:
|
||||
# Esse formulario tem IDs proprios (nao reaproveita os dos outros tres),
|
||||
# nao tem Placa e traz a Observacao da proposta.
|
||||
start_event = 'StartEvent_1'
|
||||
|
||||
campos = [
|
||||
("37897690-8d03-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
("420c59c0-8d03-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
("46da1900-8d04-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
("48ee6f80-8d03-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
("53933290-8d03-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
("58d81310-8d03-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
("5b19c5b0-8d03-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
("5f92a3a0-8d03-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
("6b95e540-8d03-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
("73c56290-8d03-11f1-9f28-e51e49945850", proposta.nome),
|
||||
("79635f90-8d03-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
("85ea9e40-8d03-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
("8f16f220-8d03-11f1-9f28-e51e49945850", proposta.email),
|
||||
("cbe61910-a2de-11f1-aff4-4f1f04587741", proposta.vendedor_holmes),
|
||||
("e7610290-a2de-11f1-aff4-4f1f04587741", proposta.observacao),
|
||||
]
|
||||
|
||||
payload = {
|
||||
"workflow": {
|
||||
"start_event": start_event,
|
||||
"property_values": [
|
||||
{"id": prop_id, "value": valor}
|
||||
for prop_id, valor in campos
|
||||
if valor is not None and str(valor).strip() != ''
|
||||
],
|
||||
"whats": "",
|
||||
"documents": [],
|
||||
"test": False
|
||||
}
|
||||
}
|
||||
logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
return payload
|
||||
|
||||
def existe_holmes(self, chassi: str, proposta: str) -> bool:
|
||||
"""Confere se o chassi já está lançado no holmes e caso tenha o mesmo chassi ele bate a proposta
|
||||
|
||||
Args:
|
||||
chassi (str): Chassi do veiculo vendido
|
||||
proposta (str): Proposta do veiculo
|
||||
|
||||
Returns:
|
||||
bool: True caso existir e False caso não exista no holmes
|
||||
"""
|
||||
|
||||
logging.info("Verificando se chassi %s (proposta %s) já existe no Holmes", chassi, proposta)
|
||||
url = 'https://app-api.holmesdoc.io/v2/search'
|
||||
body = {
|
||||
"query": {
|
||||
"from": 0,
|
||||
"size": 50,
|
||||
"context": "process",
|
||||
"sort": "updated_at",
|
||||
"order": "desc",
|
||||
"groups": [
|
||||
{
|
||||
"match_all": True,
|
||||
"terms": [
|
||||
{
|
||||
"value": f"{chassi}",
|
||||
"type": "match_phrase",
|
||||
"field": "_content"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"trash": False,
|
||||
"deleted_by_me": False
|
||||
}
|
||||
|
||||
resposta = requests.post(url, json=body, headers=self.headers)
|
||||
resposta.raise_for_status()
|
||||
dados = resposta.json()
|
||||
|
||||
if dados['total'] == 0:
|
||||
logging.info("Chassi %s não encontrado no Holmes", chassi)
|
||||
return False
|
||||
|
||||
PROCESSOS_VALIDOS = {
|
||||
'Faturamento de Novos',
|
||||
'Faturamento de Venda Direta',
|
||||
'Faturamento de Test Drive',
|
||||
'Faturamento de Usados',
|
||||
}
|
||||
|
||||
docs_validos = [
|
||||
doc for doc in dados.get('docs', [])
|
||||
if doc.get('name') in PROCESSOS_VALIDOS
|
||||
and doc.get('status') != 'canceled'
|
||||
]
|
||||
|
||||
if not docs_validos:
|
||||
logging.info("Chassi %s encontrado mas sem processos válidos (todos cancelados ou de outro template)", chassi)
|
||||
return False
|
||||
|
||||
# proposta_holmes = extrair_proposta(docs_validos[0]['identifier'])
|
||||
# if str(proposta_holmes) != str(proposta):
|
||||
# logging.info("Chassi %s encontrado mas proposta diferente (Holmes: %s, Apollo: %s)", chassi, proposta_holmes, proposta)
|
||||
# return False
|
||||
|
||||
logging.info("Chassi %s já existe no Holmes %s", chassi, proposta)
|
||||
return True
|
||||
|
||||
def envia_fat_estoque_usado(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cc58744c4ba86a63aebc1/start'
|
||||
payload = self._build_payload_usados(proposta)
|
||||
logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
try:
|
||||
if response.status_code != 200:
|
||||
err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
estoque_repo.insere_erro(
|
||||
ErroHolmes(
|
||||
empresa = proposta.empresa,
|
||||
revenda = proposta.revenda,
|
||||
proposta_apollo = proposta.proposta_apollo,
|
||||
motivo_erro= err_msg
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
else:
|
||||
resposta = response.json()
|
||||
logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
estoque_repo.insere_estoque(
|
||||
EstoqueHolmes(
|
||||
empresa= proposta.empresa,
|
||||
revenda= proposta.revenda,
|
||||
proposta_apollo= proposta.proposta_apollo,
|
||||
proesso_id= resposta['id'],
|
||||
usuario_criou= 'SUPORTE SISTEMAS',
|
||||
nome_processo= '[FAT] Faturamento de Estoque'
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
except Exception as e:
|
||||
logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
return Resultado(sucesso=False, mensagem=str(e))
|
||||
|
||||
def envia_fat_estoque_novos(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cbe67aff519bb6aa4b2d8/start'
|
||||
payload = self._build_payload_novos(proposta)
|
||||
logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
try:
|
||||
if response.status_code != 200:
|
||||
err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
estoque_repo.insere_erro(
|
||||
ErroHolmes(
|
||||
empresa = proposta.empresa,
|
||||
revenda = proposta.revenda,
|
||||
proposta_apollo = proposta.proposta_apollo,
|
||||
motivo_erro= err_msg
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
else:
|
||||
resposta = response.json()
|
||||
logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
estoque_repo.insere_estoque(
|
||||
EstoqueHolmes(
|
||||
empresa= proposta.empresa,
|
||||
revenda= proposta.revenda,
|
||||
proposta_apollo= proposta.proposta_apollo,
|
||||
proesso_id= resposta['id'],
|
||||
usuario_criou= 'SUPORTE SISTEMAS',
|
||||
nome_processo= '[FAT] Faturamento de Estoque'
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
except Exception as e:
|
||||
logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
return Resultado(sucesso=False, mensagem=str(e))
|
||||
|
||||
def envia_fat_estoque_imobilizado(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cc2a3dbf5173588777520/start'
|
||||
payload = self._build_payload_imobilizado(proposta)
|
||||
logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
try:
|
||||
if response.status_code != 200:
|
||||
err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
estoque_repo.insere_erro(
|
||||
ErroHolmes(
|
||||
empresa = proposta.empresa,
|
||||
revenda = proposta.revenda,
|
||||
proposta_apollo = proposta.proposta_apollo,
|
||||
motivo_erro= err_msg
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
else:
|
||||
resposta = response.json()
|
||||
logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
estoque_repo.insere_estoque(
|
||||
EstoqueHolmes(
|
||||
empresa= proposta.empresa,
|
||||
revenda= proposta.revenda,
|
||||
proposta_apollo= proposta.proposta_apollo,
|
||||
proesso_id= resposta['id'],
|
||||
usuario_criou= 'SUPORTE SISTEMAS',
|
||||
nome_processo= '[FAT] Faturamento de Estoque'
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
except Exception as e:
|
||||
logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
return Resultado(sucesso=False, mensagem=str(e))
|
||||
def envia_fat_estoque_venda_direta(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cd6449341bbc7e45f29cf/start'
|
||||
payload = self._build_payload_venda_direta(proposta)
|
||||
logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
try:
|
||||
if response.status_code != 200:
|
||||
err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
estoque_repo.insere_erro(
|
||||
ErroHolmes(
|
||||
empresa = proposta.empresa,
|
||||
revenda = proposta.revenda,
|
||||
proposta_apollo = proposta.proposta_apollo,
|
||||
motivo_erro= err_msg
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
else:
|
||||
resposta = response.json()
|
||||
logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
estoque_repo.insere_estoque(
|
||||
EstoqueHolmes(
|
||||
empresa= proposta.empresa,
|
||||
revenda= proposta.revenda,
|
||||
proposta_apollo= proposta.proposta_apollo,
|
||||
proesso_id= resposta['id'],
|
||||
usuario_criou= 'SUPORTE SISTEMAS',
|
||||
nome_processo= '[FAT] Faturamento de Estoque'
|
||||
)
|
||||
)
|
||||
return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
except Exception as e:
|
||||
logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
return Resultado(sucesso=False, mensagem=str(e))
|
||||
# import json
|
||||
# import logging
|
||||
# import os
|
||||
|
||||
# import requests
|
||||
|
||||
# from src.models.erro_holmes import ErroHolmes
|
||||
# from src.models.estoque_homes import EstoqueHolmes
|
||||
# from src.models.proposta import Proposta
|
||||
# from src.models.resultado import Resultado
|
||||
# from src.repositories.estoque_repository import EstoqueRepository
|
||||
# from src.utils.utils import extrair_proposta
|
||||
|
||||
# class HolmesAPI:
|
||||
|
||||
# def __init__(self):
|
||||
# self.headers = {
|
||||
# "authorization": self._token_usuario(),
|
||||
# "Content-Type": "application/json"
|
||||
# }
|
||||
|
||||
# def _somente_digitos(self, valor) -> str:
|
||||
# return ''.join(c for c in str(valor or '') if c.isdigit())
|
||||
|
||||
# def _token_usuario(self) -> str:
|
||||
# url = "https://app-api.holmesdoc.io/v1/session"
|
||||
# body = {"email": os.getenv('HOLMES_USER'), "password": os.getenv('HOLMES_PASS')}
|
||||
# headers = {"Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36"}
|
||||
# response = requests.post(url, json=body, headers=headers)
|
||||
# response.raise_for_status()
|
||||
# dados = response.json()
|
||||
# if "token" not in dados:
|
||||
# logging.error(
|
||||
# f"Login Holmes sem token (HTTP {response.status_code}): {str(dados)[:500]}"
|
||||
# )
|
||||
# raise RuntimeError("Login Holmes não retornou token")
|
||||
|
||||
# return dados["token"]
|
||||
|
||||
# def _build_payload_novos(self, proposta: Proposta) -> dict:
|
||||
# start_event = 'StartEvent_1'
|
||||
|
||||
# campos = [
|
||||
# ("e88ea290-8ce4-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
# ("ed2d30f0-8ce4-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
# ("f2fe24d0-8ce4-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
# ("2aafcff0-8cf4-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
# ("fad87d40-8ce4-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
# ("fdfd63f0-8ce4-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
# ("01109760-8ce5-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
# ("04ab7160-8ce5-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
# ("1b0974c0-8ce5-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
# ("23914b40-8ce5-11f1-9f28-e51e49945850", proposta.nome),
|
||||
# ("27b419f0-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
# ("398ac070-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
# ("3e7bb490-8ce5-11f1-9f28-e51e49945850", proposta.email),
|
||||
# ("6873d880-9ccc-11f1-b919-f777409ec14c", proposta.vendedor_holmes),
|
||||
# ]
|
||||
|
||||
# payload = {
|
||||
# "workflow": {
|
||||
# "start_event": start_event,
|
||||
# "property_values": [
|
||||
# {"id": prop_id, "value": valor}
|
||||
# for prop_id, valor in campos
|
||||
# if valor is not None and str(valor).strip() != ''
|
||||
# ],
|
||||
# "whats": "",
|
||||
# "documents": [],
|
||||
# "test": False
|
||||
# }
|
||||
# }
|
||||
# logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
# return payload
|
||||
|
||||
# def _build_payload_usados(self, proposta: Proposta) -> dict:
|
||||
# start_event = 'StartEvent_1'
|
||||
|
||||
# campos = [
|
||||
# ("e88ea290-8ce4-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
# ("ed2d30f0-8ce4-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
# ("2aafcff0-8cf4-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
# ("f2fe24d0-8ce4-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
# ("fad87d40-8ce4-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
# ("fdfd63f0-8ce4-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
# ("01109760-8ce5-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
# ("04ab7160-8ce5-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
# ("08b38c20-8ce5-11f1-9f28-e51e49945850", proposta.placa),
|
||||
# ("1b0974c0-8ce5-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
# ("23914b40-8ce5-11f1-9f28-e51e49945850", proposta.nome),
|
||||
# ("27b419f0-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
# ("398ac070-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
# ("3e7bb490-8ce5-11f1-9f28-e51e49945850", proposta.email),
|
||||
# ("19c78c10-9d92-11f1-ad38-41765eab56e3", proposta.vendedor_holmes),
|
||||
# ]
|
||||
|
||||
# payload = {
|
||||
# "workflow": {
|
||||
# "start_event": start_event,
|
||||
# "property_values": [
|
||||
# {"id": prop_id, "value": valor}
|
||||
# for prop_id, valor in campos
|
||||
# if valor is not None and str(valor).strip() != ''
|
||||
# ],
|
||||
# "whats": "",
|
||||
# "documents": [],
|
||||
# "test": False
|
||||
# }
|
||||
# }
|
||||
# logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
# return payload
|
||||
|
||||
# def _build_payload_imobilizado(self, proposta: Proposta) -> dict:
|
||||
# start_event = 'StartEvent_1'
|
||||
|
||||
# campos = [
|
||||
# ("e88ea290-8ce4-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
# ("ed2d30f0-8ce4-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
# ("f2fe24d0-8ce4-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
# ("2aafcff0-8cf4-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
# ("fad87d40-8ce4-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
# ("fdfd63f0-8ce4-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
# ("01109760-8ce5-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
# ("04ab7160-8ce5-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
# ("08b38c20-8ce5-11f1-9f28-e51e49945850", proposta.placa),
|
||||
# ("1b0974c0-8ce5-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
# ("23914b40-8ce5-11f1-9f28-e51e49945850", proposta.nome),
|
||||
# ("27b419f0-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
# ("398ac070-8ce5-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
# ("3e7bb490-8ce5-11f1-9f28-e51e49945850", proposta.email),
|
||||
# ("d1b18d20-9d98-11f1-8298-cb4f6a31d606", proposta.vendedor_holmes),
|
||||
# ]
|
||||
|
||||
# payload = {
|
||||
# "workflow": {
|
||||
# "start_event": start_event,
|
||||
# "property_values": [
|
||||
# {"id": prop_id, "value": valor}
|
||||
# for prop_id, valor in campos
|
||||
# if valor is not None and str(valor).strip() != ''
|
||||
# ],
|
||||
# "whats": "",
|
||||
# "documents": [],
|
||||
# "test": False
|
||||
# }
|
||||
# }
|
||||
# logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
# return payload
|
||||
|
||||
# def _build_payload_venda_direta(self, proposta: Proposta) -> dict:
|
||||
# # Esse formulario tem IDs proprios (nao reaproveita os dos outros tres),
|
||||
# # nao tem Placa e traz a Observacao da proposta.
|
||||
# start_event = 'StartEvent_1'
|
||||
|
||||
# campos = [
|
||||
# ("37897690-8d03-11f1-9f28-e51e49945850", proposta.empresa_holmes),
|
||||
# ("420c59c0-8d03-11f1-9f28-e51e49945850", proposta.tipo_pessoa),
|
||||
# ("46da1900-8d04-11f1-9f28-e51e49945850", proposta.forma_pagamento),
|
||||
# ("48ee6f80-8d03-11f1-9f28-e51e49945850", proposta.usado_na_troca),
|
||||
# ("53933290-8d03-11f1-9f28-e51e49945850", proposta.proposta_apollo),
|
||||
# ("58d81310-8d03-11f1-9f28-e51e49945850", proposta.veiculo),
|
||||
# ("5b19c5b0-8d03-11f1-9f28-e51e49945850", proposta.chassi),
|
||||
# ("5f92a3a0-8d03-11f1-9f28-e51e49945850", proposta.des_modelo),
|
||||
# ("6b95e540-8d03-11f1-9f28-e51e49945850", proposta.valor_proposta),
|
||||
# ("73c56290-8d03-11f1-9f28-e51e49945850", proposta.nome),
|
||||
# ("79635f90-8d03-11f1-9f28-e51e49945850", self._somente_digitos(proposta.cpfcnpj)),
|
||||
# ("85ea9e40-8d03-11f1-9f28-e51e49945850", self._somente_digitos(proposta.celular)),
|
||||
# ("8f16f220-8d03-11f1-9f28-e51e49945850", proposta.email),
|
||||
# ("cbe61910-a2de-11f1-aff4-4f1f04587741", proposta.vendedor_holmes),
|
||||
# ("e7610290-a2de-11f1-aff4-4f1f04587741", proposta.observacao),
|
||||
# ]
|
||||
|
||||
# payload = {
|
||||
# "workflow": {
|
||||
# "start_event": start_event,
|
||||
# "property_values": [
|
||||
# {"id": prop_id, "value": valor}
|
||||
# for prop_id, valor in campos
|
||||
# if valor is not None and str(valor).strip() != ''
|
||||
# ],
|
||||
# "whats": "",
|
||||
# "documents": [],
|
||||
# "test": False
|
||||
# }
|
||||
# }
|
||||
# logging.debug("Payload proposta %s: %s", proposta.proposta_apollo, payload)
|
||||
# return payload
|
||||
|
||||
# def existe_holmes(self, chassi: str, proposta: str) -> bool:
|
||||
# """Confere se o chassi já está lançado no holmes e caso tenha o mesmo chassi ele bate a proposta
|
||||
|
||||
# Args:
|
||||
# chassi (str): Chassi do veiculo vendido
|
||||
# proposta (str): Proposta do veiculo
|
||||
|
||||
# Returns:
|
||||
# bool: True caso existir e False caso não exista no holmes
|
||||
# """
|
||||
|
||||
# logging.info("Verificando se chassi %s (proposta %s) já existe no Holmes", chassi, proposta)
|
||||
# url = 'https://app-api.holmesdoc.io/v2/search'
|
||||
# body = {
|
||||
# "query": {
|
||||
# "from": 0,
|
||||
# "size": 50,
|
||||
# "context": "process",
|
||||
# "sort": "updated_at",
|
||||
# "order": "desc",
|
||||
# "groups": [
|
||||
# {
|
||||
# "match_all": True,
|
||||
# "terms": [
|
||||
# {
|
||||
# "value": f"{chassi}",
|
||||
# "type": "match_phrase",
|
||||
# "field": "_content"
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# },
|
||||
# "trash": False,
|
||||
# "deleted_by_me": False
|
||||
# }
|
||||
|
||||
# resposta = requests.post(url, json=body, headers=self.headers)
|
||||
# resposta.raise_for_status()
|
||||
# dados = resposta.json()
|
||||
|
||||
# if dados['total'] == 0:
|
||||
# logging.info("Chassi %s não encontrado no Holmes", chassi)
|
||||
# return False
|
||||
|
||||
# docs_validos = [
|
||||
# doc for doc in dados['docs']
|
||||
# if doc.get('name') == '[FAT] Faturamento de Estoque'
|
||||
# and doc.get('status') != 'canceled'
|
||||
# ]
|
||||
|
||||
# if not docs_validos:
|
||||
# logging.info("Chassi %s encontrado mas sem processos válidos (todos cancelados ou de outro template)", chassi)
|
||||
# return False
|
||||
|
||||
# proposta_holmes = extrair_proposta(docs_validos[0]['identifier'])
|
||||
# if str(proposta_holmes) != str(proposta):
|
||||
# logging.info("Chassi %s encontrado mas proposta diferente (Holmes: %s, Apollo: %s)", chassi, proposta_holmes, proposta)
|
||||
# return False
|
||||
|
||||
# logging.info("Chassi %s já existe no Holmes com mesma proposta %s", chassi, proposta)
|
||||
# return True
|
||||
|
||||
# def envia_fat_estoque_usado(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
# logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
# url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cc58744c4ba86a63aebc1/start'
|
||||
# payload = self._build_payload_usados(proposta)
|
||||
# logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
# response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
# logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
# try:
|
||||
# if response.status_code != 200:
|
||||
# err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
# err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
# logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
# estoque_repo.insere_erro(
|
||||
# ErroHolmes(
|
||||
# empresa = proposta.empresa,
|
||||
# revenda = proposta.revenda,
|
||||
# proposta_apollo = proposta.proposta_apollo,
|
||||
# motivo_erro= err_msg
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
# else:
|
||||
# resposta = response.json()
|
||||
# logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
# estoque_repo.insere_estoque(
|
||||
# EstoqueHolmes(
|
||||
# empresa= proposta.empresa,
|
||||
# revenda= proposta.revenda,
|
||||
# proposta_apollo= proposta.proposta_apollo,
|
||||
# proesso_id= resposta['id'],
|
||||
# usuario_criou= 'SUPORTE SISTEMAS',
|
||||
# nome_processo= '[FAT] Faturamento de Estoque'
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
# except Exception as e:
|
||||
# logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
# return Resultado(sucesso=False, mensagem=str(e))
|
||||
|
||||
# def envia_fat_estoque_novos(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
# logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
# url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cbe67aff519bb6aa4b2d8/start'
|
||||
# payload = self._build_payload_novos(proposta)
|
||||
# logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
# response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
# logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
# try:
|
||||
# if response.status_code != 200:
|
||||
# err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
# err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
# logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
# estoque_repo.insere_erro(
|
||||
# ErroHolmes(
|
||||
# empresa = proposta.empresa,
|
||||
# revenda = proposta.revenda,
|
||||
# proposta_apollo = proposta.proposta_apollo,
|
||||
# motivo_erro= err_msg
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
# else:
|
||||
# resposta = response.json()
|
||||
# logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
# estoque_repo.insere_estoque(
|
||||
# EstoqueHolmes(
|
||||
# empresa= proposta.empresa,
|
||||
# revenda= proposta.revenda,
|
||||
# proposta_apollo= proposta.proposta_apollo,
|
||||
# proesso_id= resposta['id'],
|
||||
# usuario_criou= 'SUPORTE SISTEMAS',
|
||||
# nome_processo= '[FAT] Faturamento de Estoque'
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
# except Exception as e:
|
||||
# logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
# return Resultado(sucesso=False, mensagem=str(e))
|
||||
|
||||
# def envia_fat_estoque_imobilizado(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
# logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
# url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cc2a3dbf5173588777520/start'
|
||||
# payload = self._build_payload_imobilizado(proposta)
|
||||
# logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
# response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
# logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
# try:
|
||||
# if response.status_code != 200:
|
||||
# err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
# err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
# logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
# estoque_repo.insere_erro(
|
||||
# ErroHolmes(
|
||||
# empresa = proposta.empresa,
|
||||
# revenda = proposta.revenda,
|
||||
# proposta_apollo = proposta.proposta_apollo,
|
||||
# motivo_erro= err_msg
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
# else:
|
||||
# resposta = response.json()
|
||||
# logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
# estoque_repo.insere_estoque(
|
||||
# EstoqueHolmes(
|
||||
# empresa= proposta.empresa,
|
||||
# revenda= proposta.revenda,
|
||||
# proposta_apollo= proposta.proposta_apollo,
|
||||
# proesso_id= resposta['id'],
|
||||
# usuario_criou= 'SUPORTE SISTEMAS',
|
||||
# nome_processo= '[FAT] Faturamento de Estoque'
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
# except Exception as e:
|
||||
# logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
# return Resultado(sucesso=False, mensagem=str(e))
|
||||
# def envia_fat_estoque_venda_direta(self, proposta: Proposta, estoque_repo: EstoqueRepository) -> Resultado:
|
||||
# logging.info("Enviando proposta %s para Holmes (empresa=%s, revenda=%s)", proposta.proposta_apollo, proposta.empresa, proposta.revenda)
|
||||
# url = 'https://app-api.holmesdoc.io/v1/workflows/6a6cd6449341bbc7e45f29cf/start'
|
||||
# payload = self._build_payload_venda_direta(proposta)
|
||||
# logging.debug("Payload montado para proposta %s", proposta.proposta_apollo)
|
||||
# response = requests.post(url, headers=self.headers, data=json.dumps(payload))
|
||||
# logging.debug("Holmes respondeu com status %s para proposta %s", response.status_code, proposta.proposta_apollo)
|
||||
|
||||
# try:
|
||||
# if response.status_code != 200:
|
||||
# err_msg = f"Erro ao enviar para Holmes: {response.status_code} - {response.text or ''}"
|
||||
# err_msg = (err_msg[:3900] + "...") if len(err_msg) > 3900 else err_msg
|
||||
# logging.error("Falha ao enviar proposta %s: %s", proposta.proposta_apollo, err_msg)
|
||||
# estoque_repo.insere_erro(
|
||||
# ErroHolmes(
|
||||
# empresa = proposta.empresa,
|
||||
# revenda = proposta.revenda,
|
||||
# proposta_apollo = proposta.proposta_apollo,
|
||||
# motivo_erro= err_msg
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=False, mensagem=err_msg)
|
||||
|
||||
# else:
|
||||
# resposta = response.json()
|
||||
# logging.info("Proposta %s enviada com sucesso - processo Holmes: %s", proposta.proposta_apollo, resposta['id'])
|
||||
# estoque_repo.insere_estoque(
|
||||
# EstoqueHolmes(
|
||||
# empresa= proposta.empresa,
|
||||
# revenda= proposta.revenda,
|
||||
# proposta_apollo= proposta.proposta_apollo,
|
||||
# proesso_id= resposta['id'],
|
||||
# usuario_criou= 'SUPORTE SISTEMAS',
|
||||
# nome_processo= '[FAT] Faturamento de Estoque'
|
||||
# )
|
||||
# )
|
||||
# return Resultado(sucesso=True, mensagem=resposta['id'])
|
||||
|
||||
# except Exception as e:
|
||||
# logging.error("Erro inesperado ao processar proposta %s: %s", proposta.proposta_apollo, e, exc_info=True)
|
||||
# return Resultado(sucesso=False, mensagem=str(e))
|
||||
Loading…
Add table
Add a link
Reference in a new issue