Versão 1.0

This commit is contained in:
Ricardo 2026-09-14 10:13:17 -03:00
commit 13bcea2077
26 changed files with 1546 additions and 0 deletions

842
src/holmes/client.py Normal file
View 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))